feat(images): mutate tags
This commit is contained in:
parent
eae5345e62
commit
bf9a85e4fd
@ -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
|
||||
|
@ -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'
|
||||
};
|
||||
|
@ -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 {
|
||||
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(`/`);
|
||||
}
|
||||
}
|
||||
|
@ -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(`/`);
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
[]
|
||||
),
|
||||
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
|
||||
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);
|
||||
|
5
packages/images/src/graphql/update-image-tags.gql
Normal file
5
packages/images/src/graphql/update-image-tags.gql
Normal file
@ -0,0 +1,5 @@
|
||||
mutation updateImageTags($id: ID!, $tags: [KeyValueInput]!) {
|
||||
updateImage(id: $id, tags: $tags) {
|
||||
id
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user