joyent-portal/consoles/my-joy-service-groups/src/containers/steps/template.js

334 lines
9.7 KiB
JavaScript
Raw Normal View History

2018-05-23 19:29:04 +03:00
import React, { Fragment, Component } from 'react';
import { If, Then, Else } from 'react-if';
import ReduxForm from 'declarative-redux-form';
import { connect } from 'react-redux';
import { set } from 'react-redux-values';
import { Field } from 'redux-form';
import { compose, graphql } from 'react-apollo';
import { Link } from 'react-router-dom';
import { Margin, Padding } from 'styled-components-spacing';
import Flex, { FlexItem } from 'styled-flex-component';
import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
import get from 'lodash.get';
import sort from 'lodash.sortby';
import reverse from 'lodash.reverse';
import find from 'lodash.find';
import Fuse from 'fuse.js';
import Step, {
Header as StepHeader,
Description as StepDescription,
Preview as StepPreview,
Outlet as StepOutlet
} from 'joyent-ui-resource-step';
import {
H2,
Label,
Divider,
Button,
FormGroup,
FormLabel,
Input,
TemplateIcon,
StatusLoader,
Message,
MessageTitle,
MessageDescription
} from 'joyent-ui-toolkit';
import TemplatesList, {
Item as TemplatesItem,
EmptyCard as TemplatesEmptyCard,
EmptyRow as TemplatesEmptyRow,
LoadingRow
} from '@components/templates';
import { Global } from '@state/global.js';
import GetTemplate from '@graphql/get-template.gql';
import ListTemplates from '@graphql/list-templates.gql';
import { Forms, Values } from '@root/constants';
const { SGC_T_F, SGC_F_F } = Forms;
const { SGC_T_SB_V, SGC_T_SO_V } = Values;
class Template extends Component {
getSnapshotBeforeUpdate(prevProps, prevState) {
const { preview: prev } = prevProps;
const { preview: next, onDefocus, readOnly } = this.props;
if (!(readOnly && prev !== next && onDefocus)) {
return;
}
onDefocus(next);
}
render() {
const {
loading = false,
empty = false,
handleGetValue,
preview = {},
initialValues,
templates = [],
filter = '',
sortBy = 'name',
sortOrder = 'asc',
expanded = false,
readOnly = false,
error = null,
handleSortBy,
...props
} = this.props;
return (
<Step
name="template"
getValue={handleGetValue}
readOnly={readOnly}
expanded={readOnly ? false : expanded}
{...props}
>
<StepHeader icon={<TemplateIcon />}>Select template</StepHeader>
<StepDescription>
Select the template youd like to deloy your instances from. Once a
Service Group is deployed with a templates, any changes to that
template will not effect the acting service group.
</StepDescription>
<StepPreview>
<Margin top="5">
<If condition={loading && !preview.name}>
<Then>
<StatusLoader />
</Then>
<Else>
<Fragment>
<Margin bottom="2">
<H2>{preview.name}</H2>
</Margin>
<Flex alignCenter>
<FlexItem>
<Padding right="3">
<Label inline>{preview.image}</Label>
</Padding>
</FlexItem>
<Divider vertical />
<FlexItem>
<Padding right="3" left="3">
<Label inline>{preview.package}</Label>
</Padding>
</FlexItem>
<Divider vertical />
<FlexItem>
<Padding right="3" left="3">
<Label inline>
{distanceInWordsToNow(preview.created)}
</Label>
</Padding>
</FlexItem>
</Flex>
</Fragment>
</Else>
</If>
</Margin>
</StepPreview>
<StepOutlet>
{({ next }) => (
<Margin top="5">
<If condition={error}>
<Then>
<Margin bottom="3">
<Message error>
<MessageTitle>Ooops!</MessageTitle>
<MessageDescription>
An error occurred while loading your templates
</MessageDescription>
</Message>
</Margin>
</Then>
</If>
<ReduxForm form={SGC_F_F}>
{props => (
<If condition={empty}>
<Else>
<Margin bottom="3">
<FormGroup name="filter" field={Field}>
<FormLabel>Filter</FormLabel>
<Margin top="0.5">
<Input disabled={!(filter || templates.length)} />
</Margin>
</FormGroup>
</Margin>
</Else>
</If>
)}
</ReduxForm>
<ReduxForm form={SGC_T_F} initialValues={initialValues}>
{({ pristine }) => (
<Fragment>
<If condition={empty}>
<Then>
<TemplatesEmptyCard />
</Then>
<Else>
<TemplatesList
{...props}
sortBy={sortBy}
sortOrder={sortOrder}
onSortBy={newSortBy =>
handleSortBy(newSortBy, { sortOrder, sortBy })
}
>
<If condition={templates.length}>
<Then>
<Fragment>
{templates.map(({ id, ...template }) => (
<TemplatesItem
key={id}
id={id}
{...template}
/>
))}
</Fragment>
</Then>
<Else>
<If condition={loading}>
<Then>
<LoadingRow />
</Then>
<Else>
<TemplatesEmptyRow />
</Else>
</If>
</Else>
</If>
</TemplatesList>
</Else>
</If>
<Margin top="5">
<Button
type="button"
disabled={pristine}
component={Link}
to={next}
>
Save
</Button>
</Margin>
</Fragment>
)}
</ReduxForm>
</Margin>
)}
</StepOutlet>
</Step>
);
}
}
export default compose(
graphql(ListTemplates, {
options: ({ location }) => {
const tmpl = Global().query.template;
return {
ssr: true,
fetchPolicy: tmpl ? 'cache-only' : 'cache-and-network'
};
},
props: ({ data: { error, templates = [], networkStatus } }) => ({
error,
loading: networkStatus === 1,
templates,
index: new Fuse(templates, {
keys: ['id', 'name', 'created']
})
})
}),
graphql(GetTemplate, {
options: ({ match }) => {
const tmpl = Global().query.template;
return {
ssr: true,
fetchPolicy: tmpl ? 'cache-and-network' : 'cache-only',
variables: {
id: tmpl
}
};
},
props: ({ data }) => {
const { variables, networkStatus, error, template } = data;
if (!variables.id) {
return {};
}
return {
readOnly: Boolean(variables.id),
loading: networkStatus === 1,
error,
preview: template
};
}
}),
connect(
(state, ownProps) => {
const { form, values: flags } = state;
const { templates: items, preview = {}, loading, index } = ownProps;
const filter = get(form, `${SGC_F_F}.values.filter`, '');
const sortBy = get(flags, SGC_T_SB_V, 'name');
const sortOrder = get(flags, SGC_T_SO_V, 'asc');
const templates = sort(filter.length ? index.search(filter) : items, [
sortBy
]);
return {
filter,
empty: !filter && !loading && !templates.length,
handleGetValue: () => {
return find(templates, [
'id',
get(form, `${SGC_T_F}.values.template`)
]);
},
initialValues: {
template: preview.id
},
templates: sortOrder === 'asc' ? templates : reverse(templates),
sortBy,
sortOrder
};
},
(dispatch, { templates = [], refetch, removeGroup }) => {
return {
handleSortBy: (newSortBy, { sortBy: currentSortBy, sortOrder }) => {
// sort prop is the same, toggle
if (currentSortBy === newSortBy) {
return dispatch(
set({
name: SGC_T_SO_V,
value: sortOrder === 'desc' ? 'asc' : 'desc'
})
);
}
dispatch([
set({
name: SGC_T_SO_V,
value: 'desc'
}),
set({
name: SGC_T_SB_V,
value: newSortBy
})
]);
}
};
}
)
)(Template);