28 | return (
29 |
30 |
31 | {utils.simplifyName(baseModel)}
32 |
33 | {model && model.description
34 | ?
38 | : null}
39 |
40 | );
41 | };
42 |
43 | export default ModelDescription;
44 |
--------------------------------------------------------------------------------
/src/application/components/JsonDoc/ModelDescription.test.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import renderer from 'react-test-renderer';
4 |
5 | import ModelDescription from 'application/components/JsonDoc/ModelDescription';
6 | import Example from 'exampleService.json';
7 |
8 | test('simple html', () => {
9 | const params = {
10 | baseModel: 'base',
11 | service: Example,
12 | importedServices: [],
13 | modelNameClick: () => {},
14 | };
15 |
16 | const component = renderer.create();
17 |
18 | const tree = component.toJSON();
19 | expect(tree).toMatchSnapshot();
20 | });
21 |
--------------------------------------------------------------------------------
/src/application/components/JsonDoc/__snapshots__/ModelDescription.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`simple html 1`] = `
4 |
7 |
11 | base
12 |
13 |
14 | `;
15 |
--------------------------------------------------------------------------------
/src/application/components/JsonDoc/defaults.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import * as utils from 'utils';
3 | import type { Field } from 'generated/version/ServiceType';
4 |
5 | const getFieldValue = (field: Field) => {
6 | const type = utils.getType(field.type);
7 | const wrap = value => {
8 | switch (type) {
9 | case 'string':
10 | case 'date-time-iso8601':
11 | case 'date-iso8601':
12 | case 'uuid':
13 | return `"${value}"`;
14 | default:
15 | return value;
16 | }
17 | };
18 |
19 | if (field.example) {
20 | return wrap(field.example);
21 | }
22 | if (field.default) {
23 | return wrap(field.default);
24 | }
25 | switch (type) {
26 | case 'boolean':
27 | return 'true';
28 | case 'string':
29 | return `"${field.name}"`;
30 | case 'integer':
31 | case 'long':
32 | return '12';
33 | case 'decimal':
34 | case 'double':
35 | return '10.12';
36 | case 'date-time-iso8601':
37 | return `"${new Date('2016-03-24T13:56:45.242Z').toISOString()}"`;
38 | case 'date-iso8601':
39 | return '"2016-03-24"';
40 | case 'uuid':
41 | return '"5ecf6502-e532-4738-aad5-7ac9701251dd"';
42 | default:
43 | return '';
44 | }
45 | };
46 |
47 | export { getFieldValue };
48 |
--------------------------------------------------------------------------------
/src/application/components/JsonDoc/json-doc.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .json-doc {
4 | font-style: normal;
5 | font-variant: normal;
6 | font-weight: 500;
7 | display: flex;
8 | align-items: flex-start;
9 | flex-direction: column;
10 | }
11 |
12 | .container {
13 | display: flex;
14 | width: 100%;
15 | flex-direction: row;
16 | align-items: flex-start;
17 | }
18 |
19 | .code {
20 | flex: 0 0 38%;
21 | width: 38%;
22 | padding: 1rem;
23 | background: var(--color-tuatara);
24 | color: white;
25 | margin: 0 2% 0 0;
26 | border-radius: var(--border-radius);
27 | overflow-x: scroll;
28 | }
29 |
30 | .field {
31 | width: 100%;
32 | text-decoration: none;
33 | color: var(--color-aluminium);
34 | font-family: var(--font-mono);
35 | cursor: pointer;
36 |
37 | @nest &:hover {
38 | background-color: color(var(--color-cool-blue) b(+35%));
39 | border-radius: var(--border-radius);
40 | }
41 | }
42 |
43 | .element {
44 | width: 100%;
45 | text-decoration: none;
46 | color: var(--color-aluminium);
47 | font-family: var(--font-mono);
48 | cursor: pointer;
49 |
50 | @nest &:hover {
51 | background-color: color(var(--color-cool-blue) b(+65%));
52 | border-radius: var(--border-radius);
53 | }
54 | }
55 |
56 | .name {
57 | color: var(--color-maya-blue);
58 | font-family: var(--font-mono);
59 | }
60 |
61 | .value {
62 | color: var(--color-secondary-light);
63 | font-family: var(--font-mono);
64 | }
65 |
66 | .default {
67 | color: black;
68 | }
69 |
70 | .documentation {
71 | flex: 0 0 60%;
72 | width: 60%;
73 | font-family: var(--font-primary);
74 | }
75 |
76 | .field-container {
77 | display: flex;
78 | }
79 |
80 | .field-left {
81 | flex: 0 1 30%;
82 | }
83 |
84 | .field-right {
85 | flex: 0 1 65%;
86 | margin-left: 5%;
87 | }
88 |
89 | .model {
90 | @nest &:hover {
91 | background-color: color(var(--color-cool-blue) b(+55%));
92 | border-radius: var(--border-radius);
93 | }
94 | }
95 |
96 | .model-name {
97 | font-weight: 400;
98 | margin: 0 0 0.5rem 0;
99 | font-size: 1.5rem;
100 | line-height: 1;
101 | }
102 |
103 | .model-description {
104 | margin: 2rem 0 1.5rem 0;
105 | }
106 |
107 | .model-description + .field-container {
108 | border-top: 1px solid var(--color-very-light-gray);
109 | }
110 |
111 | .default-view {
112 | color: var(--color-light-gray);
113 | }
114 |
--------------------------------------------------------------------------------
/src/application/components/JsonDoc/test-jsondoc-spec-expected.js:
--------------------------------------------------------------------------------
1 | // This is what the test-jsondoc-spec should look like in the ui
2 |
3 | /* eslint-disable comma-dangle */
4 |
5 | export const getGender200 = 'female';
6 |
7 | export const getGender201 = 'string';
8 |
9 | export const postPerson = {
10 | id: 12,
11 | default: 'default value',
12 | example: 'example value',
13 | boolean: true,
14 | dob: '2001-10-10',
15 | time: '2016-03-24T13:56:45.242Z',
16 | tags: ['tag'],
17 | details: {
18 | some_thing: 10,
19 | tags: ['string'],
20 | },
21 | addresses: [
22 | {
23 | street: 10,
24 | tags: ['string'],
25 | },
26 | ],
27 | gender: 'gender',
28 | };
29 |
30 | export const postPeople = [
31 | {
32 | id: 'xyz',
33 | name: 'name',
34 | dob: '2001-10-10',
35 | tags: ['tag'],
36 | details: {
37 | some_thing: 10,
38 | tags: ['string'],
39 | },
40 | addresses: [
41 | {
42 | street: 10,
43 | tags: ['string'],
44 | },
45 | ],
46 | gender: 'gender',
47 | },
48 | ];
49 |
50 | /* eslint-enable comma-dangle */
51 |
--------------------------------------------------------------------------------
/src/application/components/Model.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import H1 from 'components/H1';
5 | import Markdown from 'components/Markdown';
6 | import JsonDoc from 'application/components/JsonDoc/JsonDoc';
7 | import ParameterListGroup from 'application/components/ParameterListGroup';
8 |
9 | import { simplifyName } from 'utils';
10 |
11 | import type {
12 | Service,
13 | Model as ModelType,
14 | } from 'generated/version/ServiceType';
15 |
16 | import styles from 'application/components/model.css';
17 |
18 | const Model = ({
19 | model,
20 | service,
21 | importedServices,
22 | showJsonDoc,
23 | }: {
24 | model: ModelType,
25 | service: Service,
26 | importedServices: Service[],
27 | showJsonDoc: boolean,
28 | }) => (
29 |
30 |
31 |
{simplifyName(model.name)}
32 |
36 |
37 |
38 |
45 |
46 | {showJsonDoc
47 | ? {}}
53 | />
54 | : null}
55 |
56 |
57 |
58 | );
59 |
60 | export default Model;
61 |
--------------------------------------------------------------------------------
/src/application/components/Operation.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { Link } from 'react-router';
4 | import Markdown from 'components/Markdown';
5 | import Header from 'application/components/Header';
6 | import Request from 'application/components/Request';
7 | import Response from 'application/components/Response';
8 | import ResourceCard from 'application/components/ResourceCard';
9 | import H1 from 'components/H1';
10 |
11 | import type {
12 | Operation as OperationServiceType,
13 | Service,
14 | Resource as ResourceServiceType,
15 | } from 'generated/version/ServiceType';
16 |
17 | import styles from 'application/components/operation.css';
18 |
19 | const Operation = ({
20 | service,
21 | operation,
22 | applicationKey,
23 | organizationKey,
24 | resource,
25 | method,
26 | path,
27 | importedServices,
28 | }: {
29 | service: Service,
30 | operation: OperationServiceType,
31 | applicationKey: string,
32 | organizationKey: string,
33 | resource: ResourceServiceType,
34 | method: string,
35 | path: string,
36 | importedServices: Service[],
37 | }) => (
38 |
39 |
40 |
41 |
45 | {resource.type}
46 |
47 |
48 | {resource.description &&
49 | }
53 |
54 |
55 |
56 |
57 | {operation.description &&
58 |
}
62 |
63 |
71 |
72 |
73 |
79 |
80 |
88 |
89 | );
90 |
91 | export default Operation;
92 |
--------------------------------------------------------------------------------
/src/application/components/ParameterList.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import classnames from 'classnames';
4 |
5 | import Markdown from 'components/Markdown';
6 | import {
7 | buildNavHref,
8 | getType,
9 | isImport,
10 | isImportOrInService,
11 | onClickHref,
12 | simplifyName,
13 | } from 'utils';
14 |
15 | import type { Service } from 'generated/version/ServiceType';
16 |
17 | import styles from 'application/components/parameter-list.css';
18 |
19 | const ParameterList = (
20 | {
21 | name,
22 | type,
23 | required,
24 | description,
25 | minimum,
26 | maximum,
27 | example,
28 | defaultValue,
29 | service,
30 | importedServices,
31 | parentModel,
32 | }: {
33 | name: string,
34 | type: string,
35 | required: boolean,
36 | minimum?: number,
37 | maximum?: number,
38 | description?: string,
39 | example?: string,
40 | defaultValue?: string,
41 | service: Service,
42 | importedServices: Service[],
43 | parentModel: string,
44 | } = {}
45 | ) => {
46 | const possibleImportType = `${parentModel.substring(0, parentModel.lastIndexOf('.'))}.${type}`;
47 | const modelType = isImport(possibleImportType, importedServices)
48 | ? possibleImportType
49 | : type;
50 | const typeClickFn = isImportOrInService(
51 | getType(modelType),
52 | service,
53 | importedServices
54 | )
55 | ? onClickHref(
56 | buildNavHref({
57 | organization: service.organization.key,
58 | application: service.application.key,
59 | model: getType(modelType),
60 | })
61 | )
62 | : null;
63 |
64 | return (
65 |
66 |
85 |
86 | {description
87 | ?
88 | :
No description
}
89 | {minimum
90 | ?
91 | Minimum{minimum}
92 |
93 | : null
94 | }
95 | {maximum
96 | ?
97 | Maximum{maximum}
98 |
99 | : null
100 | }
101 | {example
102 | ?
103 | Example{example}
104 |
105 | : null}
106 | {defaultValue
107 | ?
108 | Default{defaultValue}
109 |
110 | : null}
111 |
112 |
113 | );
114 | };
115 |
116 | export default ParameterList;
117 |
--------------------------------------------------------------------------------
/src/application/components/ParameterListGroup.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import H2 from 'components/H2';
5 | import ParameterList from 'application/components/ParameterList';
6 |
7 | import type { Service } from 'generated/version/ServiceType';
8 |
9 | import styles from 'application/components/parameter-list-group.css';
10 |
11 | const ParameterListGroup = ({
12 | title,
13 | parameters,
14 | service,
15 | importedServices,
16 | parentModel,
17 | }: {
18 | title: string,
19 | parameters: any[], // FIXME PropTypes.array.isRequired,
20 | service: Service,
21 | importedServices: Service[],
22 | parentModel: string,
23 | }) => (
24 |
25 |
{title}
26 |
27 | {parameters.length > 0
28 | ? parameters.map((parameter, id) => (
29 |
36 | ))
37 | :
No parameters
}
38 |
39 |
40 | );
41 |
42 | export default ParameterListGroup;
43 |
--------------------------------------------------------------------------------
/src/application/components/Request.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import { cleanPath } from 'utils';
5 | import JsonDoc from 'application/components/JsonDoc/JsonDoc';
6 | import ParameterListGroup from 'application/components/ParameterListGroup';
7 |
8 | import H2 from 'components/H2';
9 | import type { Operation, Service } from 'generated/version/ServiceType';
10 |
11 | import styles from 'application/components/request.css';
12 |
13 | const Request = ({
14 | operation,
15 | service,
16 | importedServices,
17 | }: {
18 | operation: Operation,
19 | service: Service,
20 | importedServices: Service[],
21 | }) => {
22 | const responseParameters = () => {
23 | if (operation.parameters && !!operation.parameters.length) {
24 | return (
25 |
34 | );
35 | } else return null;
36 | };
37 | const body = () => {
38 | if (operation.body) {
39 | const baseModel = operation.body.type;
40 | return (
41 |
42 |
Request Body
43 |
44 | {}}
51 | />
52 |
53 |
54 | );
55 | } else return null;
56 | };
57 |
58 | return (
59 |
60 | {responseParameters()}
61 | {body()}
62 |
63 | );
64 | };
65 |
66 | export default Request;
67 |
68 | export { styles };
69 |
--------------------------------------------------------------------------------
/src/application/components/ResourceCard.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import classnames from 'classnames';
4 |
5 | import Markdown from 'components/Markdown';
6 |
7 | import styles from 'application/components/resource-card.css';
8 |
9 | const ResourceCard = (
10 | {
11 | method,
12 | path,
13 | click,
14 | description,
15 | }: {
16 | method: string,
17 | path: string,
18 | click?: Function,
19 | description?: string,
20 | } = {}
21 | ) => {
22 | const methodClasses = classnames(
23 | styles.method,
24 | styles[method.toLowerCase()],
25 | description ? styles.isExpandedMethod : null
26 | );
27 | const containerClasses = classnames(
28 | styles.container,
29 | click ? styles.isClick : null
30 | );
31 | const pathClasses = classnames(
32 | styles.path,
33 | description ? styles.isExpandedPath : null
34 | );
35 |
36 | return (
37 |
54 | );
55 | };
56 |
57 | export default ResourceCard;
58 |
59 | export { styles };
60 |
--------------------------------------------------------------------------------
/src/application/components/Response.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import { onClickHref, buildNavHref, getType } from 'utils';
5 |
6 | import H2 from 'components/H2';
7 | import Markdown from 'components/Markdown';
8 | import JsonDoc from 'application/components/JsonDoc/JsonDoc';
9 |
10 | import type { Operation, Service } from 'generated/version/ServiceType';
11 |
12 | import styles from 'application/components/response.css';
13 |
14 | const Response = ({
15 | operation,
16 | service,
17 | importedServices,
18 | orgKey,
19 | appKey,
20 | }: {
21 | operation: Operation,
22 | service: Service,
23 | importedServices: Service[],
24 | orgKey: string,
25 | appKey: string,
26 | }) => {
27 | const body = response => {
28 | if (response.type) {
29 | const baseModel = response.type;
30 | // TODO make this better, perhaps use isInImportOrService?
31 | const rawValue = response.type === 'string' ||
32 | response.type === 'integer' ||
33 | response.type === 'number'
34 | ? `${response.code.integer.value}`
35 | : '';
36 | const formattedRawValue = response.type === 'string'
37 | ? `"${rawValue}"`
38 | : rawValue;
39 | return (
40 |
41 |
55 |
56 | );
57 | } else return null;
58 | };
59 |
60 | return (
61 |
62 | {operation.responses.map(response => (
63 |
64 |
{`${response.code.integer.value} Response`}
67 |
71 | {body(response)}
72 |
73 | ))}
74 |
75 | );
76 | };
77 |
78 | export default Response;
79 |
80 | export { styles };
81 |
--------------------------------------------------------------------------------
/src/application/components/application-home.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .header {
4 | padding: 2rem 0 1rem 0;
5 | background: white;
6 | }
7 |
8 | .content {
9 | padding: 0 3rem;
10 | }
11 |
12 | .description {
13 | line-height: 2;
14 | margin: 0;
15 | }
16 |
--------------------------------------------------------------------------------
/src/application/components/application.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .method {
4 | padding: 0 5rem;
5 | }
6 |
7 | .request {
8 | background: #FAFAFA;
9 | }
10 |
11 | .section-header {
12 | margin: 0;
13 | font-weight: 600;
14 | }
15 |
--------------------------------------------------------------------------------
/src/application/components/enum.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .header {
4 | margin: 2rem 0 1rem 0;
5 | }
6 |
7 | .title {
8 | font-weight: 700;
9 | margin: 0 0 1rem 0;
10 | }
11 |
12 | .container {
13 | padding: 0 3rem;
14 | }
15 |
16 | .fields-container {
17 | padding: 0 1rem 1rem 1rem;
18 | border: 2px solid var(--color-concrete);
19 | border-bottom-right-radius: var(--border-radius);
20 | border-bottom-left-radius: var(--border-radius);
21 | }
22 |
23 | .description {
24 | margin: 0;
25 | }
26 |
27 | .json {
28 | padding: 1rem 0 1rem 0;
29 | }
30 |
--------------------------------------------------------------------------------
/src/application/components/header.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | padding: 0 1rem 1rem 1rem;
5 | margin: 0 0 1rem 0;
6 | border: 2px solid var(--color-concrete);
7 | border-bottom-right-radius: var(--border-radius);
8 | border-bottom-left-radius: var(--border-radius);
9 | }
10 |
11 | .json {
12 | padding: 1rem 0 1rem 0;
13 | }
14 |
--------------------------------------------------------------------------------
/src/application/components/model.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .header {
4 | margin: 2rem 0 1rem 0;
5 | }
6 |
7 | .title {
8 | font-weight: 700;
9 | margin: 0 0 1rem 0;
10 | }
11 |
12 | .container {
13 | padding: 0 3rem;
14 | }
15 |
16 | .fields-container {
17 | padding: 0 1rem 1rem 1rem;
18 | border: 2px solid var(--color-concrete);
19 | border-bottom-right-radius: var(--border-radius);
20 | border-bottom-left-radius: var(--border-radius);
21 | }
22 |
23 | .description {
24 | margin: 0;
25 | }
26 |
27 | .json {
28 | padding: 1rem 0 1rem 0;
29 | }
30 |
--------------------------------------------------------------------------------
/src/application/components/operation.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .header {
4 | padding: 2rem 0 1rem 0;
5 | }
6 |
7 | .resource {
8 | padding: 0 0 1rem 0;
9 | }
10 |
11 | .content {
12 | padding: 0 3rem;
13 | }
14 |
15 | .description {
16 | padding: 1rem 0;
17 | }
18 |
19 | .link {
20 | color: inherit;
21 | text-decoration: none;
22 |
23 | @nest &:hover {
24 | opacity: 0.7;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/application/components/parameter-list-group.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | background: var(--color-concrete);
5 | padding: 1rem 0 1rem 0;
6 | border-radius: var(--border-radius);
7 | overflow: hidden;
8 | }
9 |
10 | .title {
11 | font-weight: 400;
12 | }
13 |
14 | .no-content {
15 | color: var(--color-very-light-gray);
16 | margin: 0;
17 | padding: 0.67rem 2rem;
18 | }
19 |
--------------------------------------------------------------------------------
/src/application/components/parameter-list.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | font-family: var(--font-primary);
5 | font-weight: 300;
6 | display: flex;
7 | align-items: stretch;
8 | padding: 0 2rem 1.5rem 2rem;
9 | margin: 0 0 1.5rem 0;
10 | border-bottom: 2px solid white;
11 |
12 | @nest &:last-of-type {
13 | border-color: transparent;
14 | padding: 0 2rem;
15 | margin: 0;
16 | }
17 | }
18 |
19 | .pointer {
20 | cursor: pointer;
21 | }
22 |
23 | .meta {
24 | flex: 0 0 25%;
25 | max-width: 25%;
26 | margin: 0 2% 0 0;
27 | }
28 |
29 | .name {
30 | font-weight: 700;
31 | margin: 0;
32 | line-height: 1.5;
33 | }
34 |
35 | .type {
36 | font-weight: 400;
37 | max-width: 95%;
38 | overflow-x: hidden;
39 | text-overflow: ellipsis;
40 | margin: 0;
41 | color: var(--color-light-gray);
42 | line-height: 1.5;
43 | display: block;
44 | }
45 |
46 | .required {
47 | line-height: 1.5;
48 | font-weight: 400;
49 | margin: 0;
50 | color: var(--color-alert);
51 | }
52 |
53 | .info {
54 | flex: 0 0 73%;
55 | max-width: 73%;
56 | margin: 0;
57 | }
58 |
59 | .description {
60 | margin: 0 0 1rem 0;
61 | line-height: 1.5;
62 | }
63 |
64 | .no-content {
65 | color: var(--color-very-light-gray);
66 | margin: 0;
67 | }
68 |
69 | .sample {
70 | margin: 0 0 1rem 0;
71 | font-weight: 400;
72 | }
73 |
74 | .sample-title {
75 | font-weight: 700;
76 | text-decoration: none;
77 | display: inline-block;
78 | margin: 0 0.5rem 0 0;
79 | }
80 |
--------------------------------------------------------------------------------
/src/application/components/request.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | padding: 0 1rem 1rem 1rem;
5 | margin: 0 0 1rem 0;
6 | border: 2px solid var(--color-concrete);
7 | border-bottom-right-radius: var(--border-radius);
8 | border-bottom-left-radius: var(--border-radius);
9 | }
10 |
11 | .json {
12 | padding: 1rem 0 1rem 0;
13 | }
14 |
--------------------------------------------------------------------------------
/src/application/components/resource-card.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | margin: 0.75rem 0;
5 | }
6 |
7 | .is-click {
8 | cursor: pointer;
9 | }
10 |
11 | .flex {
12 | display: flex;
13 | }
14 |
15 | .left {
16 | flex: 0 0 10%;
17 | border-radius: var(--border-radius);
18 | }
19 |
20 | .method {
21 | padding: 0.67rem 1rem;
22 | border-top-left-radius: var(--border-radius);
23 | border-bottom-left-radius: var(--border-radius);
24 | text-transform: uppercase;
25 | letter-spacing: 0.05em;
26 | color: white;
27 | text-align: center;
28 |
29 | @nest &.get {
30 | background: var(--color-method-get);
31 | }
32 |
33 | @nest &.post {
34 | background: var(--color-method-post);
35 | }
36 |
37 | @nest &.put {
38 | background: var(--color-method-put);
39 | }
40 |
41 | @nest &.delete {
42 | background: var(--color-method-delete);
43 | }
44 | }
45 |
46 | .is-expanded-method {
47 | border-bottom-left-radius: 0;
48 | }
49 |
50 | .right {
51 | flex: 0 0 90%;
52 | }
53 |
54 | .path {
55 | display: block;
56 | margin: 0;
57 | background: var(--color-concrete);
58 | font-family: var(--font-code);
59 | padding: 0.67rem 1rem;
60 | border-top-right-radius: var(--border-radius);
61 | border-bottom-right-radius: var(--border-radius);
62 | }
63 |
64 | .is-expanded-path {
65 | border-bottom-right-radius: 0;
66 | }
67 |
68 | .description {
69 | padding: 0.67rem 2rem 0.67rem 11%;
70 | border: 2px solid var(--color-concrete);
71 | border-top-color: transparent;
72 | border-bottom-right-radius: var(--border-radius);
73 | border-bottom-left-radius: var(--border-radius);
74 | }
75 |
--------------------------------------------------------------------------------
/src/application/components/response.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | margin: 0 0 1rem 0;
5 | padding: 0 0 1rem 1rem;
6 | border: 2px solid var(--color-concrete);
7 | border-bottom-right-radius: var(--border-radius);
8 | border-bottom-left-radius: var(--border-radius);
9 | }
10 |
11 | .description {
12 | padding: 0 0 1rem 0;
13 | }
14 |
--------------------------------------------------------------------------------
/src/application/components/service.js:
--------------------------------------------------------------------------------
1 | export const service = {
2 | name: 'apidoc generator',
3 | description: 'This is an api',
4 | organization: {
5 | key: 'bryzek',
6 | },
7 | application: {
8 | key: 'apidoc-generator',
9 | },
10 | resources: [
11 | {
12 | type: 'generator',
13 | plural: 'generators',
14 | operations: [
15 | {
16 | method: 'GET',
17 | path: '/generators',
18 | parameters: [
19 | {
20 | name: 'key',
21 | type: 'string',
22 | location: 'Query',
23 | required: false,
24 | description: 'Filter generators with this key',
25 | },
26 | {
27 | name: 'limit',
28 | type: 'integer',
29 | location: 'Query',
30 | required: true,
31 | description: 'The number of records to return',
32 | default: '100',
33 | minimum: 0,
34 | },
35 | {
36 | name: 'offset',
37 | type: 'integer',
38 | location: 'Query',
39 | required: true,
40 | description: 'Used to paginate. First page of results is 0.',
41 | default: '0',
42 | minimum: 0,
43 | },
44 | ],
45 | responses: [
46 | {
47 | code: {
48 | integer: {
49 | value: 200,
50 | },
51 | },
52 | type: '[generator]',
53 | },
54 | ],
55 | attributes: [],
56 | description: 'Get all available generators',
57 | },
58 | {
59 | method: 'GET',
60 | path: '/generators/:key',
61 | parameters: [
62 | {
63 | name: 'key',
64 | type: 'string',
65 | location: 'Path',
66 | required: true,
67 | },
68 | ],
69 | responses: [
70 | {
71 | code: {
72 | integer: {
73 | value: 200,
74 | },
75 | },
76 | type: 'generator',
77 | },
78 | {
79 | code: {
80 | integer: {
81 | value: 404,
82 | },
83 | },
84 | type: 'unit',
85 | },
86 | ],
87 | attributes: [],
88 | description: 'Get generator with this key',
89 | },
90 | ],
91 | attributes: [],
92 | path: '/generators',
93 | },
94 | ],
95 | };
96 |
--------------------------------------------------------------------------------
/src/application/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { actions, actionTypes } from 'application/actions';
3 | import { reducers } from 'application/reducers';
4 |
5 | import Appln from 'application/components/Application';
6 |
7 | const name = 'application';
8 |
9 | export { name, actionTypes, actions, reducers, Appln };
10 |
--------------------------------------------------------------------------------
/src/application/reducers.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { actionTypes } from 'generated/version';
3 |
4 | import type { Service } from 'generated/version/ServiceType';
5 |
6 | export type State = {|
7 | loaded: boolean,
8 | service?: Service,
9 | importedServices: Service[],
10 | |};
11 |
12 | type Action = {|
13 | type: string,
14 | payload: any, // FIXME
15 | |};
16 |
17 | const initialState: State = {
18 | loaded: false,
19 | importedServices: [],
20 | };
21 |
22 | const application = (state: State = initialState, action: Action) => {
23 | switch (action.type) {
24 | case actionTypes.getByOrgkeyAndApplicationkeyAndVersion_success: {
25 | return {
26 | loaded: true,
27 | service: action.payload.service,
28 | importedServices: action.payload.importedServices,
29 | };
30 | }
31 | case actionTypes.getByOrgkeyAndApplicationkeyAndVersion_doing: {
32 | return Object.assign(state, {
33 | loaded: false,
34 | });
35 | }
36 | default: {
37 | return state;
38 | }
39 | }
40 | };
41 |
42 | const reducers = {
43 | application,
44 | };
45 |
46 | export { reducers };
47 |
--------------------------------------------------------------------------------
/src/components/Button/button.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --spacing: 10px 10px;
5 | --bg-color: var(--color-primary);
6 | }
7 |
8 | .button-inner {
9 | background: var(--color-primary);
10 | outline: none;
11 | border: none;
12 | color: white;
13 | line-height: 32px;
14 | font-size: 14px;
15 | padding: 0 12px;
16 | border-radius: var(--border-radius);
17 | text-decoration: none;
18 | transition: all 0.3s;
19 | cursor: pointer;
20 |
21 | &:not(.disabled):hover {
22 | background: var(--color-primary-dark);
23 | }
24 |
25 | &.disabled {
26 | cursor: default;
27 | background: var(--color-very-light-gray);
28 | color: var(--color-light-gray);
29 | }
30 | }
31 |
32 | .button {
33 | text-decoration: none;
34 | border: none;
35 | }
36 |
37 | /* // Variations */
38 |
39 | .button.loading {
40 | position: relative;
41 | padding-left: 42px;
42 |
43 | &::before {
44 | content: "";
45 | position: absolute;
46 | top: 7px;
47 | left: 12px;
48 | width: 14px;
49 | height: 14px;
50 | border-radius: 50%;
51 | border: 2px solid white;
52 | border-bottom-color: rgba(0, 0, 0, 0);
53 | animation: rotate 1s linear infinite;
54 | }
55 | }
56 |
57 | /* // Component relations */
58 |
59 | h1 + .button { margin-top: 30px; }
60 | h2 + .button { margin-top: 20px; }
61 | p + .button { margin-top: 20px; }
62 | .button + .button { margin-left: 10px; }
63 |
--------------------------------------------------------------------------------
/src/components/Button/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import styles from 'components/Button/button.css';
3 | import classnames from 'classnames';
4 |
5 | const Button = props => (
6 |
7 |
13 |
14 | );
15 |
16 | Button.propTypes = {
17 | children: PropTypes.node.isRequired,
18 | className: PropTypes.string,
19 | classNameInner: PropTypes.string,
20 | onClick: PropTypes.func.isRequired,
21 | target: PropTypes.string,
22 | };
23 |
24 | export default Button;
25 |
26 | export { styles };
27 |
--------------------------------------------------------------------------------
/src/components/Content/content.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .content {
4 | position: fixed 50px 0 0 400px;
5 | width: calc(100% - 400px);
6 | padding: 0;
7 | font-family: var(--font-primary);
8 | overflow-y: auto;
9 |
10 | @nest &::-webkit-scrollbar {
11 | width: 0;
12 | background: transparent;
13 | }
14 | }
15 |
16 | .content-inner {
17 | padding: 0 0 1.25rem 0;
18 | width: 100%;
19 | min-height: calc(100% - 50px);
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Content/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 |
3 | import styles from 'components/Content/content.css';
4 |
5 | const Content = props => (
6 |
7 |
8 | {props.children}
9 |
10 |
11 | );
12 |
13 | Content.propTypes = {
14 | children: PropTypes.node,
15 | };
16 |
17 | export default Content;
18 |
19 | export { styles };
20 |
--------------------------------------------------------------------------------
/src/components/H1/h1.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --spacing: 10px 10px;
5 | --bg-color: var(--color-primary);
6 | }
7 |
8 | .h1 {
9 | font-size: 2.5rem;
10 | color: var(--color-primary);
11 | font-weight: 700;
12 | font-family: var(--font-secondary);
13 | letter-spacing: 0.025em;
14 | margin: 0;
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/H1/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import classnames from 'classnames';
3 |
4 | import styles from 'components/H1/h1.css';
5 |
6 | const H1 = ({ className, children }) => (
7 |
8 | {children}
9 |
10 | );
11 |
12 | H1.propTypes = {
13 | children: PropTypes.node,
14 | className: PropTypes.string,
15 | };
16 |
17 | export default H1;
18 |
19 | export { styles };
20 |
--------------------------------------------------------------------------------
/src/components/H2/h2.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --bg-color: var(--color-primary);
5 | }
6 |
7 | .pointer {
8 | cursor: pointer;
9 | }
10 |
11 | .h2 {
12 | font-size: 24px;
13 | font-weight: 400;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/H2/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import classnames from 'classnames';
3 |
4 | import styles from 'components/H2/h2.css';
5 |
6 | const H2 = ({ className, children, click }) => (
7 |
11 | {children}
12 |
13 | );
14 |
15 | H2.propTypes = {
16 | children: PropTypes.node.isRequired,
17 | className: PropTypes.string,
18 | click: PropTypes.func,
19 | };
20 |
21 | export default H2;
22 |
23 | export { styles };
24 |
--------------------------------------------------------------------------------
/src/components/H3/h3.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --bg-color: var(--color-primary);
5 | }
6 |
7 | .pointer {
8 | cursor: pointer;
9 | }
10 |
11 | .h3 {
12 | font-size: 18px;
13 | font-weight: 400;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/H3/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import classnames from 'classnames';
3 |
4 | import styles from 'components/H3/h3.css';
5 |
6 | const H3 = ({ className, children, click }) => (
7 |
11 | {children}
12 |
13 | );
14 |
15 | H3.propTypes = {
16 | children: PropTypes.node.isRequired,
17 | className: PropTypes.string,
18 | click: PropTypes.func,
19 | };
20 |
21 | export default H3;
22 |
23 | export { styles };
24 |
--------------------------------------------------------------------------------
/src/components/LoadingOverlay/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
3 | import classnames from 'classnames';
4 |
5 | import styles from 'components/LoadingOverlay/loading-overlay.css';
6 |
7 | const LoadingOverlay = (
8 | {
9 | isLoaded,
10 | children,
11 | }: {
12 | isLoaded: boolean,
13 | children?: React$Element<*>,
14 | } = {}
15 | ) => {
16 | const loader = (
17 |
24 | );
25 | return (
26 |
33 | {isLoaded ? {children}
: loader}
34 |
35 | );
36 | };
37 |
38 | export default LoadingOverlay;
39 |
--------------------------------------------------------------------------------
/src/components/Markdown/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import ReactMarkdown from 'react-markdown';
3 | import classnames from 'classnames';
4 |
5 | import styles from 'components/Markdown/markdown.css';
6 |
7 | const Markdown = ({ source, className }) => (
8 |
9 |
10 |
11 | );
12 |
13 | Markdown.propTypes = {
14 | source: PropTypes.string.isRequired,
15 | className: PropTypes.string,
16 | };
17 |
18 | export default Markdown;
19 |
20 | export { styles };
21 |
--------------------------------------------------------------------------------
/src/components/Markdown/markdown.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .markdown {
4 | @nest & p {
5 | font-size: 1rem;
6 | font-weight: 400;
7 | line-height: 1.6;
8 | margin: 0 0 1rem 0;
9 |
10 | @nest &:last-of-type {
11 | margin: 0;
12 | }
13 | }
14 |
15 | @nest & code {
16 | font-family: var(--font-code);
17 | display: inline-block;
18 | background: white;
19 | border-radius: 3px;
20 | color: var(--color-red);
21 | border: 1px solid var(--color-very-light-gray);
22 | line-height: 1.5;
23 | font-size: 0.85rem;
24 | padding: 0 0.25rem;
25 | }
26 |
27 | @nest & ul {
28 | list-style-type: none;
29 | padding: 0;
30 | margin: 0 0 0 0.2rem;
31 | font-size: 0;
32 |
33 | @nest & li {
34 | display: block;
35 | font-size: 1rem;
36 | font-weight: normal;
37 | padding: 0.25rem 0 0.25rem 1rem;
38 | margin: 0;
39 | line-height: 1.5;
40 | border-left: 2px solid var(--color-very-light-gray);
41 | }
42 | }
43 |
44 | @nest & a {
45 | text-decoration: none;
46 | color: var(--color-cool-blue);
47 | }
48 |
49 | @nest & h1, & h2 {
50 | font-size: 1rem;
51 | margin: 0 0 1rem 0;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/NavBar/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 |
3 | import Button from 'components/Button';
4 | import styles from 'components/NavBar/navbar.css';
5 |
6 | const githubLink = () => (
7 |
13 |
25 |
26 | );
27 |
28 | const NavBar = ({ title, items, homeOnClick, removeGithubLink }) => (
29 |
30 |
{title}
31 |
32 | {items.map((item, id) => (
33 |
36 | ))}
37 |
38 | {removeGithubLink ? null : githubLink()}
39 |
40 | );
41 |
42 | NavBar.propTypes = {
43 | title: PropTypes.string.isRequired,
44 | items: PropTypes.array.isRequired,
45 | homeOnClick: PropTypes.func.isRequired,
46 | removeGithubLink: PropTypes.bool.isRequired,
47 | };
48 |
49 | export default NavBar;
50 |
51 | export { styles };
52 |
--------------------------------------------------------------------------------
/src/components/NavBar/navbar.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --spacing: 10px 10px;
5 | --bg-color: var(--color-primary);
6 | }
7 |
8 | .navbar {
9 | position: fixed;
10 | width: 100%;
11 | height: 50px;
12 | background: var(--color-primary);
13 | padding: 5px 20px;
14 | }
15 |
16 | .home {
17 | font-family: var(--font-secondary);
18 | text-transform: uppercase;
19 | color: white;
20 | padding: 5px 0;
21 | float: left;
22 | line-height: 2;
23 | cursor: pointer;
24 | letter-spacing: 0.05em;
25 | text-shadow: 0.1rem 0.1rem 0.2rem rgba(0, 0, 0, 0.1);
26 | width: 400px;
27 | }
28 |
29 | .breadcrumbs {
30 | float: left;
31 | }
32 |
33 | .github {
34 | padding-top: 2px;
35 | float: right;
36 | color: white;
37 | }
38 |
39 | .button {
40 | display: inline-block;
41 | line-height: 40px;
42 | padding-left: 10px;
43 |
44 | @nest &::before {
45 | content: '/';
46 | color: white;
47 | position: relative 0 auto auto -10px;
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/src/components/SideBar/index.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import classnames from 'classnames';
3 |
4 | import { simplifyName } from 'utils';
5 |
6 | import styles from 'components/SideBar/sidebar.css';
7 |
8 | const SidebarIcon = ({ item }) => {
9 | const iconClasses = classnames(
10 | styles[item.type.toLowerCase()],
11 | styles.icon,
12 | item.method ? styles[item.method.toLowerCase()] : null
13 | );
14 |
15 | const markup = item.method ? item.method : item.type[0];
16 |
17 | return {markup}
;
18 | };
19 |
20 | SidebarIcon.propTypes = {
21 | item: PropTypes.object.isRequired,
22 | };
23 |
24 | const Item = ({ item }) => (
25 |
30 | {item.path ? `${item.method} ${item.path}` : simplifyName(item.name)}
31 |
32 | );
33 |
34 | Item.propTypes = {
35 | item: PropTypes.object.isRequired,
36 | };
37 |
38 | const Groups = ({ group }) => (
39 |
40 |
{group.name}
41 | {group.items.map((item, id) => )}
42 |
43 | );
44 |
45 | Groups.propTypes = {
46 | group: PropTypes.object.isRequired,
47 | };
48 |
49 | const Section = ({ section }) => (
50 |
51 |
52 | {section.items.map((group, id) => )}
53 |
54 | );
55 |
56 | Section.propTypes = {
57 | section: PropTypes.object.isRequired,
58 | };
59 |
60 | const SideBar = ({ sections }) => (
61 |
62 |
63 | {sections.map((section, id) => )}
64 |
65 |
66 | );
67 |
68 | SideBar.propTypes = {
69 | sections: PropTypes.array.isRequired,
70 | };
71 |
72 | export default SideBar;
73 |
74 | export { styles };
75 |
--------------------------------------------------------------------------------
/src/components/SideBar/sidebar.css:
--------------------------------------------------------------------------------
1 | @import 'variables.css';
2 |
3 | :root {
4 | --spacing: 10px 10px;
5 | --bg-color: var(--color-primary);
6 | }
7 |
8 | .sidebar {
9 | position: fixed 50px auto 0 0;
10 | width: 400px;
11 | height: 100%;
12 | background: var(--color-tuatara);
13 | color: white;
14 | padding: 1.25rem;
15 | overflow-y: auto;
16 | }
17 |
18 | .sidebar-inner {
19 | padding-bottom: 1.25rem;
20 | min-height: calc(100% - 50px);
21 | }
22 |
23 | .icon {
24 | display: inline-block;
25 | margin-right: 0.4rem;
26 | border-radius: 3px;
27 | color: white;
28 | font-size: 0.5rem;
29 | padding: 0.25rem 0.25rem 0.35rem 0.25rem;
30 | text-align: center;
31 | line-height: 1.2;
32 | position: relative;
33 | top: -1px;
34 | }
35 |
36 | .get {
37 | background: var(--color-method-get);
38 | }
39 |
40 | .post {
41 | background: var(--color-method-post);
42 | }
43 |
44 | .put {
45 | background: var(--color-method-put);
46 | }
47 |
48 | .delete {
49 | line-height: 1.7;
50 | background: var(--color-method-delete);
51 | }
52 |
53 | .enum {
54 | background: var(--color-hawkes-blue);
55 | color: black;
56 | line-height: 1.5;
57 | }
58 |
59 | .model {
60 | background: var(--color-medium-persian-blue);
61 | color: white;
62 | }
63 |
64 | .a {
65 | color: white;
66 | display: block;
67 | padding: 0.5rem 0 0.5rem 0.75rem;
68 | margin: 0 0 0 0.25rem;
69 | font-family: var(--font-primary);
70 | text-decoration: none;
71 | border-left: 2px solid rgba(255, 255, 255, 0.5);
72 | position: relative;
73 | cursor: pointer;
74 | max-width: 100%;
75 | overflow: hidden;
76 | white-space: nowrap;
77 |
78 | @nest &:after {
79 | content: '';
80 | position: absolute 0 0 0 0;
81 | background-image: linear-gradient(to right, transparent 90%, color(var(--color-tuatara) alpha(- 95%)));
82 | }
83 |
84 | @nest &:hover, .active {
85 | background: var(--color-primary);
86 | }
87 | }
88 |
89 | .group {
90 | margin: 0 0 2rem 0;
91 |
92 | @nest &:last-of-type {
93 | margin: 0;
94 | }
95 | }
96 |
97 | .h2 {
98 | font-family: var(--font-primary);
99 | margin: 0 0 0.5rem 0;
100 | font-weight: 400;
101 | max-width: 100%;
102 | overflow: hidden;
103 | white-space: nowrap;
104 | }
105 |
106 | .label {
107 | font-family: var(--font-secondary);
108 | font-weight: 700;
109 | text-transform: uppercase;
110 | letter-spacing: 0.05rem;
111 | color: var(--color-primary);
112 | display: block;
113 | margin: 0 0 0.5rem 0;
114 | }
115 |
116 | .section {
117 | margin: 0 0 2rem 0;
118 | }
119 |
--------------------------------------------------------------------------------
/src/documentation/documentation.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | padding: 3rem;
5 | }
6 |
7 | .h1 {
8 | margin-bottom: 1rem;
9 | }
10 |
--------------------------------------------------------------------------------
/src/documentation/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React, { Component } from 'react';
3 | import { bindActionCreators } from 'redux';
4 | import { connect } from 'react-redux';
5 |
6 | import { actions as docActions } from 'generated/documentation/getByRootUrlAndMarkdownPath';
7 |
8 | import H1 from 'components/H1';
9 | import LoadingOverlay from 'components/LoadingOverlay';
10 | import Markdown from 'components/Markdown';
11 |
12 | import styles from 'documentation/documentation.css';
13 |
14 | import type { State as ApplicationState } from 'app/reducers';
15 | import docs from '../../documents.json';
16 |
17 | const allActions = Object.assign({}, docActions);
18 |
19 | type Props = {|
20 | loaded: boolean,
21 | params: Object, // FIXME
22 | actions: Object, // FIXME
23 | markdown: string,
24 | |};
25 |
26 | class Documentation extends Component {
27 | props: Props;
28 |
29 | componentWillMount() {
30 | const document = docs.organizations[
31 | this.props.params.organizationKey
32 | ].documents.filter(
33 | doc => doc.slug === this.props.params.documentationKey
34 | )[0];
35 | this.props.actions.getByRootUrlAndMarkdownPath_get({
36 | rootUrl: document.rootUrl,
37 | markdownPath: document.markdownPath,
38 | });
39 | }
40 |
41 | componentWillReceiveProps(nextProps) {
42 | if (
43 | this.props.params.documentationKey !== nextProps.params.documentationKey
44 | ) {
45 | const document = docs.organizations[
46 | nextProps.params.organizationKey
47 | ].documents.filter(
48 | doc => doc.slug === nextProps.params.documentationKey
49 | )[0];
50 | this.props.actions.getByRootUrlAndMarkdownPath_get({
51 | rootUrl: document.rootUrl,
52 | markdownPath: document.markdownPath,
53 | });
54 | }
55 | }
56 |
57 | render() {
58 | const document = docs.organizations[
59 | this.props.params.organizationKey
60 | ].documents.filter(
61 | doc => doc.slug === this.props.params.documentationKey
62 | )[0];
63 | return (
64 |
65 |
66 |
67 |
68 | {document.name}
69 |
70 |
74 |
75 |
76 |
77 | );
78 | }
79 | }
80 |
81 | const mapStateToProps = (state: ApplicationState) => ({
82 | markdown: state.documentation.markdown,
83 | loaded: state.documentation.loaded,
84 | });
85 |
86 | const mapDispatchToProps = (dispatch): { [key: string]: Function } => ({
87 | actions: bindActionCreators(allActions, dispatch),
88 | });
89 |
90 | export default connect(mapStateToProps, mapDispatchToProps)(Documentation);
91 |
92 | export { styles };
93 |
--------------------------------------------------------------------------------
/src/documentation/reducers.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { actionTypes } from 'generated/documentation/getByRootUrlAndMarkdownPath';
3 |
4 | export type State = {
5 | loaded: boolean,
6 | markdown?: string,
7 | };
8 |
9 | type Action = {|
10 | type: string,
11 | payload: any, // FIXME
12 | |};
13 |
14 | const initialState: State = {
15 | loaded: false,
16 | };
17 |
18 | const documentation = (state: State = initialState, action: Action) => {
19 | switch (action.type) {
20 | // Get documentation
21 | case actionTypes.getByRootUrlAndMarkdownPath_success: {
22 | return {
23 | markdown: action.payload,
24 | loaded: true,
25 | };
26 | }
27 | case actionTypes.getByRootUrlAndMarkdownPath_doing: {
28 | return {
29 | loaded: false,
30 | markdown: state.markdown,
31 | };
32 | }
33 | case actionTypes.getByRootUrlAndMarkdownPath_failure: {
34 | return {
35 | loaded: true,
36 | markdown: state.markdown,
37 | };
38 | }
39 | default: {
40 | return state;
41 | }
42 | }
43 | };
44 |
45 | const reducers = {
46 | documentation,
47 | };
48 |
49 | export { reducers };
50 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apicollective/ui/0324e73e4b750d1c59302e0ad85d87ab772fb8dc/src/favicon.ico
--------------------------------------------------------------------------------
/src/generated/application/getByOrgkey.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 | /* eslint-disable max-len */
3 |
4 | import { takeEvery, takeLatest } from 'redux-saga';
5 | import { call, put } from 'redux-saga/effects';
6 | import * as request from 'superagent';
7 |
8 | function api({ orgKey, name, guid, key, has_version, limit, offset } = {}) {
9 | return request.get(`${process.env.APIDOC_HOST}/${orgKey}`);
10 | }
11 |
12 | const actionTypes = {
13 | getByOrgkey_get: 'getByOrgkey/get',
14 | getByOrgkey_doing: 'getByOrgkey/doing',
15 | getByOrgkey_success: 'getByOrgkey/success',
16 | getByOrgkey_failure: 'getByOrgkey/failure',
17 | };
18 |
19 | const actions = {
20 | /**
21 | * Search all applications. Results are always paginated.
22 | * @param {string} orgKey - The organization key for which to search applications
23 | * @param {string=} name - The name of an application. Case in-sensitive. Exact match (Optional)
24 | * @param {uuid=} guid - The guid of an application. Exact match (Optional)
25 | * @param {string=} key - The key of an application. Case in-sensitive. Exact match (Optional)
26 | * @param {boolean=} has_version - If true, we return applications that have at least one version. If false, we return applications that have no versions in the system (Optional)
27 | * @param {long} limit - The number of records to return
28 | * @param {long} offset - Used to paginate. First page of results is 0.
29 | */
30 | getByOrgkey_get: (
31 | { orgKey, name, guid, key, has_version, limit, offset } = {}
32 | ) => ({
33 | type: actionTypes.getByOrgkey_get,
34 | payload: {
35 | orgKey,
36 | name,
37 | guid,
38 | key,
39 | has_version,
40 | limit,
41 | offset,
42 | },
43 | }),
44 | getByOrgkey_doing: () => ({
45 | type: actionTypes.getByOrgkey_doing,
46 | }),
47 | getByOrgkey_success: response => ({
48 | type: actionTypes.getByOrgkey_success,
49 | payload: response,
50 | }),
51 | getByOrgkey_failure: err => ({
52 | type: actionTypes.getByOrgkey_failure,
53 | payload: err,
54 | error: true,
55 | }),
56 | };
57 |
58 | function* saga(action) {
59 | try {
60 | yield put(actions.getByOrgkey_doing());
61 | const { body } = yield call(api, action.payload);
62 | yield put(actions.getByOrgkey_success(body));
63 | } catch (error) {
64 | yield put(actions.getByOrgkey_failure(error));
65 | }
66 | }
67 |
68 | /**
69 | * Start this saga if you'd prefer to process every action
70 | */
71 | function* takeEverySaga() {
72 | yield* takeEvery(actionTypes.getByOrgkey_get, saga);
73 | }
74 |
75 | /**
76 | * Start this saga if you'd prefer to process only the latest action
77 | */
78 | function* takeLatestSaga() {
79 | yield* takeLatest(actionTypes.getByOrgkey_get, saga);
80 | }
81 |
82 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
83 |
--------------------------------------------------------------------------------
/src/generated/docs/getHighLevelDocs.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 | /* eslint-disable max-len */
3 |
4 | import { takeEvery, takeLatest } from 'redux-saga';
5 | import { call, put } from 'redux-saga/effects';
6 | import * as request from 'superagent';
7 |
8 | function api({ orgKey, name, guid, key, has_version, limit, offset } = {}) {
9 | return request.get(`${process.env.APIDOC_HOST}/docs/${orgKey}`);
10 | }
11 |
12 | const actionTypes = {
13 | getHighLevelDocs_get: 'getHighLevelDocs/get',
14 | getHighLevelDocs_doing: 'getHighLevelDocs/doing',
15 | getHighLevelDocs_success: 'getHighLevelDocs/success',
16 | getHighLevelDocs_failure: '/failure',
17 | };
18 |
19 | const actions = {
20 | /**
21 | * Search all applications. Results are always paginated.
22 | * @param {string} orgKey - The organization key for which to search applications
23 | * @param {string=} name - The name of an application. Case in-sensitive. Exact match (Optional)
24 | * @param {uuid=} guid - The guid of an application. Exact match (Optional)
25 | * @param {string=} key - The key of an application. Case in-sensitive. Exact match (Optional)
26 | * @param {boolean=} has_version - If true, we return applications that have at least one version. If false, we return applications that have no versions in the system (Optional)
27 | * @param {long} limit - The number of records to return
28 | * @param {long} offset - Used to paginate. First page of results is 0.
29 | */
30 | getHighLevelDocs_get: (
31 | { orgKey, name, guid, key, has_version, limit, offset } = {}
32 | ) => ({
33 | type: actionTypes.getHighLevelDocs_get,
34 | payload: {
35 | orgKey,
36 | },
37 | }),
38 | getHighLevelDocs_doing: () => ({
39 | type: actionTypes.getHighLevelDocs_doing,
40 | }),
41 | getHighLevelDocs_success: response => ({
42 | type: actionTypes.getHighLevelDocs_success,
43 | payload: response,
44 | }),
45 | getHighLevelDocs_failure: err => ({
46 | type: actionTypes.getHighLevelDocs_failure,
47 | payload: err,
48 | error: true,
49 | }),
50 | };
51 |
52 | function* saga(action) {
53 | try {
54 | yield put(actions.getHighLevelDocs_doing());
55 | const { body } = yield call(api, action.payload);
56 | yield put(actions.getHighLevelDocs_success(body));
57 | } catch (error) {
58 | yield put(actions.getHighLevelDocs_failure(error));
59 | }
60 | }
61 |
62 | /**
63 | * Start this saga if you'd prefer to process every action
64 | */
65 | function* takeEverySaga() {
66 | yield* takeEvery(actionTypes.getHighLevelDocs_get, saga);
67 | }
68 |
69 | /**
70 | * Start this saga if you'd prefer to process only the latest action
71 | */
72 | function* takeLatestSaga() {
73 | yield* takeLatest(actionTypes.getHighLevelDocs_get, saga);
74 | }
75 |
76 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
77 |
--------------------------------------------------------------------------------
/src/generated/documentation/getByRootUrlAndMarkdownPath.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 | /* eslint-disable max-len */
3 |
4 | import { takeEvery, takeLatest } from 'redux-saga';
5 | import { call, put } from 'redux-saga/effects';
6 | import * as request from 'superagent';
7 | import { resolve } from 'url';
8 |
9 | function api({ rootUrl, markdownPath } = {}) {
10 | const url = resolve(rootUrl, markdownPath);
11 | return request.get(url);
12 | }
13 |
14 | const actionTypes = {
15 | getByRootUrlAndMarkdownPath_get: 'getByRootUrlAndMarkdownPath/get',
16 | getByRootUrlAndMarkdownPath_doing: 'getByRootUrlAndMarkdownPath/doing',
17 | getByRootUrlAndMarkdownPath_success: 'getByRootUrlAndMarkdownPath/success',
18 | getByRootUrlAndMarkdownPath_failure: 'getByRootUrlAndMarkdownPath/failure',
19 | };
20 |
21 | const actions = {
22 | getByRootUrlAndMarkdownPath_get: ({ rootUrl, markdownPath } = {}) => ({
23 | type: actionTypes.getByRootUrlAndMarkdownPath_get,
24 | payload: {
25 | rootUrl,
26 | markdownPath,
27 | },
28 | }),
29 | getByRootUrlAndMarkdownPath_doing: () => ({
30 | type: actionTypes.getByRootUrlAndMarkdownPath_doing,
31 | }),
32 | getByRootUrlAndMarkdownPath_success: response => ({
33 | type: actionTypes.getByRootUrlAndMarkdownPath_success,
34 | payload: response,
35 | }),
36 | getByRootUrlAndMarkdownPath_failure: err => ({
37 | type: actionTypes.getByRootUrlAndMarkdownPath_failure,
38 | payload: err,
39 | error: true,
40 | }),
41 | };
42 |
43 | function* saga(action) {
44 | try {
45 | const rootUrl = action.payload.rootUrl;
46 | yield put(actions.getByRootUrlAndMarkdownPath_doing());
47 | const { text } = yield call(api, action.payload);
48 |
49 | const imagesRegex = /!\[(.*)]\(/gi;
50 | const textWithImages = text.replace(imagesRegex, `;
51 |
52 | yield put(actions.getByRootUrlAndMarkdownPath_success(textWithImages));
53 | } catch (error) {
54 | yield put(actions.getByRootUrlAndMarkdownPath_failure(error));
55 | }
56 | }
57 |
58 | /**
59 | * Start this saga if you'd prefer to process every action
60 | */
61 | function* takeEverySaga() {
62 | yield* takeEvery(actionTypes.getByRootUrlAndMarkdownPath_get, saga);
63 | }
64 |
65 | /**
66 | * Start this saga if you'd prefer to process only the latest action
67 | */
68 | function* takeLatestSaga() {
69 | yield* takeLatest(actionTypes.getByRootUrlAndMarkdownPath_get, saga);
70 | }
71 |
72 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
73 |
--------------------------------------------------------------------------------
/src/generated/organization/getOrganizations.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 | /* eslint-disable max-len */
3 |
4 | import { takeEvery, takeLatest } from 'redux-saga';
5 | import { call, put } from 'redux-saga/effects';
6 | import * as request from 'superagent';
7 |
8 | function api({ guid, user_guid, key, name, namespace, limit, offset } = {}) {
9 | return request.get(`${process.env.APIDOC_HOST}/organizations`);
10 | }
11 |
12 | // FIXME - eg of types
13 | /* declare type Response = 'yes' | 'no' | 'maybe';*/
14 | const actionTypes = {
15 | getOrganizations_get: 'getOrganizations/get',
16 | getOrganizations_doing: 'getOrganizations/doing',
17 | getOrganizations_success: 'getOrganizations/success',
18 | getOrganizations_failure: 'getOrganizations/failure',
19 | };
20 |
21 | const actions = {
22 | /**
23 | * Search all organizations. Results are always paginated.
24 | * @param {uuid=} guid - Finds the organization with this guid, if any (Optional)
25 | * @param {uuid=} user_guid - If specified, restricts to organizations that this user is specifically a member of (e.g. will exclude public organizations with which the user does not have a direct membership). (Optional)
26 | * @param {string=} key - Find organizations with this key. Case in-sensitive. Exact match (Optional)
27 | * @param {string=} name - Find organizations with this name. Case in-sensitive. Exact match (Optional)
28 | * @param {string=} namespace - Find organizations with this namespace. Case in-sensitive. Exact match (Optional)
29 | * @param {long} limit - The number of records to return
30 | * @param {long} offset - Used to paginate. First page of results is 0.
31 | */
32 | getOrganizations_get: (
33 | { guid, user_guid, key, name, namespace, limit, offset } = {}
34 | ) => ({
35 | type: actionTypes.getOrganizations_get,
36 | payload: {
37 | guid,
38 | user_guid,
39 | key,
40 | name,
41 | namespace,
42 | limit,
43 | offset,
44 | },
45 | }),
46 | getOrganizations_doing: () => ({
47 | type: actionTypes.getOrganizations_doing,
48 | }),
49 | getOrganizations_success: response => ({
50 | type: actionTypes.getOrganizations_success,
51 | payload: response,
52 | }),
53 | getOrganizations_failure: err => ({
54 | type: actionTypes.getOrganizations_failure,
55 | payload: err,
56 | error: true,
57 | }),
58 | };
59 |
60 | function* saga(action) {
61 | try {
62 | yield put(actions.getOrganizations_doing());
63 | const { body } = yield call(api, action.payload);
64 | yield put(actions.getOrganizations_success(body));
65 | } catch (error) {
66 | yield put(actions.getOrganizations_failure(error));
67 | }
68 | }
69 |
70 | /**
71 | * Start this saga if you'd prefer to process every action
72 | */
73 | function* takeEverySaga() {
74 | yield* takeEvery(actionTypes.getOrganizations_get, saga);
75 | }
76 |
77 | /**
78 | * Start this saga if you'd prefer to process only the latest action
79 | */
80 | function* takeLatestSaga() {
81 | yield* takeLatest(actionTypes.getOrganizations_get, saga);
82 | }
83 |
84 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
85 |
--------------------------------------------------------------------------------
/src/generated/organization/getOrganizationsByKey.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 |
3 | import { takeEvery, takeLatest } from 'redux-saga';
4 | import { call, put } from 'redux-saga/effects';
5 | import * as request from 'superagent';
6 |
7 | function api({ key } = {}) {
8 | return request.get(`${process.env.APIDOC_HOST}/organizations/${key}`);
9 | }
10 |
11 | const actionTypes = {
12 | getOrganizationsByKey_get: 'getOrganizationsByKey/get',
13 | getOrganizationsByKey_doing: 'getOrganizationsByKey/doing',
14 | getOrganizationsByKey_success: 'getOrganizationsByKey/success',
15 | getOrganizationsByKey_failure: 'getOrganizationsByKey/failure',
16 | };
17 |
18 | const actions = {
19 | /**
20 | * Returns the organization with this key.
21 | * @param {string} key -
22 | */
23 | getOrganizationsByKey_get: key => ({
24 | type: actionTypes.getOrganizationsByKey_get,
25 | payload: {
26 | key,
27 | },
28 | }),
29 | getOrganizationsByKey_doing: () => ({
30 | type: actionTypes.getOrganizationsByKey_doing,
31 | }),
32 | getOrganizationsByKey_success: response => ({
33 | type: actionTypes.getOrganizationsByKey_success,
34 | payload: response,
35 | }),
36 | getOrganizationsByKey_failure: err => ({
37 | type: actionTypes.getOrganizationsByKey_failure,
38 | payload: err,
39 | error: true,
40 | }),
41 | };
42 |
43 | function* saga(action) {
44 | try {
45 | yield put(actions.getOrganizationsByKey_doing());
46 | const { body } = yield call(api, action.payload);
47 | yield put(actions.getOrganizationsByKey_success(body));
48 | } catch (error) {
49 | yield put(actions.getOrganizationsByKey_failure(error));
50 | }
51 | }
52 |
53 | /**
54 | * Start this saga if you'd prefer to process every action
55 | */
56 | function* takeEverySaga() {
57 | yield* takeEvery(actionTypes.getOrganizationsByKey_get, saga);
58 | }
59 |
60 | /**
61 | * Start this saga if you'd prefer to process only the latest action
62 | */
63 | function* takeLatestSaga() {
64 | yield* takeLatest(actionTypes.getOrganizationsByKey_get, saga);
65 | }
66 |
67 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
68 |
--------------------------------------------------------------------------------
/src/generated/organization/index.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 |
3 | import * as getOrganizations from 'generated/organization/getOrganizations';
4 |
5 | const actionTypes = Object.assign({}, getOrganizations.actionTypes);
6 |
7 | const actions = Object.assign({}, getOrganizations.actions);
8 |
9 | const sagas = {
10 | getOrganizationsTakeEverySaga: getOrganizations.takeEverySaga,
11 | getOrganizationsTakeLatestSaga: getOrganizations.takeLatestSaga,
12 | };
13 |
14 | export { actionTypes, actions, sagas };
15 |
--------------------------------------------------------------------------------
/src/generated/version/ServiceType.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | // THIS FILE WILL BE GENERATED in the future
3 |
4 | export type Header = {|
5 | name: string,
6 | type: string,
7 | required: boolean,
8 | description?: string,
9 | default?: string,
10 | |};
11 |
12 | export type Organization = {|
13 | key: string,
14 | name: string,
15 | description?: string,
16 | |};
17 |
18 | export type Application = {|
19 | key: string,
20 | name: string,
21 | description?: string,
22 | |};
23 |
24 | export type Import = {|
25 | uri: string,
26 | namespace: string,
27 | organization: Organization,
28 | application: Application,
29 | version: string,
30 | enums: string[],
31 | unions: string[],
32 | models: string[],
33 | |};
34 |
35 | export type EnumValue = {|
36 | name: string,
37 | description?: string,
38 | |};
39 |
40 | export type Enum = {|
41 | name: string,
42 | plural: string,
43 | description?: string,
44 | values: EnumValue[],
45 | |};
46 |
47 | export type UnionType = {|
48 | type: string,
49 | description?: string,
50 | |};
51 |
52 | export type Union = {|
53 | name: string,
54 | plural: string,
55 | descriminator?: string,
56 | description?: string,
57 | types: UnionType[],
58 | |};
59 |
60 | export type Field = {|
61 | name: string,
62 | type: string,
63 | description?: string,
64 | default?: string,
65 | required?: boolean,
66 | minimum?: number,
67 | maximum?: number,
68 | example?: string,
69 | |};
70 |
71 | export type Model = {|
72 | name: string,
73 | plural: string,
74 | description?: string,
75 | fields: Field[],
76 | |};
77 |
78 | export type Method = string;
79 |
80 | export type Parameter = {|
81 | name: string,
82 | type: string,
83 | location: string,
84 | description?: string,
85 | required?: boolean,
86 | default?: string,
87 | minimum?: number,
88 | maximum?: number,
89 | example?: string,
90 | |};
91 |
92 | export type Integer = {|
93 | value: number,
94 | |};
95 |
96 | export type Code = {|
97 | integer: Integer,
98 | |};
99 |
100 | export type Response = {|
101 | code: Code,
102 | type: string,
103 | description?: string,
104 | |};
105 |
106 | export type Body = {|
107 | type: string,
108 | description: ?string,
109 | |};
110 |
111 | export type Operation = {|
112 | method: Method,
113 | path: string,
114 | description?: string,
115 | body?: Body,
116 | parameters: Parameter[],
117 | responses: Response[],
118 | |};
119 |
120 | export type Resource = {|
121 | type: string,
122 | plural: string,
123 | path?: string,
124 | description?: string,
125 | operations: Operation[],
126 | |};
127 |
128 | export type Service = {|
129 | name: string,
130 | organization: Organization,
131 | application: Application,
132 | namespace: string,
133 | version: string,
134 | headers: Header[],
135 | imports: Import[],
136 | enums: Enum[],
137 | unions: Union[],
138 | models: Model[],
139 | resources: Resource[],
140 | |};
141 |
--------------------------------------------------------------------------------
/src/generated/version/getByOrgkeyAndApplicationkeyAndVersion.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 | /* eslint-disable max-len */
3 |
4 | import { takeEvery, takeLatest } from 'redux-saga';
5 | import { call, put } from 'redux-saga/effects';
6 | import * as request from 'superagent';
7 |
8 | // import exampleService from 'exampleService.json';
9 |
10 | function api({ orgKey, applicationKey, version } = {}) {
11 | return request.get(
12 | `${process.env.APIDOC_HOST}/${orgKey}/${applicationKey}/latest`
13 | );
14 | // return new Promise((resolve) => {
15 | // resolve(exampleService);
16 | // });
17 | }
18 |
19 | const actionTypes = {
20 | getByOrgkeyAndApplicationkeyAndVersion_get: 'getByOrgkeyAndApplicationkeyAndVersion/get',
21 | getByOrgkeyAndApplicationkeyAndVersion_doing: 'getByOrgkeyAndApplicationkeyAndVersion/doing',
22 | getByOrgkeyAndApplicationkeyAndVersion_success: 'getByOrgkeyAndApplicationkeyAndVersion/success',
23 | getByOrgkeyAndApplicationkeyAndVersion_failure: 'getByOrgkeyAndApplicationkeyAndVersion/failure',
24 | };
25 |
26 | const actions = {
27 | /**
28 | * Retrieve a specific version of an application.
29 | * @param {string} orgKey -
30 | * @param {string} applicationKey -
31 | * @param {string} version - The version of tthis application to download, or the keyword latest to get the latest version
32 | */
33 | getByOrgkeyAndApplicationkeyAndVersion_get: (
34 | { orgKey, applicationKey, version } = {}
35 | ) => ({
36 | type: actionTypes.getByOrgkeyAndApplicationkeyAndVersion_get,
37 | payload: {
38 | orgKey,
39 | applicationKey,
40 | version,
41 | },
42 | }),
43 | getByOrgkeyAndApplicationkeyAndVersion_doing: () => ({
44 | type: actionTypes.getByOrgkeyAndApplicationkeyAndVersion_doing,
45 | }),
46 | getByOrgkeyAndApplicationkeyAndVersion_success: payload => ({
47 | type: actionTypes.getByOrgkeyAndApplicationkeyAndVersion_success,
48 | payload,
49 | }),
50 | getByOrgkeyAndApplicationkeyAndVersion_failure: err => ({
51 | type: actionTypes.getByOrgkeyAndApplicationkeyAndVersion_failure,
52 | payload: err,
53 | error: true,
54 | }),
55 | };
56 |
57 | const namespaceEntities = (namespace, entities, entityType) =>
58 | entities.map(entity =>
59 | Object.assign(entity, {
60 | name: `${namespace}.${entityType}.${entity.name}`,
61 | plural: `${namespace}.${entityType}.${entity.plural}`,
62 | })
63 | );
64 |
65 | function* saga(action) {
66 | try {
67 | yield put(actions.getByOrgkeyAndApplicationkeyAndVersion_doing());
68 | const { body } = yield call(api, action.payload);
69 | const calls = body.service.imports.map(importValue =>
70 | call(api, {
71 | orgKey: importValue.organization.key,
72 | applicationKey: importValue.application.key,
73 | version: importValue.version,
74 | })
75 | );
76 | const results = yield calls;
77 | body.importedServices = results.map(result => {
78 | const service = result.body.service;
79 | namespaceEntities(service.namespace, service.models, 'models');
80 | namespaceEntities(service.namespace, service.enums, 'enums');
81 | return service;
82 | });
83 |
84 | yield put(actions.getByOrgkeyAndApplicationkeyAndVersion_success(body));
85 | } catch (error) {
86 | yield put(actions.getByOrgkeyAndApplicationkeyAndVersion_failure(error));
87 | }
88 | }
89 |
90 | /**
91 | * Start this saga if you'd prefer to process every action
92 | */
93 | function* takeEverySaga() {
94 | yield* takeEvery(
95 | actionTypes.getByOrgkeyAndApplicationkeyAndVersion_get,
96 | saga
97 | );
98 | }
99 |
100 | /**
101 | * Start this saga if you'd prefer to process only the latest action
102 | */
103 | function* takeLatestSaga() {
104 | yield* takeLatest(
105 | actionTypes.getByOrgkeyAndApplicationkeyAndVersion_get,
106 | saga
107 | );
108 | }
109 |
110 | export { actions, actionTypes, api, saga, takeEverySaga, takeLatestSaga };
111 |
--------------------------------------------------------------------------------
/src/generated/version/getByOrgkeyAndApplicationkeyAndVersion.js.flow:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import type { Service, Model, Field } from 'generated/version/ServiceType';
4 |
5 | declare export var actionTypes: {
6 | getByOrgkeyAndApplicationkeyAndVersion_get: string,
7 | getByOrgkeyAndApplicationkeyAndVersion_doing: string,
8 | getByOrgkeyAndApplicationkeyAndVersion_success: string,
9 | getByOrgkeyAndApplicationkeyAndVersion_failure: string,
10 | };
11 |
12 | declare type Query = {
13 | orgKey: string,
14 | applicationKey: string,
15 | version?: string
16 | };
17 |
18 | declare type Result = {
19 | type: string,
20 | payload: Query,
21 | error?: boolean
22 | };
23 |
24 | declare export var actions: {
25 | /**
26 | * Retrieve a specific version of an application.
27 | * @param {string} orgKey -
28 | * @param {string} applicationKey -
29 | * @param {string} version - The version of tthis application to download, or the keyword latest to get the latest version
30 | */
31 | getByOrgkeyAndApplicationkeyAndVersion_get: (query: Query) => Result;
32 |
33 | getByOrgkeyAndApplicationkeyAndVersion_doing: () => {type: string};
34 |
35 | getByOrgkeyAndApplicationkeyAndVersion_success: (results: Array) => Result;
36 |
37 | getByOrgkeyAndApplicationkeyAndVersion_failure: (err: Object) => Result;
38 | };
39 |
40 | declare export function api(parmas: Query): Promise<*>;
41 |
--------------------------------------------------------------------------------
/src/generated/version/index.js:
--------------------------------------------------------------------------------
1 | // This file is generated
2 |
3 | import * as getByOrgkeyAndApplicationkeyAndVersion
4 | from 'generated/version/getByOrgkeyAndApplicationkeyAndVersion';
5 |
6 | const actionTypes = Object.assign(
7 | {},
8 | getByOrgkeyAndApplicationkeyAndVersion.actionTypes
9 | );
10 |
11 | const actions = Object.assign(
12 | {},
13 | getByOrgkeyAndApplicationkeyAndVersion.actions
14 | );
15 |
16 | const sagas = {
17 | getByOrgkeyAndApplicationkeyAndVersionTakeEverySaga: getByOrgkeyAndApplicationkeyAndVersion.takeEverySaga,
18 | getByOrgkeyAndApplicationkeyAndVersionLatestSaga: getByOrgkeyAndApplicationkeyAndVersion.takeLatestSaga,
19 | };
20 |
21 | export { actionTypes, actions, sagas };
22 |
--------------------------------------------------------------------------------
/src/home/HomeCard.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import Markdown from 'components/Markdown';
5 | import { onClickHref } from 'utils';
6 |
7 | import styles from 'home/home-card.css';
8 |
9 | const HomeCard = (
10 | {
11 | name,
12 | description,
13 | link,
14 | }: {
15 | name: string,
16 | description?: string,
17 | link: string,
18 | } = {}
19 | ) =>
20 | ;
32 |
33 | export default HomeCard;
34 |
35 | export { styles };
36 |
--------------------------------------------------------------------------------
/src/home/home-card.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | border-radius: var(--border-radius);
5 | cursor: pointer;
6 | }
7 |
8 | .name {
9 | margin: 0;
10 | background: var(--color-concrete);
11 | border-top-left-radius: var(--border-radius);
12 | border-top-right-radius: var(--border-radius);
13 | font-size: 1.75rem;
14 | padding: 0.67rem 1rem;
15 | color: var(--color-cool-blue);
16 | }
17 |
18 | .no-content {
19 | color: var(--color-very-light-gray);
20 | margin: 0;
21 | }
22 |
23 | .description {
24 | border: 2px solid var(--color-concrete);
25 | border-bottom-left-radius: var(--border-radius);
26 | border-bottom-right-radius: var(--border-radius);
27 | padding: 0.67rem 1rem;
28 | }
29 |
--------------------------------------------------------------------------------
/src/home/home.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .main {
4 | display: flex;
5 | }
6 |
7 | .header {
8 | margin: 2rem 0 2rem 0;
9 | background: white;
10 | }
11 |
12 | .content {
13 | padding: 0 3rem;
14 | }
15 |
16 | .container {
17 | margin: 0 0 0.75rem;
18 | }
19 |
20 | .link {
21 | display: block;
22 | text-decoration: none;
23 | color: var(--color-cool-blue);
24 | line-height: 2;
25 | cursor: pointer;
26 |
27 | @nest &:hover {
28 | color: color(var(--color-cool-blue) b(+15%));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/home/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React, { Component } from 'react';
3 | import { bindActionCreators } from 'redux';
4 | import { connect } from 'react-redux';
5 |
6 | import { actions as orgActions } from 'generated/organization';
7 |
8 | import H1 from 'components/H1';
9 | import LoadingOverlay from 'components/LoadingOverlay';
10 | import HomeCard from 'home/HomeCard';
11 |
12 | import styles from 'home/home.css';
13 |
14 | import type { State } from 'app/reducers';
15 | import type { Organization } from 'generated/version/ServiceType';
16 |
17 | const allActions = Object.assign({}, orgActions);
18 |
19 | const Org = ({ organization }: { organization: Organization }) =>
20 | ;
25 |
26 | const Organizations = ({ organizations }: { organizations: Organization[] }) =>
27 |
28 | {organizations.map(organization =>
29 |
30 |
31 |
32 | )}
33 |
;
34 |
35 | type Props = {
36 | loaded: boolean,
37 | actions: Object, // FIXME - types
38 | organizations: Organization[],
39 | };
40 | class Home extends Component {
41 | props: Props;
42 |
43 | // TODO: Can I haz more orgs?
44 | componentDidMount() {
45 | this.props.actions.getOrganizations_get({ limit: 20, offset: 0 });
46 | }
47 |
48 | render() {
49 | return (
50 |
51 |
52 |
53 |
Organizations
54 |
55 |
56 |
57 |
58 |
59 |
60 | );
61 | }
62 | }
63 |
64 | const mapStateToProps = (state: State) => ({ ...state.app });
65 |
66 | const mapDispatchToProps = (dispatch): { [key: string]: Function } => ({
67 | actions: bindActionCreators(allActions, dispatch),
68 | });
69 |
70 | export default connect(mapStateToProps, mapDispatchToProps)(Home);
71 |
72 | export { styles };
73 |
--------------------------------------------------------------------------------
/src/index.html.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= htmlWebpackPlugin.options.title %>
6 |
7 |
8 |
9 |
10 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React from 'react';
4 | import ReactDOM from 'react-dom';
5 | import { Provider } from 'react-redux';
6 | import { Router, browserHistory } from 'react-router';
7 | import { syncHistoryWithStore } from 'react-router-redux';
8 |
9 | import routes from 'routes';
10 | import configureStore from 'store/configureStore';
11 |
12 | // Needed for React Developer Tools
13 | window.React = React;
14 |
15 | const store = configureStore();
16 |
17 | const history = syncHistoryWithStore(browserHistory, store);
18 |
19 | ReactDOM.render(
20 |
21 |
22 | ,
23 | document.getElementById('root')
24 | );
25 |
--------------------------------------------------------------------------------
/src/organization/AppCard.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 |
4 | import Markdown from 'components/Markdown';
5 | import { onClickHref } from 'utils';
6 |
7 | import styles from 'organization/app-card.css';
8 |
9 | const AppCard = (
10 | {
11 | name,
12 | description,
13 | link,
14 | }: {
15 | name: string,
16 | description?: string,
17 | link: string,
18 | } = {}
19 | ) =>
20 | ;
32 |
33 | export default AppCard;
34 |
35 | export { styles };
36 |
--------------------------------------------------------------------------------
/src/organization/app-card.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .container {
4 | border-radius: var(--border-radius);
5 | cursor: pointer;
6 | }
7 |
8 | .name {
9 | margin: 0;
10 | background: var(--color-concrete);
11 | border-top-left-radius: var(--border-radius);
12 | border-top-right-radius: var(--border-radius);
13 | font-size: 1.75rem;
14 | padding: 0.67rem 1rem;
15 | color: var(--color-cool-blue);
16 | }
17 |
18 | .no-content {
19 | color: var(--color-very-light-gray);
20 | margin: 0;
21 | }
22 |
23 | .description {
24 | border: 2px solid var(--color-concrete);
25 | border-bottom-left-radius: var(--border-radius);
26 | border-bottom-right-radius: var(--border-radius);
27 | padding: 0.67rem 1rem;
28 | }
29 |
--------------------------------------------------------------------------------
/src/organization/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React, { Component } from 'react';
3 | import { bindActionCreators } from 'redux';
4 | import { connect } from 'react-redux';
5 |
6 | import H1 from 'components/H1';
7 | import LoadingOverlay from 'components/LoadingOverlay';
8 | import AppCard from 'organization/AppCard';
9 |
10 | import styles from 'organization/organization.css';
11 | import { actions } from 'organization/sagas';
12 |
13 | import type { State } from 'app/reducers';
14 | import type {
15 | Application,
16 | Organization as OrganizationType,
17 | } from 'generated/version/ServiceType';
18 |
19 | const App = ({
20 | orgKey,
21 | application,
22 | }: {
23 | orgKey: string,
24 | application: Application,
25 | }) =>
26 | ;
31 |
32 | // Roll into Org FIXME
33 | const Applications = ({
34 | orgKey,
35 | applications,
36 | }: {
37 | orgKey: string,
38 | applications: Application[],
39 | }) =>
40 |
41 | {applications.map(application =>
42 |
45 | )}
46 |
;
47 |
48 | type Props = {
49 | loaded: boolean,
50 | params: Object, // FIXME
51 | actions: Object, // FIXME
52 | organization?: OrganizationType,
53 | applications: any, // FIXME PropTypes.array.isRequired,
54 | };
55 |
56 | class Organization extends Component {
57 | props: Props;
58 |
59 | componentDidMount() {
60 | const orgKey = this.props.params.organizationKey;
61 | this.props.actions.getOrganizationDetails_get({ orgKey });
62 | }
63 |
64 | render() {
65 | return (
66 |
67 |
68 |
69 |
70 | {this.props.organization && this.props.organization.name}
71 |
72 |
73 |
79 |
80 |
81 | );
82 | }
83 | }
84 |
85 | const mapStateToProps = (state: State) => ({
86 | organization: state.organization.organization,
87 | applications: state.organization.applications,
88 | loaded: state.organization.loaded,
89 | });
90 |
91 | const mapDispatchToProps = dispatch => ({
92 | actions: bindActionCreators(actions, dispatch),
93 | });
94 |
95 | export default connect(mapStateToProps, mapDispatchToProps)(Organization);
96 |
97 | export { styles };
98 |
--------------------------------------------------------------------------------
/src/organization/organization.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .link {
4 | display: block;
5 | text-decoration: none;
6 | color: var(--color-cool-blue);
7 | line-height: 2;
8 | cursor: pointer;
9 |
10 | @nest &:hover {
11 | color: color(var(--color-cool-blue) b(+15%));
12 | }
13 | }
14 |
15 | .header {
16 | margin: 2rem 0 2rem 0;
17 | background: white;
18 | }
19 |
20 | .content {
21 | padding: 0 3rem;
22 | }
23 |
24 | .container {
25 | margin: 0 0 0.75rem;
26 | }
27 |
--------------------------------------------------------------------------------
/src/organization/reducers.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { actionTypes } from 'organization/sagas';
3 |
4 | import type { Application, Organization } from 'generated/version/ServiceType';
5 |
6 | export type OrgState = {
7 | loaded: boolean,
8 | organization?: Organization,
9 | applications: Application[],
10 | };
11 |
12 | export type OrgAction = {
13 | type: string,
14 | payload: {
15 | organization: Organization,
16 | applications: Application[],
17 | },
18 | };
19 |
20 | const initialState = {
21 | loaded: false,
22 | /* organization: {},*/
23 | applications: [],
24 | };
25 |
26 | const organization = (state: OrgState = initialState, action: OrgAction) => {
27 | switch (action.type) {
28 | // Get Applications
29 | case actionTypes.getOrganizationDetails_success: {
30 | return {
31 | loaded: true,
32 | organization: action.payload.organization,
33 | applications: action.payload.applications,
34 | };
35 | }
36 | case actionTypes.getOrganizationDetails_doing: {
37 | return Object.assign(state, {
38 | loaded: false,
39 | });
40 | }
41 | default: {
42 | return state;
43 | }
44 | }
45 | };
46 |
47 | const reducers = {
48 | organization,
49 | };
50 |
51 | export { reducers };
52 |
--------------------------------------------------------------------------------
/src/organization/sagas.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { takeLatest } from 'redux-saga';
3 | import { call, put } from 'redux-saga/effects';
4 |
5 | import { api as appsApi } from 'generated/organization/getOrganizationsByKey';
6 | import { api as orgsApi } from 'generated/application/getByOrgkey';
7 |
8 | const actionTypes = {
9 | getOrganizationDetails_get: 'getOrganizationDetails/get',
10 | getOrganizationDetails_doing: 'getOrganizationDetails/doing',
11 | getOrganizationDetails_success: 'getOrganizationDetails/success',
12 | getOrganizationDetails_failure: 'getOrganizationDetails/failure',
13 | };
14 |
15 | const actions = {
16 | getOrganizationDetails_get: ({ orgKey }: { orgKey?: string } = {}) => ({
17 | type: actionTypes.getOrganizationDetails_get,
18 | payload: { orgKey },
19 | }),
20 | getOrganizationDetails_doing: () => ({
21 | type: actionTypes.getOrganizationDetails_doing,
22 | }),
23 | getOrganizationDetails_success: (result: any) => ({
24 | // FIXME types
25 | type: actionTypes.getOrganizationDetails_success,
26 | payload: result,
27 | }),
28 | getOrganizationDetails_failure: (err: any) => ({
29 | // FIXME types
30 | type: actionTypes.getOrganizationDetails_failure,
31 | payload: err,
32 | error: true,
33 | }),
34 | };
35 |
36 | function* saga(action: any): Generator {
37 | // FIXME types
38 | const { orgKey } = action.payload;
39 | try {
40 | yield put(actions.getOrganizationDetails_doing());
41 | const [appResult, orgResult] = yield [
42 | call(orgsApi, { orgKey }),
43 | call(appsApi, { key: orgKey }),
44 | ];
45 | const organization = orgResult.body;
46 | const applications = appResult.body;
47 |
48 | yield put(
49 | actions.getOrganizationDetails_success({
50 | organization,
51 | applications,
52 | })
53 | );
54 | } catch (error) {
55 | yield put(actions.getOrganizationDetails_failure(error));
56 | }
57 | }
58 |
59 | function* takeLatestSaga(): Generator {
60 | yield* takeLatest(actionTypes.getOrganizationDetails_get, saga);
61 | }
62 |
63 | export { actions, actionTypes, saga, takeLatestSaga };
64 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { IndexRoute, Route } from 'react-router';
4 |
5 | import { App } from 'app';
6 |
7 | import Home from 'home';
8 | import Organization from 'organization';
9 | import { Appln } from 'application';
10 | import Documentation from 'documentation';
11 |
12 | const routes = (
13 |
14 |
15 |
16 |
17 |
21 |
25 |
29 |
30 | );
31 |
32 | export default routes;
33 |
--------------------------------------------------------------------------------
/src/store/configureStore.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { createStore, applyMiddleware, compose } from 'redux';
3 | import createSagaMiddleware from 'redux-saga';
4 | import rootReducer from 'app/rootReducer';
5 | import allSagas from 'app/allSagas';
6 |
7 | // for flowtype of module
8 | /* declare var module : {
9 | * hot : {
10 | * accept(path:string, callback:() => void): void;
11 | * };
12 | * };
13 | * */
14 | const configureStore = () => {
15 | const sagaMiddleware = createSagaMiddleware();
16 | const store = createStore(
17 | rootReducer,
18 | compose(
19 | applyMiddleware(sagaMiddleware),
20 | window.devToolsExtension ? window.devToolsExtension() : f => f
21 | )
22 | );
23 |
24 | if (module.hot) {
25 | // Enable Webpack hot module replacement for reducers
26 | module.hot.accept('../app/rootReducer', () => {
27 | const nextReducer = rootReducer;
28 | store.replaceReducer(nextReducer);
29 | });
30 | }
31 |
32 | // Run Sagas - needs to be done after the middleware is added to the store
33 | allSagas.map(_ => sagaMiddleware.run(_));
34 |
35 | return store;
36 | };
37 |
38 | export default configureStore;
39 |
--------------------------------------------------------------------------------
/src/styles/global.css:
--------------------------------------------------------------------------------
1 | /* Sensible defaults */
2 |
3 | html {
4 | font-size: 14px;
5 | margin: 0;
6 | padding: 0;
7 | box-sizing: border-box;
8 | border-collapse: collapse;
9 | }
10 |
11 | * {
12 | border-collapse: inherit;
13 | }
14 |
15 | *,
16 | *::before,
17 | *::after {
18 | box-sizing: inherit;
19 | }
20 |
21 | body {
22 | margin: 0;
23 | padding: 0;
24 | }
25 |
--------------------------------------------------------------------------------
/src/styles/typography.css:
--------------------------------------------------------------------------------
1 | @import "variables.css";
2 |
3 | .h1 {
4 | font-family: var(--font-primary);
5 | font-weight: 400;
6 | font-size: 3.157rem;
7 | line-height: 1.2;
8 | margin: 0;
9 | padding: 0;
10 | }
11 |
12 | .h2 {
13 | font-family: var(--font-secondary);
14 | font-size: 2.369rem;
15 | line-height: 1.2;
16 | margin: 0;
17 | padding: 0;
18 | }
19 |
20 | .h3 {
21 | font-family: var(--font-primary);
22 | font-size: 1.777rem;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 | .p {
30 | font-family: var(--font-primary);
31 | line-height: 1.2;
32 | font-size: 1rem;
33 | color: var(--color-tuatara);
34 | }
35 |
--------------------------------------------------------------------------------
/src/styles/variables.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Top level variables
3 | */
4 |
5 | :root {
6 | --color-concrete: #F3F3F3;
7 | --color-very-light-gray: #CECECE;
8 | --color-light-gray: #AAA;
9 | --color-aluminium: #9B9B9B;
10 | --color-monsoon: #777;
11 | --color-steel: #666;
12 | --color-armadillo: #494949;
13 | --color-montana: #3A3A3A;
14 | --color-tuatara: #343434;
15 | --color-dark: #222;
16 |
17 | --color-solitude: #E8F4FF;
18 | --color-hawkes-blue: #D1EAFE;
19 | --color-sail: #BAE0FD;
20 | --color-colombia-blue: #9BD5FD;
21 | --color-light-sky-blue: #82CAFC;
22 | --color-maya-blue: #5DBBFB;
23 | --color-dodger-blue: #2BA6FA;
24 | --color-cool-blue: #0696F9;
25 | --color-rich-electric-blue: #0688E1;
26 | --color-lochmara: #0578C8;
27 | --color-medium-persian-blue: #056AAF;
28 | --color-bahama-blue: #045A96;
29 | --color-dark-cerulean: #044C7D;
30 | --color-astronaut-blue: #033C64;
31 | --color-blue-whale: #022E4C;
32 | --color-midnight: #021E32;
33 |
34 | --color-red: #E74C3C;
35 |
36 | --color-method-get: #27AE60;
37 | --color-method-post: #F39C12;
38 | --color-method-put: #8E44AD;
39 | --color-method-delete: #E74C3C;
40 |
41 | --color-primary: var(--color-cool-blue);
42 | --color-primary-light: var(--color-maya-blue);
43 | --color-primary-dark: var(--color-lochmara);
44 | --color-secondary: #27DBCF;
45 | --color-secondary-light: #98ECE6;
46 | --color-secondary-dark: #1FAFA6;
47 |
48 | --color-alert: var(--color-red);
49 | --border-radius: 3px;
50 | --font-avenir: avenir, helvetica, arial, sans-serif;
51 | --font-open-sans: 'Open Sans', sans-serif;
52 | --font-brandon: "Brandon grotesque";
53 | --font-lato: 'Lato', sans-serif;
54 | --font-mono: 'Droid Sans Mono', monospace;
55 |
56 | --font-primary: var(--font-open-sans);
57 | --font-secondary: var(--font-lato);
58 | --font-code: var(--font-mono);
59 | }
60 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | function buildConfig(env) {
2 | return require(`./config/webpack.${env ? env : 'dev'}.js`)({ env });
3 | }
4 |
5 | module.exports = buildConfig;
6 |
--------------------------------------------------------------------------------