Skip to content

Commit

Permalink
Revert "Init project"
Browse files Browse the repository at this point in the history
This reverts commit 23f9648.
  • Loading branch information
alexeybondarenko committed Apr 7, 2018
1 parent 23f9648 commit b02e41c
Show file tree
Hide file tree
Showing 178 changed files with 14,287 additions and 207 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"root": ["./app/common"],
"alias": {
"tests": "./tests",
"withStyles": "isomorphic-style-loader/lib/withStyles",
"withStyles": "nebo15-isomorphic-style-loader/lib/withStyles",
"public": "./public"
}
}
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ script:
- sleep 5
- docker ps
- RUNNING_CONTAINERS=`docker ps | wc -l`; if [ "${RUNNING_CONTAINERS//[[:space:]]/}"
== "1" ]; then echo "[E] Container is not started\!"; docker logs cryptograph --details
== "1" ]; then echo "[E] Container is not started\!"; docker logs man.web --details
--since 5h; exit 1; fi;
- npm run nightwatch -- -e travis
- sleep 5
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Front.band
Copyright (c) 2017 Nebo #15

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,48 @@
# Cryptograph
# Mán Dashboard

[![Greenkeeper badge](https://badges.greenkeeper.io/Nebo15/man.web.svg)](https://greenkeeper.io/)
[![Build Status](https://travis-ci.org/Nebo15/man.web.svg?branch=master)](https://travis-ci.org/Nebo15/man.web)

[![Build history](https://buildstats.info/travisci/chart/Nebo15/man.web)](https://travis-ci.org/Nebo15/man.web)

![Man Logo](https://github.com/Nebo15/man.api/raw/master/docs/images/logo.png)

Mán stores templates (in `iex`, `mustache`) or `markdown` documents, renders it over HTTP API with dispatch in PDF, JSON or HTML formats.

> "Mán" translates from the Sindarin as "Spirit". Sindarin is one of the many languages spoken by the immortal Elves.
API: https://github.com/Nebo15/man.api

## Demo

![UI Demo](https://github.com/Nebo15/man.web/raw/master/docs/images/ui-animated.gif)

Try it here: http://man-web.herokuapp.com/

## Installation

### Heroku One-Click Deployment

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/nebo15/man.web)

### Docker

Dashboard can be deployed as a single container from [nebo15/man.web](https://hub.docker.com/r/nebo15/man.web/) Docker Hub.

## Configurations

Application supports these environment variables:

| Environment Variable | Default Value | Description |
| --------------------- | ----------------------- | ----------- |
| `PORT` | `8080` | Node.js server port. |
| `API_ENDPOINT` | `https://man-api.herokuapp.com` | Mán API endpoint. |
| `SITEMAP_HOSTNAME` | `http://localhost:8080` | URL will be used in sitemap generated urls |
| `LANG_COOKIE_NAME` | `lang` | Name of the cookie, where storing language variable |

## Docs

Dashboard works on top of [Man management API](http://docs.man2.apiary.io).

## Technologies

Expand Down
40 changes: 40 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "man.web",
"logo": "https://raw.githubusercontent.com/Nebo15/man.web/master/assets/images/logo.png",
"scripts": {
},
"env": {
"PREBUILD": {
"description": "RUN postinstall script. MUST be `true`",
"required": true,
"value": "true"
},
"API_ENDPOINT": {
"description": "Mán API host",
"required": true,
"value": "https://man-api.herokuapp.com"
},
"SITEMAP_HOSTNAME": {
"description": "SITEMAP_HOSTNAME will be used as hostname in sitemap URLs",
"required": false,
"value": ""
},
"LANG_COOKIE_NAME": {
"description": "Name of the cookie, where storing language variable",
"value": "lang"
}
},
"formation": {
"web": {
"quantity": 1
}
},
"addons": [

],
"buildpacks": [
{
"url": "heroku/nodejs"
}
]
}
6 changes: 6 additions & 0 deletions app/client/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom';

import 'codemirror/addon/display/placeholder';
import 'codemirror/mode/handlebars/handlebars';
import 'codemirror/mode/xml/xml';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/mode/javascript/javascript';

import { AppContainer } from 'react-hot-loader';

import CookieDough from 'cookie-dough';
Expand Down
65 changes: 31 additions & 34 deletions app/client/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useRedial } from 'react-router-redial';
import { I18nextProvider } from 'react-i18next';

import { showLoading, hideLoading } from 'redux/loading';
import WithStylesContext from 'WithStylesContext';

const trackPage = (route) => {}; // eslint-disable-line

Expand Down Expand Up @@ -37,39 +36,37 @@ export default class RootComponent extends React.Component {
return (
<I18nextProvider i18n={i18n}>
<Provider store={store}>
<WithStylesContext onInsertCss={() => {}}>
<Router
{...renderProps}
history={history}
routes={routes}
render={applyRouterMiddleware(
useRedial({
locals,
beforeTransition: ['fetch'],
afterTransition: ['defer', 'done'],
parallel: true,
initialLoading: process.env.NODE_ENV === 'production' ? null : (() => <div>Loading...</div>),
onStarted: () => {
store.dispatch(showLoading());
},
onCompleted: (transition) => {
store.dispatch([
hideLoading(),
]);
if (transition === 'beforeTransition') {
window.scrollTo(0, 0);
}
},
onAborted: () => {
store.dispatch(hideLoading());
},
onError: () => {
store.dispatch(hideLoading());
},
})
)}
/>
</WithStylesContext>
<Router
{...renderProps}
history={history}
routes={routes}
render={applyRouterMiddleware(
useRedial({
locals,
beforeTransition: ['fetch'],
afterTransition: ['defer', 'done'],
parallel: true,
initialLoading: process.env.NODE_ENV === 'production' ? null : (() => <div>Loading...</div>),
onStarted: () => {
store.dispatch(showLoading());
},
onCompleted: (transition) => {
store.dispatch([
hideLoading(),
]);
if (transition === 'beforeTransition') {
window.scrollTo(0, 0);
}
},
onAborted: () => {
store.dispatch(hideLoading());
},
onError: () => {
store.dispatch(hideLoading());
},
})
)}
/>
</Provider>
</I18nextProvider>
);
Expand Down
3 changes: 1 addition & 2 deletions app/common/WithStylesContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

import { Component, Children } from 'react';
import PropTypes from 'prop-types';
import { Component, PropTypes, Children } from 'react';

export default class WithStylesContext extends Component {
static propTypes = {
Expand Down
87 changes: 87 additions & 0 deletions app/common/components/Button/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { Link } from 'react-router';
import classnames from 'classnames';
import withStyles from 'nebo15-isomorphic-style-loader/lib/withStyles';

import Icon, { icons } from 'components/Icon';

import styles from './styles.scss';

const URL_TEST_REG_EXP = /^((?:[a-z]+:)?\/\/)|mailto:/i;

const Button = (props) => {
const {
theme = 'fill',
size = 'middle',
color = 'orange',
active = false,
disabled = false,
block = false,
inheritColor = false,
type = 'button',
to, children, onClick, id, icon, name,
} = props;

const className = classnames(
styles.button,
styles[`theme-${theme}`],
styles[`color-${color}`],
styles[`size-${size}`],
active && styles.active,
disabled && styles.disabled,
block && styles.block,
inheritColor && styles['inherit-color'],
);

const content = (
<div>
{icon && <span className={styles.icon}><Icon name={icon} /></span>}
{children}
</div>
);

if (to === undefined) {
return (
<button name={name} id={id} onClick={onClick} type={type} className={className}>
{content}
</button>
);
}
if (URL_TEST_REG_EXP.test(to)) {
return (
<a id={id} href={to} onClick={onClick} className={className}>
{content}
</a>
);
}

return (
<Link id={id} to={to} onClick={onClick} className={className}>{content}</Link>
);
};

Button.propTypes = {
theme: React.PropTypes.oneOf(['fill', 'border', 'link']),
size: React.PropTypes.oneOf(['small', 'middle']),
color: React.PropTypes.oneOf(['orange', 'blue', 'green', 'red']),
type: React.PropTypes.string,
active: React.PropTypes.bool,
disabled: React.PropTypes.bool,
block: React.PropTypes.bool,
inheritColor: React.PropTypes.bool,
to: React.PropTypes.string,
id: React.PropTypes.string,
icon: React.PropTypes.oneOf(icons),
onClick: React.PropTypes.func,
};

export default withStyles(styles)(Button);
export const ButtonsGroup = withStyles(styles)(
({ children, ...props }) => (<div {...props} className={styles.buttonsGroup}>
{
React.Children.toArray(children).map((i, key) =>
<div className={styles.buttonsGroupItem} key={key}>{i}</div>
)
}
</div>)
);
87 changes: 87 additions & 0 deletions app/common/components/Button/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import chai, { expect } from 'chai';
import { shallow, mount } from 'enzyme';
import spies from 'chai-spies';

import Button from './index';
import styles from './styles.scss';

chai.use(spies);

describe('Button', () => {
it('children', () => {
const elem = shallow(<Button><span>My button</span></Button>);
expect(elem.contains(<span>My button</span>)).to.equal(true);
});

describe('props', () => {
const elem = shallow(<Button theme="border" size="small" color="blue" active disabled />);

it('theme', () => {
expect(elem.render().find(`button.${styles['theme-border']}`)).to.have.length(1);
});

it('size', () => {
expect(elem.render().find(`button.${styles['size-small']}`)).to.have.length(1);
});

it('color', () => {
expect(elem.render().find(`button.${styles['color-blue']}`)).to.have.length(1);
});

it('disabled', () => {
expect(elem.render().find(`button.${styles.disabled}`)).to.have.length(1);
});

it('active', () => {
expect(elem.render().find(`button.${styles.active}`)).to.have.length(1);
});

it('icon', () => {
const elem = mount(<Button icon="plus" />);
expect(elem.find('Icon').props().name).to.equal('plus');
});

describe('type', () => {
it('should be button by default', () => {
const wrapper = mount(<Button />);
expect(wrapper.find('button').prop('type')).to.equal('button');
});
it('should be passed to button', () => {
const wrapperType = mount(<Button type="test" />);
expect(wrapperType.find('button').prop('type')).to.equal('test');
});
});

describe('onClick', () => {
let handleClick;
beforeEach(() => {
handleClick = chai.spy(() => {});
});

it('should work', () => {
const elem = shallow(<Button onClick={handleClick} />);
elem.simulate('click');
expect(handleClick).to.have.been.called.once;
});

it('should not be called if button disabled', () => {
const elem = shallow(<Button disabled onClick={handleClick} />);
elem.simulate('click');
expect(handleClick).to.have.not.been.called;
});
});

describe('to', () => {
it('should work inner link', () => {
const elem = mount(<Button to="/" />);
expect(elem.find('Link')).to.have.length(1);
});

it('should work outer link', () => {
const elem = shallow(<Button to="http://google.com" />);
expect(elem.render().find('a[href="http://google.com"]')).to.have.length(1);
});
});
});
});
Loading

0 comments on commit b02e41c

Please sign in to comment.