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

334 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);