feat(images): mutate tags

This commit is contained in:
Sérgio Ramos 2018-02-14 20:30:25 +00:00 committed by Sérgio Ramos
parent eae5345e62
commit bf9a85e4fd
13 changed files with 173 additions and 39 deletions

View File

@ -32,7 +32,7 @@ export const Toolbar = ({
<FormGroup right>
<Divider height={remcalc(21)} transparent />
<Button
type={onActionClick ? 'button' : 'submit'}
type="button"
disabled={!actionable}
onClick={onActionClick}
icon

View File

@ -29,5 +29,9 @@ export const Forms = {
FORM_TAGS_EDIT: i => `CREATE-IMAGE-TAGS-EDIT-${i}`,
FORM_DETAILS: 'CREATE-IMAGE-DETAILS',
CREATE_FORM: 'CREATE-IMAGE',
CREATE_TAGS: 'CREATE-IMAGE-TAGS'
CREATE_TAGS: 'CREATE-IMAGE-TAGS',
LIST_TOGGLE_TYPE_FORM: 'LIST-TOGGLE-TYPE-FORM',
LIST_TOOLBAR_FORM: 'LIST-TOOLBAR-FORM',
TAGS_TOOLBAR_FORM: 'TAGS-TOOLBAR-FORM',
TAGS_ADD_FORM: 'TAGS-ADD-FORM'
};

View File

@ -22,14 +22,13 @@ import {
import ToolbarForm from '@components/toolbar';
import Empty from '@components/empty';
import { ImageType } from '@root/constants';
import { ImageType, Forms } from '@root/constants';
import ListImages from '@graphql/list-images.gql';
import { Image, Filters } from '@components/image';
import RemoveImage from '@graphql/remove-image.gql';
import parseError from '@state/parse-error';
const TOGGLE_FORM_DETAILS = 'images-list-toggle';
const MENU_FORM_DETAILS = 'images-list-menu';
const { LIST_TOOLBAR_FORM, LIST_TOGGLE_TYPE_FORM } = Forms;
export const List = ({
images = [],
@ -42,7 +41,7 @@ export const List = ({
}) => (
<ViewContainer main>
<Divider height={remcalc(30)} transparent />
<ReduxForm form={MENU_FORM_DETAILS}>
<ReduxForm form={LIST_TOOLBAR_FORM}>
{props => <ToolbarForm {...props} actionable={!loading} />}
</ReduxForm>
<Divider height={remcalc(1)} />
@ -66,7 +65,7 @@ export const List = ({
<Fragment>
<Margin bottom={4}>
<ReduxForm
form={TOGGLE_FORM_DETAILS}
form={LIST_TOGGLE_TYPE_FORM}
initialValues={{ 'image-type': 'all' }}
>
{props =>
@ -91,25 +90,26 @@ export const List = ({
);
export default compose(
graphql(RemoveImage, { name: 'removeImage' }),
graphql(RemoveImage, {
name: 'removeImage'
}),
graphql(ListImages, {
options: { pollInterval: 5000 },
props: ({ data: { images, loading, error, refetch } }) => {
return {
images,
loading,
error
};
}
fetchPolicy: 'network-only',
pollInterval: 1000,
props: ({ data: { images, loading, error, refetch } }) => ({
images,
loading,
error
})
}),
connect(
({ form, values }, { index, error, images = [] }) => {
const filter = get(form, `${MENU_FORM_DETAILS}.values.filter`, false);
const filter = get(form, `${LIST_TOOLBAR_FORM}.values.filter`, false);
const mutationError = get(values, 'remove-mutation-error', null);
const typeValue = get(
form,
`${TOGGLE_FORM_DETAILS}.values.image-type`,
`${LIST_TOGGLE_TYPE_FORM}.values.image-type`,
'all'
);
@ -171,9 +171,10 @@ export default compose(
}
if (res) {
dispatch([
dispatch(
set({ name: `remove-mutation-${id}-loading`, value: false })
]);
);
history.push(`/`);
}
}

View File

@ -92,7 +92,7 @@ export default compose(
},
(dispatch, { removeImage, image, history }) => ({
handleRemove: async () => {
dispatch([set({ name: 'remove-mutation-loading', value: true })]);
dispatch(set({ name: 'remove-mutation-loading', value: true }));
const [err, res] = await intercept(
removeImage({
@ -110,7 +110,7 @@ export default compose(
}
if (res) {
dispatch([set({ name: 'remove-mutation-loading', value: false })]);
dispatch(set({ name: 'remove-mutation-loading', value: false }));
history.push(`/`);
}
}

View File

@ -1,7 +1,11 @@
import React from 'react';
import { compose, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { Margin } from 'styled-components-spacing';
import ReduxForm from 'declarative-redux-form';
import { destroy } from 'redux-form';
import { set } from 'react-redux-values';
import intercept from 'apr-intercept';
import find from 'lodash.find';
import get from 'lodash.get';
import remcalc from 'remcalc';
@ -17,22 +21,36 @@ import {
TagList
} from 'joyent-ui-toolkit';
import Tag from '@components/tags';
import { Forms } from '@root/constants';
import Tag, { AddForm } from '@components/tags';
import ToolbarForm from '@components/toolbar';
import UpdateImageTags from '@graphql/update-image-tags.gql';
import GetTags from '@graphql/get-tags.gql';
import parseError from '@state/parse-error';
const MENU_FORM_DETAILS = 'image-tags-list-menu';
const { TAGS_TOOLBAR_FORM, TAGS_ADD_FORM } = Forms;
export const Tags = ({ tags = [], loading = false, error = null }) => (
export const Tags = ({
tags = [],
addOpen = false,
loading = false,
error = null,
mutationError = null,
mutating = false,
handleToggleAddOpen,
handleRemoveTag,
handleAddTag
}) => (
<ViewContainer main>
<ReduxForm form={MENU_FORM_DETAILS}>
<ReduxForm form={TAGS_TOOLBAR_FORM}>
{props => (
<Margin bottom="4">
<ToolbarForm
{...props}
searchable={!loading}
actionLabel="Add Tag"
actionable={!loading}
actionable={!loading && !mutating && !addOpen}
onActionClick={handleToggleAddOpen}
action
/>
<Divider height={remcalc(1)} />
@ -49,6 +67,27 @@ export const Tags = ({ tags = [], loading = false, error = null }) => (
</Message>
</Margin>
) : null}
{mutationError ? (
<Margin bottom={4}>
<Message error>
<MessageTitle>Ooops!</MessageTitle>
<MessageDescription>{mutationError}</MessageDescription>
</Message>
</Margin>
) : null}
<ReduxForm form={TAGS_ADD_FORM} onSubmit={handleAddTag}>
{props =>
addOpen ? (
<Margin bottom={4}>
<AddForm
{...props}
onToggleExpanded={() => handleToggleAddOpen(!addOpen)}
onCancel={() => handleToggleAddOpen(!addOpen)}
/>
</Margin>
) : null
}
</ReduxForm>
{!loading ? (
<Margin bottom={4}>
<H3>
@ -59,29 +98,114 @@ export const Tags = ({ tags = [], loading = false, error = null }) => (
{loading && !tags.length ? <StatusLoader /> : null}
<TagList>
{tags.map(({ name, value }) => (
<Tag key={value} name={name} value={value} active />
<Tag
key={value}
name={name}
value={value}
onRemoveClick={!mutating && (() => handleRemoveTag(name))}
active
/>
))}
</TagList>
</ViewContainer>
);
export default compose(
graphql(UpdateImageTags, {
name: 'updateTags'
}),
graphql(GetTags, {
options: ({ match }) => ({
fetchPolicy: 'network-only',
pollInterval: 1000,
variables: {
name: get(match, 'params.image')
}
}),
props: ({
data: { loading = false, error = null, variables, ...rest }
}) => ({
tags: get(
find(get(rest, 'images', []), ['name', variables.name]),
'tags',
[]
),
loading,
error
props: ({ data }) => {
const {
loading = false,
error = null,
variables,
refetch,
...rest
} = data;
const image = find(get(rest, 'images', []), ['name', variables.name]);
const tags = get(image || {}, 'tags', []);
return {
image: image || {},
tags,
loading,
error,
refetch
};
}
}),
connect(
({ values }, { image }) => ({
addOpen: get(values, `${image.id}-add-open`, false),
mutationError: get(values, `${image.id}-mutation-error`, false),
mutating: get(values, `${image.id}-mutating`, false)
}),
(dispatch, { image, tags = [], updateTags, refetch }) => ({
handleToggleAddOpen: addOpen => {
dispatch(set({ name: `${image.id}-add-open`, value: addOpen }));
},
handleRemoveTag: async name => {
dispatch(set({ name: `${image.id}-mutating`, value: true }));
const [err, res] = await intercept(
updateTags({
variables: {
id: image.id,
tags: tags
.map(({ name, value }) => ({ name, value }))
.filter(tag => tag.name !== name)
}
})
);
if (err) {
dispatch([
set({ name: `${image.id}-mutation-error`, value: parseError(err) }),
set({ name: `${image.id}-mutating`, value: false })
]);
}
await refetch();
dispatch(set({ name: `${image.id}-mutating`, value: false }));
},
handleAddTag: async ({ name, value }) => {
dispatch(set({ name: `${image.id}-mutating`, value: true }));
const [err, res] = await intercept(
updateTags({
variables: {
id: image.id,
tags: tags
.map(({ name, value }) => ({ name, value }))
.concat([{ name, value }])
}
})
);
if (err) {
dispatch([
set({ name: `${image.id}-mutation-error`, value: parseError(err) }),
set({ name: `${image.id}-mutating`, value: false })
]);
}
await refetch();
dispatch([
set({ name: `${image.id}-mutating`, value: false }),
dispatch(set({ name: `${image.id}-add-open`, value: false })),
destroy(TAGS_ADD_FORM)
]);
}
})
})
)
)(Tags);

View File

@ -0,0 +1,5 @@
mutation updateImageTags($id: ID!, $tags: [KeyValueInput]!) {
updateImage(id: $id, tags: $tags) {
id
}
}