Fix prettier integration, format (#31)

* Fix prettier integration, format

* Reformat again
This commit is contained in:
Tom Moor 2017-04-27 21:48:13 -07:00 committed by GitHub
parent 51fade7439
commit 2095b3a874
74 changed files with 823 additions and 808 deletions

View File

@ -1,23 +1,16 @@
{
"extends": [
"airbnb",
"prettier",
"prettier/react"
],
"parser": "babel-eslint",
"extends": ["react-app", "plugin:import/errors", "plugin:import/warnings"],
"plugins": [
"prettier"
],
"rules": {
"arrow-body-style":[0, "as-needed"], // fix `this` shortcut on ES6 classes
"react/jsx-no-bind": 0, // Makes difficult to pass args to prop functions
"react/jsx-curly-spacing": [2, "always", {"spacing": {
"objectLiterals": "never"
}}], // Spaces inside curlies, except prop={{}}
"react/prefer-stateless-function": 0, // Don't prefer stateless components
"no-else-return": 0,
"new-cap": 0,
"no-param-reassign": 0,
no-unused-vars: ["error", {
"argsIgnorePattern": "^_",
}],
"import/order": "warn",
// Prettier automatically uses the least amount of parens possible, so this
// does more harm than good.
"no-mixed-operators": "off",
// Enforce that code is formatted with prettier.
"prettier/prettier": ["error", {"trailingComma": "es5", "singleQuote": true}]
},
"settings" : {
"import/resolver": {
@ -34,7 +27,6 @@
SLACK_KEY: true,
SLACK_REDIRECT_URI: true,
DEPLOYMENT: true,
afterAll: true
},
}

View File

@ -1,9 +1,8 @@
import React, { PropTypes } from 'react';
import { Flex } from 'reflexbox';
import styles from './Alert.scss';
import classNames from 'classnames/bind';
import styles from './Alert.scss';
const cx = classNames.bind(styles);
class Alert extends React.Component {
@ -12,9 +11,8 @@ class Alert extends React.Component {
danger: PropTypes.bool,
warning: PropTypes.bool,
success: PropTypes.bool,
info: PropTypes.bool,
offline: PropTypes.bool,
}
};
render() {
let alertType;
@ -25,8 +23,12 @@ class Alert extends React.Component {
if (!alertType) alertType = 'info'; // default
return (
<Flex align="center" justify="center" className={ cx(styles.container, styles[alertType]) }>
{ this.props.children }
<Flex
align="center"
justify="center"
className={cx(styles.container, styles[alertType])}
>
{this.props.children}
</Flex>
);
}

View File

@ -8,29 +8,29 @@ import styles from './AtlasPreview.scss';
// import classNames from 'classnames/bind';
// const cx = classNames.bind(styles);
@observer
class AtlasPreview extends React.Component {
@observer class AtlasPreview extends React.Component {
static propTypes = {
data: React.PropTypes.object.isRequired,
}
};
render() {
const data = this.props.data;
return (
<div className={ styles.container }>
<h2><Link to={ data.url } className={ styles.atlasLink }>{ data.name }</Link></h2>
{ data.recentDocuments.length > 0 ?
data.recentDocuments.map(document => {
return (
<DocumentLink document={ document } key={ document.id } />
);
})
: (
<div className={ styles.description }>
No documents. Why not <Link to={ `${data.url}/new` }>create one</Link>?
</div>
) }
<div className={styles.container}>
<h2>
<Link to={data.url} className={styles.atlasLink}>{data.name}</Link>
</h2>
{data.recentDocuments.length > 0
? data.recentDocuments.map(document => {
return <DocumentLink document={document} key={document.id} />;
})
: <div className={styles.description}>
No documents. Why not
{' '}
<Link to={`${data.url}/new`}>create one</Link>
?
</div>}
</div>
);
}

View File

@ -1,16 +1,18 @@
import React from 'react';
import { observer } from "mobx-react"
import { observer } from 'mobx-react';
import moment from 'moment';
import Link from 'react-router/lib/Link';
import styles from './DocumentLink.scss';
const DocumentLink = observer((props) => {
const DocumentLink = observer(props => {
return (
<Link to={ props.document.url } className={ styles.link }>
<h3 className={ styles.title }>{ props.document.title }</h3>
<span className={ styles.timestamp }>{ moment(props.document.updatedAt).fromNow() }</span>
<Link to={props.document.url} className={styles.link}>
<h3 className={styles.title}>{props.document.title}</h3>
<span className={styles.timestamp}>
{moment(props.document.updatedAt).fromNow()}
</span>
</Link>
);
});

View File

@ -1,2 +1,2 @@
import DocumentLink from './DocumentLink';
export default DocumentLink;
export default DocumentLink;

View File

@ -1,2 +1,2 @@
import AtlasPreview from './AtlasPreview';
export default AtlasPreview;
export default AtlasPreview;

View File

@ -7,37 +7,40 @@ const cx = classNames.bind(styles);
import { randomInteger } from 'utils/random';
const randomValues = Array.from(new Array(5), () => `${randomInteger(85, 100)}%`);
const randomValues = Array.from(
new Array(5),
() => `${randomInteger(85, 100)}%`
);
export default (_props) => {
export default _props => {
return (
<ReactCSSTransitionGroup
transitionName="fadeIn"
transitionAppear
transitionEnter
transitionLeave
transitionAppearTimeout={ 0 }
transitionEnterTimeout={ 0 }
transitionLeaveTimeout={ 0 }
transitionAppearTimeout={0}
transitionEnterTimeout={0}
transitionLeaveTimeout={0}
>
<div>
<div className={ cx(styles.container, styles.animated) }>
<div className={cx(styles.container, styles.animated)}>
<div
className={ cx(styles.mask, styles.header) }
className={cx(styles.mask, styles.header)}
style={{ width: randomValues[0] }}
>&nbsp;</div>
/>
<div
className={ cx(styles.mask, styles.bodyText) }
className={cx(styles.mask, styles.bodyText)}
style={{ width: randomValues[1] }}
>&nbsp;</div>
/>
<div
className={ cx(styles.mask, styles.bodyText) }
className={cx(styles.mask, styles.bodyText)}
style={{ width: randomValues[2] }}
>&nbsp;</div>
/>
<div
className={ cx(styles.mask, styles.bodyText) }
className={cx(styles.mask, styles.bodyText)}
style={{ width: randomValues[3] }}
>&nbsp;</div>
/>
</div>
</div>
</ReactCSSTransitionGroup>

View File

@ -1,2 +1,2 @@
import AtlasPreviewLoading from './AtlasPreviewLoading';
export default AtlasPreviewLoading;
export default AtlasPreviewLoading;

View File

@ -1,2 +1,2 @@
import Button from './Button';
export default Button;
export default Button;

View File

@ -2,15 +2,15 @@ import React from 'react';
import styles from './CenteredContent.scss';
const CenteredContent = (props) => {
const CenteredContent = props => {
const style = {
maxWidth: props.maxWidth,
...props.style,
};
return (
<div className={ styles.content } style={ style }>
{ props.children }
<div className={styles.content} style={style}>
{props.children}
</div>
);
};
@ -24,4 +24,4 @@ CenteredContent.propTypes = {
style: React.PropTypes.object,
};
export default CenteredContent;
export default CenteredContent;

View File

@ -1,2 +1,2 @@
import CenteredContent from './CenteredContent';
export default CenteredContent;
export default CenteredContent;

View File

@ -2,10 +2,8 @@ import React from 'react';
import styles from './Divider.scss';
const Divider = (props) => {
return(
<div className={ styles.divider }><span></span></div>
);
const Divider = props => {
return <div className={styles.divider}><span /></div>;
};
export default Divider;
export default Divider;

View File

@ -1,2 +1,2 @@
import Divider from './Divider';
export default Divider;
export default Divider;

View File

@ -7,23 +7,22 @@ import DocumentHtml from './components/DocumentHtml';
import styles from './Document.scss';
@observer
class Document extends React.Component {
@observer class Document extends React.Component {
static propTypes = {
document: PropTypes.object.isRequired,
}
};
render() {
return (
<div className={ styles.container }>
<div className={styles.container}>
<PublishingInfo
createdAt={ this.props.document.createdAt }
createdBy={ this.props.document.createdBy }
updatedAt={ this.props.document.updatedAt }
updatedBy={ this.props.document.updatedBy }
collaborators={ toJS(this.props.document.collaborators) }
createdAt={this.props.document.createdAt}
createdBy={this.props.document.createdBy}
updatedAt={this.props.document.updatedAt}
updatedBy={this.props.document.updatedBy}
collaborators={toJS(this.props.document.collaborators)}
/>
<DocumentHtml html={ this.props.document.html } />
<DocumentHtml html={this.props.document.html} />
</div>
);
}

View File

@ -4,19 +4,18 @@ import { observer } from 'mobx-react';
import styles from './DocumentHtml.scss';
@observer
class DocumentHtml extends React.Component {
@observer class DocumentHtml extends React.Component {
static propTypes = {
html: PropTypes.string.isRequired,
}
};
componentDidMount = () => {
this.setExternalLinks();
}
};
componentDidUpdate = () => {
this.setExternalLinks();
}
};
setExternalLinks = () => {
const links = ReactDOM.findDOMNode(this).querySelectorAll('a');
@ -25,12 +24,12 @@ class DocumentHtml extends React.Component {
link.target = '_blank'; // eslint-disable-line no-param-reassign
}
});
}
};
render() {
return (
<div
className={ styles.document }
className={styles.document}
dangerouslySetInnerHTML={{ __html: this.props.html }}
/>
);

View File

@ -2,6 +2,4 @@ import Document from './Document';
import DocumentHtml from './components/DocumentHtml';
export default Document;
export {
DocumentHtml,
};
export { DocumentHtml };

View File

@ -8,22 +8,23 @@ import styles from './DocumentList.scss';
class DocumentList extends React.Component {
static propTypes = {
documents: React.PropTypes.arrayOf(React.PropTypes.object),
}
};
render() {
return (
<div>
{ this.props.documents && this.props.documents.map((document) => {
return (
<div>
<DocumentPreview document={ document } />
<Divider />
</div>
);
}) }
{this.props.documents &&
this.props.documents.map(document => {
return (
<div>
<DocumentPreview document={document} />
<Divider />
</div>
);
})}
</div>
);
}
};
}
export default DocumentList;
export default DocumentList;

View File

@ -1,2 +1,2 @@
import DocumentList from './DocumentList';
export default DocumentList;
export default DocumentList;

View File

@ -10,33 +10,29 @@ import styles from './DocumentPreview.scss';
class Document extends React.Component {
static propTypes = {
document: React.PropTypes.object.isRequired,
}
};
render() {
return (
<div className={ styles.container }>
<div className={styles.container}>
<PublishingInfo
createdAt={ this.props.document.createdAt }
createdBy={ this.props.document.createdBy }
updatedAt={ this.props.document.updatedAt }
updatedBy={ this.props.document.updatedBy }
collaborators={ toJS(this.props.document.collaborators) }
createdAt={this.props.document.createdAt}
createdBy={this.props.document.createdBy}
updatedAt={this.props.document.updatedAt}
updatedBy={this.props.document.updatedBy}
collaborators={toJS(this.props.document.collaborators)}
/>
<Link
to={ this.props.document.url }
className={ styles.title }
>
<h2>{ this.props.document.title }</h2>
<Link to={this.props.document.url} className={styles.title}>
<h2>{this.props.document.title}</h2>
</Link>
<div dangerouslySetInnerHTML={{ __html: this.props.document.preview }} />
<div
dangerouslySetInnerHTML={{ __html: this.props.document.preview }}
/>
<div>
<Link
to={ this.props.document.url }
className={ styles.continueLink }
>
<Link to={this.props.document.url} className={styles.continueLink}>
Continue reading...
</Link>
</div>

View File

@ -1,2 +1,2 @@
import DocumentPreview from './DocumentPreview';
export default DocumentPreview;
export default DocumentPreview;

View File

@ -10,14 +10,13 @@ class MenuItem extends React.Component {
} else {
this.props.onClick();
}
}
};
render() {
return (
<div
className={ styles.menuItem }
onClick={ this.onClick }
>{ this.props.children }</div>
<div className={styles.menuItem} onClick={this.onClick}>
{this.props.children}
</div>
);
}
}
@ -34,46 +33,44 @@ class DropdownMenu extends React.Component {
static propTypes = {
label: React.PropTypes.node.isRequired,
children: React.PropTypes.node.isRequired,
}
};
state = {
menuVisible: false,
}
};
onMouseEnter = () => {
this.setState({ menuVisible: true });
}
};
onMouseLeave = () => {
this.setState({ menuVisible: false });
}
};
onClick = () => {
this.setState({ menuVisible: !this.state.menuVisible });
}
};
render() {
return (
<div
className={ styles.menuContainer }
onMouseEnter={ this.onMouseEnter }
onMouseLeave={ this.onMouseLeave }
className={styles.menuContainer}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
>
<div className={ styles.label } onClick={ this.onClick }>
{ this.props.label }
<div className={styles.label} onClick={this.onClick}>
{this.props.label}
</div>
{ this.state.menuVisible ? (
<div className={ styles.menu }>
{ this.props.children }
</div>
) : null }
{this.state.menuVisible
? <div className={styles.menu}>
{this.props.children}
</div>
: null}
</div>
);
}
};
}
export default DropdownMenu;
export {
MenuItem,
}
export { MenuItem };

View File

@ -2,13 +2,8 @@ import React from 'react';
import styles from './MoreIcon.scss';
const MoreIcon = (props) => {
return (
<img
src={ require("./assets/more.svg") }
className={ styles.icon }
/>
);
const MoreIcon = props => {
return <img src={require('./assets/more.svg')} className={styles.icon} />;
};
export default MoreIcon;

View File

@ -1,7 +1,4 @@
import DropdownMenu, { MenuItem } from './DropdownMenu';
import MoreIcon from './components/MoreIcon';
export default DropdownMenu;
export {
MenuItem,
MoreIcon,
};
export { MenuItem, MoreIcon };

View File

@ -5,10 +5,10 @@ export default ({ style = {}, className }) => {
<span className={className}>
<svg
xmlns="http://www.w3.org/2000/svg"
width={ style.width || 208 }
height={ style.height || 128 }
width={style.width || 208}
height={style.height || 128}
viewBox="0 0 208 128"
color={ style.color }
color={style.color}
>
<rect
width="198"

View File

@ -2,12 +2,11 @@ import React from 'react';
import styles from './HeaderAction.scss';
const HeaderAction = (props) => {
const HeaderAction = props => {
return (
<div
onClick={ props.onClick }
className={ styles.container }
>{ props.children }</div>
<div onClick={props.onClick} className={styles.container}>
{props.children}
</div>
);
};
@ -15,4 +14,4 @@ HeaderAction.propTypes = {
onClick: React.PropTypes.func,
};
export default HeaderAction;
export default HeaderAction;

View File

@ -1,2 +1,2 @@
import HeaderAction from './HeaderAction';
export default HeaderAction;
export default HeaderAction;

View File

@ -1,20 +1,19 @@
import React from 'react';
import { observer } from 'mobx-react';
@observer
class SaveAction extends React.Component {
@observer class SaveAction extends React.Component {
static propTypes = {
onClick: React.PropTypes.func.isRequired,
disabled: React.PropTypes.bool,
isNew: React.PropTypes.bool,
}
};
onClick = (event) => {
onClick = event => {
if (this.props.disabled) return;
event.preventDefault();
this.props.onClick();
}
};
render() {
const { disabled, isNew } = this.props;
@ -23,11 +22,11 @@ class SaveAction extends React.Component {
<div>
<a
href
onClick={ this.onClick }
onClick={this.onClick}
style={{ opacity: disabled ? 0.5 : 1 }}
title="Save changes (Cmd+Enter)"
>
{ isNew ? 'Publish' : 'Save' }
{isNew ? 'Publish' : 'Save'}
</a>
</div>
);

View File

@ -10,7 +10,7 @@ class Title extends React.Component {
children: React.PropTypes.string,
truncate: React.PropTypes.number,
placeholder: React.PropTypes.string,
}
};
render() {
let title;
@ -28,12 +28,12 @@ class Title extends React.Component {
return (
<span>
{ title && (<span>&nbsp;/&nbsp;</span>) }
{title && <span>&nbsp;/&nbsp;</span>}
<span
title={ this.props.children }
className={ cx(styles.title, { untitled: usePlaceholder }) }
title={this.props.children}
className={cx(styles.title, { untitled: usePlaceholder })}
>
{ title }
{title}
</span>
</span>
);

View File

@ -5,8 +5,4 @@ import SaveAction from './components/SaveAction';
export default Layout;
export {
Title,
HeaderAction,
SaveAction,
};
export { Title, HeaderAction, SaveAction };

View File

@ -2,12 +2,12 @@ import React from 'react';
import styles from './LoadingIndicator.scss';
const LoadingIndicator = (props) => {
const LoadingIndicator = props => {
return (
<div className={ styles.loading }>
<div className={ styles.loader }></div>
<div className={styles.loading}>
<div className={styles.loader} />
</div>
);
};
export default LoadingIndicator;
export default LoadingIndicator;

View File

@ -14,8 +14,7 @@ import './codemirror.scss';
import { client } from 'utils/ApiClient';
@observer
class MarkdownEditor extends React.Component {
@observer class MarkdownEditor extends React.Component {
static propTypes = {
text: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired,
@ -27,15 +26,15 @@ class MarkdownEditor extends React.Component {
// re-render to help with CodeMirror focus issues
preview: React.PropTypes.bool,
toggleUploadingIndicator: React.PropTypes.func,
}
};
onChange = (newText) => {
onChange = newText => {
if (newText !== this.props.text) {
this.props.onChange(newText);
}
}
};
onDropAccepted = (files) => {
onDropAccepted = files => {
const file = files[0];
const editor = this.getEditorInstance();
@ -56,67 +55,68 @@ class MarkdownEditor extends React.Component {
}
editor.setCursor(newCursorPositionLine, 0);
client.post('/user.s3Upload', {
kind: file.type,
size: file.size,
filename: file.name,
})
.then(response => {
const data = response.data;
// Upload using FormData API
const formData = new FormData();
for (const key in data.form) {
formData.append(key, data.form[key]);
}
if (file.blob) {
formData.append('file', file.file);
} else {
formData.append('file', file);
}
fetch(data.uploadUrl, {
method: 'post',
body: formData,
client
.post('/user.s3Upload', {
kind: file.type,
size: file.size,
filename: file.name,
})
.then(_s3Response => {
this.props.toggleUploadingIndicator();
this.props.replaceText({
original: pendingUploadTag,
new: `![${file.name}](${data.asset.url})`,
});
editor.setCursor(newCursorPositionLine, 0);
.then(response => {
const data = response.data;
// Upload using FormData API
const formData = new FormData();
for (const key in data.form) {
formData.append(key, data.form[key]);
}
if (file.blob) {
formData.append('file', file.file);
} else {
formData.append('file', file);
}
fetch(data.uploadUrl, {
method: 'post',
body: formData,
})
.then(_s3Response => {
this.props.toggleUploadingIndicator();
this.props.replaceText({
original: pendingUploadTag,
new: `![${file.name}](${data.asset.url})`,
});
editor.setCursor(newCursorPositionLine, 0);
})
.catch(_err => {
this.props.toggleUploadingIndicator();
this.props.replaceText({
original: pendingUploadTag,
new: '',
});
editor.setCursor(newCursorPositionLine, 0);
});
})
.catch(_err => {
this.props.toggleUploadingIndicator();
this.props.replaceText({
original: pendingUploadTag,
new: '',
});
editor.setCursor(newCursorPositionLine, 0);
});
})
.catch(_err => {
this.props.toggleUploadingIndicator();
});
}
};
onPaddingTopClick = () => {
const cm = this.getEditorInstance();
cm.setCursor(0, 0);
cm.focus();
}
};
onPaddingBottomClick = () => {
const cm = this.getEditorInstance();
cm.setCursor(cm.lineCount(), 0);
cm.focus();
}
};
getEditorInstance = () => {
return this.refs.editor.getCodeMirror();
}
};
render = () => {
const options = {
@ -146,24 +146,24 @@ class MarkdownEditor extends React.Component {
return (
<Dropzone
onDropAccepted={ this.onDropAccepted }
onDropAccepted={this.onDropAccepted}
disableClick
multiple={ false }
multiple={false}
accept="image/*"
className={ styles.container }
className={styles.container}
>
<ClickablePadding onClick={ this.onPaddingTopClick } />
<ClickablePadding onClick={this.onPaddingTopClick} />
<Codemirror
value={ this.props.text }
onChange={ this.onChange }
options={ options }
value={this.props.text}
onChange={this.onChange}
options={options}
ref="editor"
className={ styles.codeMirrorContainer }
className={styles.codeMirrorContainer}
/>
<ClickablePadding onClick={ this.onPaddingBottomClick } />
<ClickablePadding onClick={this.onPaddingBottomClick} />
</Dropzone>
);
}
};
}
export default MarkdownEditor;

View File

@ -2,17 +2,12 @@ import React from 'react';
import styles from './ClickablePadding.scss';
const ClickablePadding = (props) => {
return (
<div
className={ styles.container }
onClick={ props.onClick }
>&nbsp;</div>
)
const ClickablePadding = props => {
return <div className={styles.container} onClick={props.onClick}>&nbsp;</div>;
};
ClickablePadding.propTypes = {
onClick: React.PropTypes.func,
};
export default ClickablePadding;
export default ClickablePadding;

View File

@ -1,2 +1,2 @@
import ClickablePadding from './ClickablePadding';
export default ClickablePadding;
export default ClickablePadding;

View File

@ -11,7 +11,7 @@ class Offline extends React.Component {
state = {
offline: !navigator.onLine,
}
};
getChildContext() {
return {
@ -22,7 +22,7 @@ class Offline extends React.Component {
componentDidMount = () => {
window.addEventListener('offline', this.handleConnectionState);
window.addEventListener('online', this.handleConnectionState);
}
};
componentWillUnmount = () => {
window.removeEventListener('offline', this.handleConnectionState);
@ -33,7 +33,7 @@ class Offline extends React.Component {
this.setState({
offline: !navigator.onLine,
});
}
};
render() {
return React.Children.only(this.props.children);

View File

@ -1,7 +1,4 @@
import Offline from './Offline';
import injectOffline from './injectOffline';
export {
Offline,
injectOffline,
}
export { Offline, injectOffline };

View File

@ -1,6 +1,6 @@
import React from 'react';
const injectOffline = (WrappedComponent) => {
const injectOffline = WrappedComponent => {
return class OfflineWrapper extends React.Component {
static contextTypes = {
offline: React.PropTypes.bool,
@ -11,7 +11,7 @@ const injectOffline = (WrappedComponent) => {
offline: this.context.offline,
};
return (<WrappedComponent { ...this.props } { ...newProps } />);
return <WrappedComponent {...this.props} {...newProps} />;
}
};
};

View File

@ -17,31 +17,35 @@ class PublishingInfo extends React.Component {
render() {
return (
<Flex align="center" className={ styles.user }>
<Flex className={ styles.avatarLine }>
{ this.props.collaborators.reverse().map(user => (
<Flex align="center" className={styles.user}>
<Flex className={styles.avatarLine}>
{this.props.collaborators.reverse().map(user => (
<Avatar
key={ `avatar-${user.id}` }
src={ user.avatarUrl }
size={ 26 }
key={`avatar-${user.id}`}
src={user.avatarUrl}
size={26}
style={{
marginRight: '-12px',
border: '2px solid #FFFFFF',
}}
title={ user.name }
title={user.name}
/>
)) }
))}
</Flex>
<span className={ styles.userName }>
{ this.props.createdBy.name } published { moment(this.props.createdAt).fromNow() }
{ this.props.createdAt !== this.props.updatedAt ? (
<span>
&nbsp;and&nbsp;
{ this.props.createdBy.id !== this.props.updatedBy.id &&
` ${this.props.updatedBy.name} ` }
modified { moment(this.props.updatedAt).fromNow() }
</span>
) : null }
<span className={styles.userName}>
{this.props.createdBy.name}
{' '}
published
{' '}
{moment(this.props.createdAt).fromNow()}
{this.props.createdAt !== this.props.updatedAt
? <span>
&nbsp;and&nbsp;
{this.props.createdBy.id !== this.props.updatedBy.id &&
` ${this.props.updatedBy.name} `}
modified {moment(this.props.updatedAt).fromNow()}
</span>
: null}
</span>
</Flex>
);

View File

@ -1,2 +1,2 @@
import PublishingInfo from './PublishingInfo';
export default PublishingInfo;
export default PublishingInfo;

View File

@ -6,52 +6,57 @@ import classNames from 'classnames/bind';
const cx = classNames.bind(styles);
class Node extends React.Component {
displayName: 'UITreeNode'
displayName: 'UITreeNode';
renderCollapse = () => {
var index = this.props.index;
const index = this.props.index;
if(index.children && index.children.length) {
var collapsed = index.node.collapsed;
if (index.children && index.children.length) {
const collapsed = index.node.collapsed;
return (
<span
className={cx(styles.collapse, collapsed ? styles.caretRight : styles.caretDown)}
onMouseDown={function(e) {e.stopPropagation()}}
className={cx(
styles.collapse,
collapsed ? styles.caretRight : styles.caretDown
)}
onMouseDown={function(e) {
e.stopPropagation();
}}
onClick={this.handleCollapse}
>
<img src={ require("./assets/chevron.svg") } />
<img src={require('./assets/chevron.svg')} />
</span>
);
}
return null;
}
};
renderChildren = () => {
var index = this.props.index;
var tree = this.props.tree;
var dragging = this.props.dragging;
const index = this.props.index;
const tree = this.props.tree;
const dragging = this.props.dragging;
if(index.children && index.children.length) {
var childrenStyles = {};
if (index.children && index.children.length) {
const childrenStyles = {};
if (!this.props.rootNode) {
if(index.node.collapsed) childrenStyles.display = 'none';
childrenStyles['paddingLeft'] = this.props.paddingLeft + 'px';
if (index.node.collapsed) childrenStyles.display = 'none';
childrenStyles.paddingLeft = `${this.props.paddingLeft}px`;
}
return (
<div className={ styles.children } style={childrenStyles}>
{index.children.map((child) => {
var childIndex = tree.getIndex(child);
<div className={styles.children} style={childrenStyles}>
{index.children.map(child => {
const childIndex = tree.getIndex(child);
return (
<Node
tree={tree}
index={childIndex}
key={childIndex.id}
dragging={dragging}
allowUpdates={ this.props.allowUpdates }
allowUpdates={this.props.allowUpdates}
paddingLeft={this.props.paddingLeft}
onCollapse={this.props.onCollapse}
onDragStart={this.props.onDragStart}
@ -63,18 +68,18 @@ class Node extends React.Component {
}
return null;
}
};
isModifying = () => {
return this.props.allowUpdates && !this.props.rootNode;
}
};
onClick = () => {
const index = this.props.index;
const node = index.node;
if (!this.isModifying()) history.push(node.url);
}
};
render() {
const tree = this.props.tree;
@ -84,24 +89,31 @@ class Node extends React.Component {
const style = {};
return (
<div className={cx(styles.node, {
placeholder: index.id === dragging,
rootNode: this.props.rootNode,
})} style={style}>
<div
className={cx(styles.node, {
placeholder: index.id === dragging,
rootNode: this.props.rootNode,
})}
style={style}
>
<div
className={ styles.inner }
className={styles.inner}
ref="inner"
onMouseDown={this.props.rootNode || !this.props.allowUpdates ? (e) => e.stopPropagation() : this.handleMouseDown}
onMouseDown={
this.props.rootNode || !this.props.allowUpdates
? e => e.stopPropagation()
: this.handleMouseDown
}
>
{ !this.props.rootNode && this.renderCollapse() }
{!this.props.rootNode && this.renderCollapse()}
<span
className={ cx(styles.nodeLabel, {
className={cx(styles.nodeLabel, {
rootLabel: this.props.rootNode,
isModifying: this.isModifying(),
}) }
onClick={ this.onClick }
})}
onClick={this.onClick}
>
{ node.title }
{node.title}
</span>
</div>
{this.renderChildren()}
@ -109,20 +121,20 @@ class Node extends React.Component {
);
}
handleCollapse = (e) => {
handleCollapse = e => {
e.stopPropagation();
var nodeId = this.props.index.id;
if(this.props.onCollapse) this.props.onCollapse(nodeId);
}
const nodeId = this.props.index.id;
if (this.props.onCollapse) this.props.onCollapse(nodeId);
};
handleMouseDown = (e) => {
var nodeId = this.props.index.id;
var dom = this.refs.inner;
handleMouseDown = e => {
const nodeId = this.props.index.id;
const dom = this.refs.inner;
if(this.props.onDragStart) {
if (this.props.onDragStart) {
this.props.onDragStart(nodeId, dom, e);
}
}
};
};
}
module.exports = Node;

View File

@ -1,24 +1,24 @@
var Tree = require('js-tree');
var proto = Tree.prototype;
const Tree = require('js-tree');
const proto = Tree.prototype;
proto.updateNodesPosition = function() {
var top = 1;
var left = 1;
var root = this.getIndex(1);
var self = this;
let top = 1;
let left = 1;
const root = this.getIndex(1);
const self = this;
root.top = top++;
root.left = left++;
if(root.children && root.children.length) {
if (root.children && root.children.length) {
walk(root.children, root, left, root.node.collapsed);
}
function walk(children, parent, left, collapsed) {
var height = 1;
children.forEach(function(id) {
var node = self.getIndex(id);
if(collapsed) {
let height = 1;
children.forEach(id => {
const node = self.getIndex(id);
if (collapsed) {
node.top = null;
node.left = null;
} else {
@ -26,30 +26,35 @@ proto.updateNodesPosition = function() {
node.left = left;
}
if(node.children && node.children.length) {
height += walk(node.children, node, left+1, collapsed || node.node.collapsed);
if (node.children && node.children.length) {
height += walk(
node.children,
node,
left + 1,
collapsed || node.node.collapsed
);
} else {
node.height = 1;
height += 1;
}
});
if(parent.node.collapsed) parent.height = 1;
if (parent.node.collapsed) parent.height = 1;
else parent.height = height;
return parent.height;
}
};
proto.move = function(fromId, toId, placement) {
if(fromId === toId || toId === 1) return;
if (fromId === toId || toId === 1) return;
var obj = this.remove(fromId);
var index = null;
const obj = this.remove(fromId);
let index = null;
if(placement === 'before') index = this.insertBefore(obj, toId);
else if(placement === 'after') index = this.insertAfter(obj, toId);
else if(placement === 'prepend') index = this.prepend(obj, toId);
else if(placement === 'append') index = this.append(obj, toId);
if (placement === 'before') index = this.insertBefore(obj, toId);
else if (placement === 'after') index = this.insertAfter(obj, toId);
else if (placement === 'prepend') index = this.prepend(obj, toId);
else if (placement === 'append') index = this.append(obj, toId);
// todo: perf
this.updateNodesPosition();
@ -57,12 +62,12 @@ proto.move = function(fromId, toId, placement) {
};
proto.getNodeByTop = function(top) {
var indexes = this.indexes;
for(var id in indexes) {
if(indexes.hasOwnProperty(id)) {
if(indexes[id].top === top) return indexes[id];
const indexes = this.indexes;
for (const id in indexes) {
if (indexes.hasOwnProperty(id)) {
if (indexes[id].top === top) return indexes[id];
}
}
};
module.exports = Tree;
module.exports = Tree;

View File

@ -1,6 +1,6 @@
var React = require('react');
var Tree = require('./Tree');
var Node = require('./Node');
const React = require('react');
const Tree = require('./Tree');
const Node = require('./Node');
import styles from './Tree.scss';
@ -16,7 +16,7 @@ module.exports = React.createClass({
getDefaultProps() {
return {
paddingLeft: 20
paddingLeft: 20,
};
},
@ -25,47 +25,47 @@ module.exports = React.createClass({
},
componentWillReceiveProps(nextProps) {
if(!this._updated) this.setState(this.init(nextProps));
if (!this._updated) this.setState(this.init(nextProps));
else this._updated = false;
},
init(props) {
var tree = new Tree(props.tree);
const tree = new Tree(props.tree);
tree.isNodeCollapsed = props.isNodeCollapsed;
tree.changeNodeCollapsed = props.changeNodeCollapsed;
tree.updateNodesPosition();
return {
tree: tree,
tree,
dragging: {
id: null,
x: null,
y: null,
w: null,
h: null
}
h: null,
},
};
},
getDraggingDom() {
var tree = this.state.tree;
var dragging = this.state.dragging;
const tree = this.state.tree;
const dragging = this.state.dragging;
if(dragging && dragging.id) {
var draggingIndex = tree.getIndex(dragging.id);
var draggingStyles = {
if (dragging && dragging.id) {
const draggingIndex = tree.getIndex(dragging.id);
const draggingStyles = {
top: dragging.y,
left: dragging.x,
width: dragging.w
width: dragging.w,
};
return (
<div className={ styles.draggable } style={ draggingStyles }>
<div className={styles.draggable} style={draggingStyles}>
<Node
tree={ tree }
index={ draggingIndex }
paddingLeft={ this.props.paddingLeft }
allowUpdates={ this.props.allowUpdates }
tree={tree}
index={draggingIndex}
paddingLeft={this.props.paddingLeft}
allowUpdates={this.props.allowUpdates}
/>
</div>
);
@ -75,23 +75,23 @@ module.exports = React.createClass({
},
render() {
var tree = this.state.tree;
var dragging = this.state.dragging;
var draggingDom = this.getDraggingDom();
const tree = this.state.tree;
const dragging = this.state.dragging;
const draggingDom = this.getDraggingDom();
return (
<div className={ styles.tree }>
{ draggingDom }
<div className={styles.tree}>
{draggingDom}
<Node
rootNode
tree={ tree }
index={ tree.getIndex(1) }
key={ 1 }
paddingLeft={ this.props.paddingLeft }
allowUpdates={ this.props.allowUpdates }
onDragStart={ this.dragStart }
onCollapse={ this.toggleCollapse }
dragging={ dragging && dragging.id }
tree={tree}
index={tree.getIndex(1)}
key={1}
paddingLeft={this.props.paddingLeft}
allowUpdates={this.props.allowUpdates}
onDragStart={this.dragStart}
onCollapse={this.toggleCollapse}
dragging={dragging && dragging.id}
/>
</div>
);
@ -99,11 +99,11 @@ module.exports = React.createClass({
dragStart(id, dom, e) {
this.dragging = {
id: id,
id,
w: dom.offsetWidth,
h: dom.offsetHeight,
x: dom.offsetLeft,
y: dom.offsetTop
y: dom.offsetTop,
};
this._startX = dom.offsetLeft;
@ -118,69 +118,73 @@ module.exports = React.createClass({
// oh
drag(e) {
if(this._start) {
if (this._start) {
this.setState({
dragging: this.dragging
dragging: this.dragging,
});
this._start = false;
}
var tree = this.state.tree;
var dragging = this.state.dragging;
var paddingLeft = this.props.paddingLeft;
var newIndex = null;
var index = tree.getIndex(dragging.id);
var collapsed = index.node.collapsed;
const tree = this.state.tree;
const dragging = this.state.dragging;
const paddingLeft = this.props.paddingLeft;
let newIndex = null;
let index = tree.getIndex(dragging.id);
const collapsed = index.node.collapsed;
var _startX = this._startX;
var _startY = this._startY;
var _offsetX = this._offsetX;
var _offsetY = this._offsetY;
const _startX = this._startX;
const _startY = this._startY;
const _offsetX = this._offsetX;
const _offsetY = this._offsetY;
var pos = {
const pos = {
x: _startX + e.clientX - _offsetX,
y: _startY + e.clientY - _offsetY
y: _startY + e.clientY - _offsetY,
};
dragging.x = pos.x;
dragging.y = pos.y;
var diffX = dragging.x - paddingLeft/2 - (index.left-2) * paddingLeft;
var diffY = dragging.y - dragging.h/2 - (index.top-2) * dragging.h;
const diffX = dragging.x - paddingLeft / 2 - (index.left - 2) * paddingLeft;
const diffY = dragging.y - dragging.h / 2 - (index.top - 2) * dragging.h;
if(diffX < 0) { // left
if(index.parent && !index.next) {
if (diffX < 0) {
// left
if (index.parent && !index.next) {
newIndex = tree.move(index.id, index.parent, 'after');
}
} else if(diffX > paddingLeft) { // right
if(index.prev) {
var prevNode = tree.getIndex(index.prev).node;
if(!prevNode.collapsed && !prevNode.leaf) {
} else if (diffX > paddingLeft) {
// right
if (index.prev) {
const prevNode = tree.getIndex(index.prev).node;
if (!prevNode.collapsed && !prevNode.leaf) {
newIndex = tree.move(index.id, index.prev, 'append');
}
}
}
if(newIndex) {
if (newIndex) {
index = newIndex;
newIndex.node.collapsed = collapsed;
dragging.id = newIndex.id;
}
if(diffY < 0) { // up
var above = tree.getNodeByTop(index.top-1);
if (diffY < 0) {
// up
const above = tree.getNodeByTop(index.top - 1);
newIndex = tree.move(index.id, above.id, 'before');
} else if(diffY > dragging.h) { // down
if(index.next) {
} else if (diffY > dragging.h) {
// down
if (index.next) {
var below = tree.getIndex(index.next);
if(below.children && below.children.length && !below.node.collapsed) {
if (below.children && below.children.length && !below.node.collapsed) {
newIndex = tree.move(index.id, index.next, 'prepend');
} else {
newIndex = tree.move(index.id, index.next, 'after');
}
} else {
var below = tree.getNodeByTop(index.top+index.height);
if(below && below.parent !== index.id) {
if(below.children && below.children.length) {
var below = tree.getNodeByTop(index.top + index.height);
if (below && below.parent !== index.id) {
if (below.children && below.children.length) {
newIndex = tree.move(index.id, below.id, 'prepend');
} else {
newIndex = tree.move(index.id, below.id, 'after');
@ -189,14 +193,14 @@ module.exports = React.createClass({
}
}
if(newIndex) {
if (newIndex) {
newIndex.node.collapsed = collapsed;
dragging.id = newIndex.id;
}
this.setState({
tree: tree,
dragging: dragging
tree,
dragging,
});
},
@ -207,8 +211,8 @@ module.exports = React.createClass({
x: null,
y: null,
w: null,
h: null
}
h: null,
},
});
this.change(this.state.tree);
@ -218,21 +222,21 @@ module.exports = React.createClass({
change(tree) {
this._updated = true;
if(this.props.onChange) this.props.onChange(tree.obj);
if (this.props.onChange) this.props.onChange(tree.obj);
},
toggleCollapse(nodeId) {
var tree = this.state.tree;
var index = tree.getIndex(nodeId);
var node = index.node;
const tree = this.state.tree;
const index = tree.getIndex(nodeId);
const node = index.node;
node.collapsed = !node.collapsed;
tree.updateNodesPosition();
this.setState({
tree: tree
tree,
});
if(this.props.onCollapse) this.props.onCollapse(node.id, node.collapsed);
if (this.props.onCollapse) this.props.onCollapse(node.id, node.collapsed);
},
// buildTreeNumbering(tree) {

View File

@ -1,2 +1,2 @@
import UiTree from './UiTree';
export default UiTree;
export default UiTree;

View File

@ -1,7 +1,7 @@
let constants;
constants = {
API_USER_AGENT: `Atlas`,
API_USER_AGENT: 'Atlas',
API_BASE_URL: '/api',
};

View File

@ -46,63 +46,83 @@ function requireAuth(nextState, replace) {
}
}
render((
render(
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
<Provider { ...stores }>
<Provider {...stores}>
<Offline>
<Router history={ History }>
<Route path="/" component={ Application }>
<IndexRoute component={ Home } />
<Router history={History}>
<Route path="/" component={Application}>
<IndexRoute component={Home} />
<Route path="/dashboard" component={ Dashboard } onEnter={ requireAuth } />
<Route path="/collections/:id" component={ Atlas } onEnter={ requireAuth } />
<Route
path="/dashboard"
component={Dashboard}
onEnter={requireAuth}
/>
<Route
path="/collections/:id"
component={Atlas}
onEnter={requireAuth}
/>
<Route
path="/collections/:id/new"
component={ DocumentEdit }
onEnter={ requireAuth }
component={DocumentEdit}
onEnter={requireAuth}
newDocument
/>
<Route path="/d/:id" component={ DocumentScene } onEnter={ requireAuth } />
<Route path="/d/:id/edit" component={ DocumentEdit } onEnter={ requireAuth } />
<Route
path="/d/:id"
component={DocumentScene}
onEnter={requireAuth}
/>
<Route
path="/d/:id/edit"
component={DocumentEdit}
onEnter={requireAuth}
/>
<Route
path="/d/:id/new"
component={ DocumentEdit }
onEnter={ requireAuth }
component={DocumentEdit}
onEnter={requireAuth}
newChildDocument
/>
<Route path="/search" component={ Search } onEnter={ requireAuth } />
<Route path="/settings" component={ Settings } onEnter={ requireAuth } />
<Route path="/search" component={Search} onEnter={requireAuth} />
<Route
path="/settings"
component={Settings}
onEnter={requireAuth}
/>
<Route path="/auth/slack" component={ SlackAuth } />
<Route path="/auth/slack" component={SlackAuth} />
<Route
path="/auth/slack/commands"
component={ SlackAuth }
component={SlackAuth}
apiPath="/auth.slackCommands"
/>
<Route path="/auth/error" component={ ErrorAuth } />
<Route path="/auth/error" component={ErrorAuth} />
<Flatpage
path="/keyboard-shortcuts"
component={ Flatpage }
component={Flatpage}
title="Keyboard shortcuts"
content={ flatpages.keyboard }
content={flatpages.keyboard}
/>
<Flatpage
path="/developers"
component={ Flatpage }
component={Flatpage}
title="API"
content={ flatpages.api }
content={flatpages.api}
/>
<Route path="/404" component={ Error404 } />
<Route path="*" component={ Search } sceneType="notFound" />
<Route path="/404" component={Error404} />
<Route path="*" component={Search} sceneType="notFound" />
</Route>
</Router>
</Offline>
</Provider>
{ __DEV__ && <DevTools position={{ bottom: 0, right: 0 }} /> }
</div>
), document.getElementById('root'));
{__DEV__ && <DevTools position={{ bottom: 0, right: 0 }} />}
</div>,
document.getElementById('root')
);

View File

@ -22,7 +22,7 @@ import styles from './Atlas.scss';
class Atlas extends React.Component {
static propTypes = {
params: PropTypes.object.isRequired,
}
};
componentDidMount = () => {
const { id } = this.props.params;
@ -32,21 +32,21 @@ class Atlas extends React.Component {
browserHistory.replace(data.navigationTree.url);
}
});
}
};
componentWillReceiveProps = (nextProps) => {
componentWillReceiveProps = nextProps => {
const key = nextProps.keydown.event;
if (key) {
if (key.key === 'c') {
_.defer(this.onCreate);
}
}
}
};
onCreate = (event) => {
onCreate = event => {
if (event) event.preventDefault();
browserHistory.push(`${store.collection.url}/new`);
}
};
render() {
const collection = store.collection;
@ -58,47 +58,44 @@ class Atlas extends React.Component {
if (collection) {
actions = (
<Flex>
<DropdownMenu label={ <MoreIcon /> } >
<MenuItem onClick={ this.onCreate }>
<DropdownMenu label={<MoreIcon />}>
<MenuItem onClick={this.onCreate}>
New document
</MenuItem>
</DropdownMenu>
</Flex>
);
title = <Title>{ collection.name }</Title>;
title = <Title>{collection.name}</Title>;
titleText = collection.name;
}
return (
<Layout
actions={ actions }
title={ title }
titleText={ titleText }
>
<Layout actions={actions} title={title} titleText={titleText}>
<CenteredContent>
<ReactCSSTransitionGroup
transitionName="fadeIn"
transitionAppear
transitionAppearTimeout={ 0 }
transitionEnterTimeout={ 0 }
transitionLeaveTimeout={ 0 }
transitionAppearTimeout={0}
transitionEnterTimeout={0}
transitionLeaveTimeout={0}
>
{ store.isFetching ? (
<AtlasPreviewLoading />
) : (
<div className={ styles.container }>
<div className={ styles.atlasDetails }>
<h2>{ collection.name }</h2>
<blockquote>
{ collection.description }
</blockquote>
</div>
{store.isFetching
? <AtlasPreviewLoading />
: <div className={styles.container}>
<div className={styles.atlasDetails}>
<h2>{collection.name}</h2>
<blockquote>
{collection.description}
</blockquote>
</div>
<Divider />
<Divider />
<DocumentList documents={ collection.recentDocuments } preview />
</div>
) }
<DocumentList
documents={collection.recentDocuments}
preview
/>
</div>}
</ReactCSSTransitionGroup>
</CenteredContent>
</Layout>

View File

@ -18,10 +18,10 @@ const store = new class AtlasStore {
this.collection = data;
successCallback(data);
} catch (e) {
console.error("Something went wrong");
console.error('Something went wrong');
}
this.isFetching = false;
}
};
}();
export default store;

View File

@ -1,2 +1,2 @@
import Atlas from './Atlas';
export default Atlas;
export default Atlas;

View File

@ -18,7 +18,7 @@ class DashboardStore {
runInAction('fetchCollections', () => {
this.collections = data;
this.pagination = pagination;
data.forEach((collection) => cacheResponse(collection.recentDocuments));
data.forEach(collection => cacheResponse(collection.recentDocuments));
});
// If only one collection, visit it automatically
@ -29,7 +29,7 @@ class DashboardStore {
console.error('Something went wrong');
}
this.isFetching = false;
}
};
constructor(options) {
this.team = options.team;

View File

@ -1,2 +1,2 @@
import Dashboard from './Dashboard';
export default Dashboard;
export default Dashboard;

View File

@ -3,9 +3,7 @@ import { observer } from 'mobx-react';
import { browserHistory, withRouter } from 'react-router';
import keydown from 'react-keydown';
import DocumentEditStore, {
DOCUMENT_EDIT_SETTINGS,
} from './DocumentEditStore';
import DocumentEditStore, { DOCUMENT_EDIT_SETTINGS } from './DocumentEditStore';
import Switch from 'components/Switch';
import Layout, { Title, HeaderAction, SaveAction } from 'components/Layout';
@ -20,9 +18,13 @@ const DISREGARD_CHANGES = `You have unsaved changes.
Are you sure you want to disgard them?`;
@keydown([
'cmd+enter', 'ctrl+enter',
'cmd+esc', 'ctrl+esc',
'cmd+shift+p', 'ctrl+shift+p'])
'cmd+enter',
'ctrl+enter',
'cmd+esc',
'ctrl+esc',
'cmd+shift+p',
'ctrl+shift+p',
])
@withRouter
@observer
class DocumentEdit extends Component {
@ -30,7 +32,7 @@ class DocumentEdit extends Component {
route: React.PropTypes.object.isRequired,
router: React.PropTypes.object.isRequired,
params: React.PropTypes.object,
}
};
constructor(props) {
super(props);
@ -41,7 +43,7 @@ class DocumentEdit extends Component {
state = {
scrollTop: 0,
}
};
componentDidMount = () => {
if (this.props.route.newDocument) {
@ -58,8 +60,7 @@ class DocumentEdit extends Component {
}
// Load editor async
EditorLoader()
.then(({ Editor }) => {
EditorLoader().then(({ Editor }) => {
this.setState({ Editor });
});
@ -70,9 +71,9 @@ class DocumentEdit extends Component {
}
return null;
});
}
};
componentWillReceiveProps = (nextProps) => {
componentWillReceiveProps = nextProps => {
const key = nextProps.keydown.event;
if (key) {
@ -91,7 +92,7 @@ class DocumentEdit extends Component {
this.store.togglePreview();
}
}
}
};
onSave = () => {
// if (this.props.title.length === 0) {
@ -103,45 +104,46 @@ class DocumentEdit extends Component {
} else {
this.store.updateDocument();
}
}
};
onCancel = () => {
browserHistory.goBack();
}
};
onScroll = (scrollTop) => {
onScroll = scrollTop => {
this.setState({
scrollTop,
});
}
};
render() {
let title = (
const title = (
<Title
truncate={ 60 }
placeholder={ !this.store.isFetching && 'Untitled document' }
truncate={60}
placeholder={!this.store.isFetching && 'Untitled document'}
>
{ this.store.title }
{this.store.title}
</Title>
);
let titleText = this.store.title;
let isNew = this.props.route.newDocument || this.props.route.newChildDocument;
const titleText = this.store.title;
const isNew =
this.props.route.newDocument || this.props.route.newChildDocument;
const actions = (
<Flex>
<HeaderAction>
<SaveAction
onClick={ this.onSave }
disabled={ this.store.isSaving }
isNew={ isNew }
onClick={this.onSave}
disabled={this.store.isSaving}
isNew={isNew}
/>
</HeaderAction>
<DropdownMenu label={ <MoreIcon /> }>
<MenuItem onClick={ this.store.togglePreview }>
Preview <Switch checked={ this.store.preview } />
<DropdownMenu label={<MoreIcon />}>
<MenuItem onClick={this.store.togglePreview}>
Preview <Switch checked={this.store.preview} />
</MenuItem>
<MenuItem onClick={ this.onCancel }>
<MenuItem onClick={this.onCancel}>
Cancel
</MenuItem>
</DropdownMenu>
@ -150,27 +152,25 @@ class DocumentEdit extends Component {
return (
<Layout
actions={ actions }
title={ title }
titleText={ titleText }
actions={actions}
title={title}
titleText={titleText}
fixed
loading={ this.store.isSaving || this.store.isUploading }
search={ false }
loading={this.store.isSaving || this.store.isUploading}
search={false}
>
{ (this.store.isFetching || !('Editor' in this.state)) ? (
<CenteredContent>
<AtlasPreviewLoading />
</CenteredContent>
) : (
<this.state.Editor
store={ this.store }
scrollTop={ this.state.scrollTop }
onScroll={ this.onScroll }
onSave={ this.onSave }
onCancel={ this.onCancel }
togglePreview={ this.togglePreview }
/>
) }
{this.store.isFetching || !('Editor' in this.state)
? <CenteredContent>
<AtlasPreviewLoading />
</CenteredContent>
: <this.state.Editor
store={this.store}
scrollTop={this.state.scrollTop}
onScroll={this.onScroll}
onSave={this.onSave}
onCancel={this.onCancel}
togglePreview={this.togglePreview}
/>}
</Layout>
);
}

View File

@ -5,7 +5,7 @@ import emojify from 'utils/emojify';
const DOCUMENT_EDIT_SETTINGS = 'DOCUMENT_EDIT_SETTINGS';
const parseHeader = (text) => {
const parseHeader = text => {
const firstLine = text.split(/\r?\n/)[0];
if (firstLine) {
const match = firstLine.match(/^#+ +(.*)$/);
@ -40,9 +40,13 @@ class DocumentEditStore {
this.isFetching = true;
try {
const data = await client.get('/documents.info', {
id: this.documentId,
}, { cache: true });
const data = await client.get(
'/documents.info',
{
id: this.documentId,
},
{ cache: true }
);
if (this.newChildDocument) {
this.parentDocument = data.data;
} else {
@ -54,7 +58,7 @@ class DocumentEditStore {
console.error('Something went wrong');
}
this.isFetching = false;
}
};
@action saveDocument = async () => {
if (this.isSaving) return;
@ -62,12 +66,16 @@ class DocumentEditStore {
this.isSaving = true;
try {
const data = await client.post('/documents.create', {
parentDocument: this.parentDocument && this.parentDocument.id,
collection: this.collectionId || this.parentDocument.collection.id,
title: this.title || 'Untitled document',
text: this.text,
}, { cache: true });
const data = await client.post(
'/documents.create',
{
parentDocument: this.parentDocument && this.parentDocument.id,
collection: this.collectionId || this.parentDocument.collection.id,
title: this.title || 'Untitled document',
text: this.text,
},
{ cache: true }
);
const { url } = data.data;
this.hasPendingChanges = false;
@ -76,7 +84,7 @@ class DocumentEditStore {
console.error('Something went wrong');
}
this.isSaving = false;
}
};
@action updateDocument = async () => {
if (this.isSaving) return;
@ -84,11 +92,15 @@ class DocumentEditStore {
this.isSaving = true;
try {
const data = await client.post('/documents.update', {
id: this.documentId,
title: this.title || 'Untitled document',
text: this.text,
}, { cache: true });
const data = await client.post(
'/documents.update',
{
id: this.documentId,
title: this.title || 'Untitled document',
text: this.text,
},
{ cache: true }
);
const { url } = data.data;
this.hasPendingChanges = false;
@ -97,35 +109,35 @@ class DocumentEditStore {
console.error('Something went wrong');
}
this.isSaving = false;
}
};
@action updateText = (text) => {
@action updateText = text => {
this.text = text;
this.title = parseHeader(text);
this.hasPendingChanges = true;
}
};
@action updateTitle = (title) => {
@action updateTitle = title => {
this.title = title;
}
};
@action replaceText = (args) => {
@action replaceText = args => {
this.text = this.text.replace(args.original, args.new);
this.hasPendingChanges = true;
}
};
@action togglePreview = () => {
this.preview = !this.preview;
}
};
@action reset = () => {
this.title = 'Lets start with a title';
this.text = '# Lets start with a title\n\nAnd continue from there...';
}
};
@action toggleUploadingIndicator = () => {
this.isUploading = !this.isUploading;
}
};
// Generic
@ -133,7 +145,7 @@ class DocumentEditStore {
localStorage[DOCUMENT_EDIT_SETTINGS] = JSON.stringify({
preview: toJS(this.preview),
});
}
};
constructor(settings) {
// Rehydrate settings
@ -148,6 +160,4 @@ class DocumentEditStore {
}
export default DocumentEditStore;
export {
DOCUMENT_EDIT_SETTINGS,
};
export { DOCUMENT_EDIT_SETTINGS };

View File

@ -8,33 +8,28 @@ import EditorPane from './EditorPane';
import styles from '../DocumentEdit.scss';
const Editor = observer((props) => {
const Editor = observer(props => {
const store = props.store;
return (
<div className={ styles.container }>
<EditorPane
fullWidth={ !store.preview }
onScroll={ props.onScroll }
>
<div className={styles.container}>
<EditorPane fullWidth={!store.preview} onScroll={props.onScroll}>
<MarkdownEditor
onChange={ store.updateText }
text={ store.text }
replaceText={ store.replaceText }
preview={ store.preview }
onSave={ props.onSave }
onCancel={ props.onCancel }
togglePreview={ props.togglePreview }
toggleUploadingIndicator={ store.toggleUploadingIndicator }
onChange={store.updateText}
text={store.text}
replaceText={store.replaceText}
preview={store.preview}
onSave={props.onSave}
onCancel={props.onCancel}
togglePreview={props.togglePreview}
toggleUploadingIndicator={store.toggleUploadingIndicator}
/>
</EditorPane>
{ store.preview ? (
<EditorPane
scrollTop={ props.scrollTop }
>
<Preview html={ convertToMarkdown(store.text) } />
</EditorPane>
) : null }
{store.preview
? <EditorPane scrollTop={props.scrollTop}>
<Preview html={convertToMarkdown(store.text)} />
</EditorPane>
: null}
</div>
);
});

View File

@ -10,32 +10,31 @@ class EditorPane extends React.Component {
onScroll: React.PropTypes.func.isRequired,
scrollTop: React.PropTypes.number,
fullWidth: React.PropTypes.bool,
}
componentWillReceiveProps = (nextProps) => {
};
componentWillReceiveProps = nextProps => {
if (nextProps.scrollTop) {
this.scrollToPosition(nextProps.scrollTop)
this.scrollToPosition(nextProps.scrollTop);
}
}
};
componentDidMount = () => {
this.refs.pane.addEventListener('scroll', this.handleScroll);
}
};
componentWillUnmount = () => {
this.refs.pane.removeEventListener('scroll', this.handleScroll);
}
};
handleScroll = (e) => {
handleScroll = e => {
setTimeout(() => {
const element = this.refs.pane;
const contentEl = this.refs.content;
this.props.onScroll(element.scrollTop / contentEl.offsetHeight);
}, 50);
}
};
scrollToPosition = (percentage) => {
scrollToPosition = percentage => {
const contentEl = this.refs.content;
// Push to edges
@ -43,20 +42,20 @@ class EditorPane extends React.Component {
if (percentage > 0.99) percentage = 100;
this.refs.pane.scrollTop = percentage * contentEl.offsetHeight;
}
};
render() {
return (
<div
className={ cx(styles.editorPane, { fullWidth: this.props.fullWidth }) }
className={cx(styles.editorPane, { fullWidth: this.props.fullWidth })}
ref="pane"
>
<div ref="content" className={ styles.paneContent }>
{ this.props.children }
<div ref="content" className={styles.paneContent}>
{this.props.children}
</div>
</div>
);
}
};
}
export default EditorPane;

View File

@ -6,10 +6,10 @@ import styles from './Preview.scss';
import classNames from 'classnames/bind';
const cx = classNames.bind(styles);
const Preview = (props) => {
const Preview = props => {
return (
<div className={ cx(styles.container) }>
<DocumentHtml html={ props.html } />
<div className={cx(styles.container)}>
<DocumentHtml html={props.html} />
</div>
);
};

View File

@ -1,5 +1,12 @@
import _ from 'lodash';
import { observable, action, computed, runInAction, toJS, autorunAsync } from 'mobx';
import {
observable,
action,
computed,
runInAction,
toJS,
autorunAsync,
} from 'mobx';
import { client } from 'utils/ApiClient';
import { browserHistory } from 'react-router';
@ -19,15 +26,14 @@ class DocumentSceneStore {
/* Computed */
@computed get isCollection() {
return this.document &&
this.document.collection.type === 'atlas';
return this.document && this.document.collection.type === 'atlas';
}
@computed get collectionTree() {
if (!this.document || this.document.collection.type !== 'atlas') return;
const tree = this.document.collection.navigationTree;
const collapseNodes = (node) => {
const collapseNodes = node => {
node.collapsed = this.collapsedNodes.includes(node.id);
node.children = node.children.map(childNode => {
return collapseNodes(childNode);
@ -69,7 +75,7 @@ class DocumentSceneStore {
}
this.isFetching = false;
this.updatingContent = false;
}
};
@action deleteDocument = async () => {
this.isFetching = true;
@ -81,9 +87,9 @@ class DocumentSceneStore {
console.error('Something went wrong');
}
this.isFetching = false;
}
};
@action updateNavigationTree = async (tree) => {
@action updateNavigationTree = async tree => {
// Only update when tree changes
if (_.isEqual(toJS(tree), toJS(this.document.collection.navigationTree))) {
return true;
@ -104,15 +110,15 @@ class DocumentSceneStore {
console.error('Something went wrong');
}
this.updatingStructure = false;
}
};
@action onNodeCollapse = (nodeId) => {
@action onNodeCollapse = nodeId => {
if (_.indexOf(this.collapsedNodes, nodeId) >= 0) {
this.collapsedNodes = _.without(this.collapsedNodes, nodeId);
} else {
this.collapsedNodes.push(nodeId);
}
}
};
// General
@ -120,7 +126,7 @@ class DocumentSceneStore {
localStorage[DOCUMENT_PREFERENCES] = JSON.stringify({
collapsedNodes: toJS(this.collapsedNodes),
});
}
};
constructor(settings, options) {
// Rehydrate settings
@ -136,6 +142,4 @@ class DocumentSceneStore {
}
export default DocumentSceneStore;
export {
DOCUMENT_PREFERENCES,
};
export { DOCUMENT_PREFERENCES };

View File

@ -12,8 +12,7 @@ const cx = classNames.bind(styles);
import SidebarStore from './SidebarStore';
@observer
class Sidebar extends React.Component {
@observer class Sidebar extends React.Component {
static store;
static propTypes = {
@ -22,7 +21,7 @@ class Sidebar extends React.Component {
navigationTree: PropTypes.object.isRequired,
onNavigationUpdate: PropTypes.func.isRequired,
onNodeCollapse: PropTypes.func.isRequired,
}
};
constructor(props) {
super(props);
@ -30,49 +29,47 @@ class Sidebar extends React.Component {
this.store = new SidebarStore();
}
toggleEdit = (e) => {
toggleEdit = e => {
e.preventDefault();
this.store.toggleEdit();
}
};
render() {
return (
<Flex>
{ this.props.open && (
<Flex column className={ cx(styles.sidebar) }>
<Flex auto className={ cx(styles.content) }>
{this.props.open &&
<Flex column className={cx(styles.sidebar)}>
<Flex auto className={cx(styles.content)}>
<Tree
paddingLeft={ 10 }
tree={ this.props.navigationTree }
allowUpdates={ this.store.isEditing }
onChange={ this.props.onNavigationUpdate }
onCollapse={ this.props.onNodeCollapse }
paddingLeft={10}
tree={this.props.navigationTree}
allowUpdates={this.store.isEditing}
onChange={this.props.onNavigationUpdate}
onCollapse={this.props.onNodeCollapse}
/>
</Flex>
<Flex auto className={ styles.actions }>
{ this.store.isEditing && (
<span className={ styles.action }>
<Flex auto className={styles.actions}>
{this.store.isEditing &&
<span className={styles.action}>
Drag & drop to organize <Separator />&nbsp;
</span>
) }
</span>}
<span
role="button"
onClick={ this.toggleEdit }
className={ cx(styles.action, { active: this.store.isEditing }) }
onClick={this.toggleEdit}
className={cx(styles.action, { active: this.store.isEditing })}
>
{ !this.store.isEditing ? 'Organize documents' : 'Done' }
{!this.store.isEditing ? 'Organize documents' : 'Done'}
</span>
</Flex>
</Flex>
) }
</Flex>}
<div
onClick={ this.props.onToggle }
className={ cx(styles.sidebarToggle, { active: this.store.isEditing }) }
onClick={this.props.onToggle}
className={cx(styles.sidebarToggle, { active: this.store.isEditing })}
title="Toggle sidebar (Cmd+/)"
>
<img
src={ require("assets/icons/menu.svg") }
className={ styles.menuIcon }
src={require('assets/icons/menu.svg')}
className={styles.menuIcon}
alt="Menu"
/>
</div>

View File

@ -7,7 +7,7 @@ class SidebarStore {
@action toggleEdit = () => {
this.isEditing = !this.isEditing;
}
};
}
export default SidebarStore;

View File

@ -5,8 +5,8 @@ import styles from './Separator.scss';
class Separator extends React.Component {
render() {
return (
<span className={ styles.separator }>
&middot;
<span className={styles.separator}>
·
</span>
);
}

View File

@ -1,2 +1,2 @@
import DocumentScene from './DocumentScene';
export default DocumentScene;
export default DocumentScene;

View File

@ -7,9 +7,7 @@ import CenteredContent from 'components/CenteredContent';
class Error404 extends React.Component {
render() {
return (
<Layout
titleText="Not Found"
>
<Layout titleText="Not Found">
<CenteredContent>
<h1>Not Found</h1>

View File

@ -7,13 +7,13 @@ import CenteredContent from 'components/CenteredContent';
class ErrorAuth extends React.Component {
render() {
return (
<Layout
titleText="Not Found"
>
<Layout titleText="Not Found">
<CenteredContent>
<h1>Authentication failed</h1>
<p>We were unable to log you in. <Link to="/">Please try again.</Link></p>
<p>
We were unable to log you in. <Link to="/">Please try again.</Link>
</p>
</CenteredContent>
</Layout>
);

View File

@ -7,23 +7,18 @@ import { DocumentHtml } from 'components/Document';
import { convertToMarkdown } from 'utils/markdown';
@observer
class Flatpage extends React.Component {
@observer class Flatpage extends React.Component {
static propTypes = {
route: PropTypes.object,
}
};
render() {
const { title, content } = this.props.route;
return (
<Layout
title={ <Title>{ title }</Title> }
titleText={ title }
search={ false }
>
<Layout title={<Title>{title}</Title>} titleText={title} search={false}>
<CenteredContent>
<DocumentHtml html={ convertToMarkdown(content) } />
<DocumentHtml html={convertToMarkdown(content)} />
</CenteredContent>
</Layout>
);

View File

@ -1,26 +1,44 @@
import React from 'react';
import { Frame } from 'react-keyframes';
let frames = [];
const p = (node) => frames.push(node);
const E = (props) => {
return (<Frame duration={props.duration || 300} component='div'>{ props.children }</Frame>);
const frames = [];
const p = node => frames.push(node);
const E = props => {
return (
<Frame duration={props.duration || 300} component="div">
{props.children}
</Frame>
);
};
const line1 = (<p>Hi there,</p>);
const line2 = (<p>We're excited to share what were building.</p>);
const line3 = (<p>We <strong>**love**</strong> Markdown,</p>);
const line4 = (<p>but we also get that it's not for everyone.</p>);
const line5 = (<p>Together with you,</p>);
const line6 = (<p>we want to build the best place to</p>);
const line7 = (<p>share ideas,</p>);
const line8 = (<p>tell stories,</p>);
const line9 = (<p>and build knowledge.</p>);
const line10 = (<p>We're just getting started.</p>);
const line11 = (<p>Welcome to Atlas.</p>);
const line1 = <p>Hi there,</p>;
const line2 = <p>We're excited to share what were building.</p>;
const line3 = <p>We <strong>**love**</strong> Markdown,</p>;
const line4 = <p>but we also get that it's not for everyone.</p>;
const line5 = <p>Together with you,</p>;
const line6 = <p>we want to build the best place to</p>;
const line7 = <p>share ideas,</p>;
const line8 = <p>tell stories,</p>;
const line9 = <p>and build knowledge.</p>;
const line10 = <p>We're just getting started.</p>;
const line11 = <p>Welcome to Atlas.</p>;
p(<E>{line1}{line2}{line3}{line4}{line5}{line6}{line7}{line8}{line9}{line10}{line11}</E>);
p(
<E>
{line1}
{line2}
{line3}
{line4}
{line5}
{line6}
{line7}
{line8}
{line9}
{line10}
{line11}
</E>
);
// Hmms leaving this here for now, would be nice to something
export default frames;
export default frames;

View File

@ -1,2 +1,2 @@
import Home from './Home';
export default Home;
export default Home;

View File

@ -12,12 +12,11 @@ import styles from './Search.scss';
import SearchStore from './SearchStore';
@observer
class Search extends React.Component {
@observer class Search extends React.Component {
static propTypes = {
route: PropTypes.object.isRequired,
routeParams: PropTypes.object.isRequired,
}
};
constructor(props) {
super(props);
@ -31,7 +30,7 @@ class Search extends React.Component {
searchTerm = searchTerm.split(/[\s-]+/gi).join(' ');
this.store.search(searchTerm);
}
}
};
get viewNotFound() {
const { sceneType } = this.props.route;
@ -39,7 +38,7 @@ class Search extends React.Component {
}
render() {
const search = _.debounce((searchTerm) => {
const search = _.debounce(searchTerm => {
this.store.search(searchTerm);
}, 250);
const title = (
@ -50,35 +49,37 @@ class Search extends React.Component {
return (
<Layout
title={ title }
title={title}
titleText="Search"
search={ false }
loading={ this.store.isFetching }
search={false}
loading={this.store.isFetching}
>
<CenteredContent>
{ this.viewNotFound && (
{this.viewNotFound &&
<div>
<h1>Not Found</h1>
<p>We're unable to find the page you're accessing.</p>
<hr />
</div>
) }
</div>}
<Flex column auto>
<Flex auto>
<img
src={ require('assets/icons/search.svg') }
className={ styles.icon }
src={require('assets/icons/search.svg')}
className={styles.icon}
alt="Search"
/>
<SearchField
searchTerm={ this.store.searchTerm }
onChange={ search }
searchTerm={this.store.searchTerm}
onChange={search}
/>
</Flex>
{ this.store.documents && this.store.documents.map((document) => {
return (<DocumentPreview key={ document.id } document={ document } />);
}) }
{this.store.documents &&
this.store.documents.map(document => {
return (
<DocumentPreview key={document.id} document={document} />
);
})}
</Flex>
</CenteredContent>
</Layout>

View File

@ -11,7 +11,7 @@ class SearchStore {
/* Actions */
@action search = async (query) => {
@action search = async query => {
this.searchTerm = query;
this.isFetching = true;
@ -24,14 +24,14 @@ class SearchStore {
this.pagination = pagination;
});
} catch (e) {
console.error("Something went wrong");
console.error('Something went wrong');
}
} else {
this.documents = null;
}
this.isFetching = false;
}
};
}
export default SearchStore;

View File

@ -3,22 +3,21 @@ import { observer } from 'mobx-react';
import styles from './SearchField.scss';
@observer
class SearchField extends React.Component {
@observer class SearchField extends React.Component {
static propTypes = {
onChange: PropTypes.func,
}
};
onChange = (event) => {
onChange = event => {
this.props.onChange(event.currentTarget.value);
}
};
render() {
return (
<div className={ styles.container }>
<div className={styles.container}>
<input
onChange={ this.onChange }
className={ styles.field }
onChange={this.onChange}
className={styles.field}
placeholder="Search"
autoFocus
/>

View File

@ -12,8 +12,7 @@ import styles from './Settings.scss';
import SettingsStore from './SettingsStore';
@observer
class Settings extends React.Component {
@observer class Settings extends React.Component {
static store;
constructor(props) {
@ -21,10 +20,10 @@ class Settings extends React.Component {
this.store = new SettingsStore();
}
onKeyCreate = (e) => {
onKeyCreate = e => {
e.preventDefault();
this.store.createApiKey();
}
};
render() {
const title = (
@ -37,48 +36,52 @@ class Settings extends React.Component {
return (
<Layout
title={ title }
title={title}
titleText="Settings"
search={ false }
loading={ this.store.isFetching }
search={false}
loading={this.store.isFetching}
>
<CenteredContent>
{ showSlackSettings && (
<div className={ styles.section }>
<h2 className={ styles.sectionHeader }>Slack</h2>
{showSlackSettings &&
<div className={styles.section}>
<h2 className={styles.sectionHeader}>Slack</h2>
<p>
Connect Atlas to your Slack to instantly search for your documents
using <code>/atlas</code> command.
</p>
<SlackAuthLink
scopes={ ['commands'] }
redirectUri={ `${URL}/auth/slack/commands` }
scopes={['commands']}
redirectUri={`${URL}/auth/slack/commands`}
>
<img alt="Add to Slack" height="40" width="139" src="https://platform.slack-edge.com/img/add_to_slack.png" srcSet="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x" />
<img
alt="Add to Slack"
height="40"
width="139"
src="https://platform.slack-edge.com/img/add_to_slack.png"
srcSet="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x"
/>
</SlackAuthLink>
</div>
) }
</div>}
<div className={ styles.section }>
<h2 className={ styles.sectionHeader }>API access</h2>
<div className={styles.section}>
<h2 className={styles.sectionHeader}>API access</h2>
<p>
Create API tokens to hack on your Atlas.
Learn more in <a href>API documentation</a>.
</p>
{ this.store.apiKeys && (
<table className={ styles.apiKeyTable }>
{ this.store.apiKeys.map(key => (
{this.store.apiKeys &&
<table className={styles.apiKeyTable}>
{this.store.apiKeys.map(key => (
<ApiKeyRow
id={ key.id }
name={ key.name }
secret={ key.secret }
onDelete={ this.store.deleteApiKey }
id={key.id}
name={key.name}
secret={key.secret}
onDelete={this.store.deleteApiKey}
/>
)) }
</table>
) }
))}
</table>}
<div>
<InlineForm
@ -86,11 +89,11 @@ class Settings extends React.Component {
buttonLabel="Create token"
label="InlineForm"
name="inline_form"
value={ this.store.keyName }
onChange={ this.store.setKeyName }
onClick={ this.onKeyCreate }
value={this.store.keyName}
onChange={this.store.setKeyName}
onClick={this.onKeyCreate}
style={{ width: '100%' }}
disabled={ this.store.isFetching }
disabled={this.store.isFetching}
/>
</div>

View File

@ -17,10 +17,10 @@ class SearchStore {
this.apiKeys = data;
});
} catch (e) {
console.error("Something went wrong");
console.error('Something went wrong');
}
this.isFetching = false;
}
};
@action createApiKey = async () => {
this.isFetching = true;
@ -35,12 +35,12 @@ class SearchStore {
this.keyName = '';
});
} catch (e) {
console.error("Something went wrong");
console.error('Something went wrong');
}
this.isFetching = false;
}
};
@action deleteApiKey = async (id) => {
@action deleteApiKey = async id => {
this.isFetching = true;
try {
@ -51,14 +51,14 @@ class SearchStore {
this.fetchApiKeys();
});
} catch (e) {
console.error("Something went wrong");
console.error('Something went wrong');
}
this.isFetching = false;
}
};
@action setKeyName = (value) => {
@action setKeyName = value => {
this.keyName = value.target.value;
}
};
constructor() {
this.fetchApiKeys();

View File

@ -10,37 +10,34 @@ class ApiKeyRow extends React.Component {
name: PropTypes.string.isRequired,
secret: PropTypes.string.isRequired,
onDelete: PropTypes.func.isRequired,
}
};
state = {
disabled: false,
}
};
onClick = () => {
this.props.onDelete(this.props.id);
this.setState({ disabled: true });
}
};
render() {
const {
name,
secret,
} = this.props;
const { name, secret } = this.props;
const {
disabled,
} = this.state;
const { disabled } = this.state;
return (
<tr>
<td>{ name }</td>
<td><code>{ secret }</code></td>
<td>{name}</td>
<td><code>{secret}</code></td>
<td>
<span
role="button"
onClick={ this.onClick }
className={ cx(styles.deleteAction, { disabled }) }
>Delete</span>
onClick={this.onClick}
className={cx(styles.deleteAction, { disabled })}
>
Delete
</span>
</td>
</tr>
);

View File

@ -31,7 +31,6 @@ class SlackAuth extends React.Component {
browserHistory.replace('/dashboard');
} catch (e) {
browserHistory.push('/auth-error');
return;
}
} else {
// Regular Slack authentication

View File

@ -1,6 +1,6 @@
export default (type, ...argNames) => {
return function(...args) {
let action = { type };
const action = { type };
argNames.forEach((arg, index) => {
action[argNames[index]] = args[index];
});

View File

@ -1,5 +1,5 @@
{
"name": "BeautifulAtlas",
"name": "Atlas",
"private": true,
"main": "index.js",
"scripts": {
@ -10,7 +10,6 @@
"start": "node index.js",
"dev": "cross-env NODE_ENV=development DEBUG=sql,cache,presenters ./node_modules/.bin/nodemon --watch server index.js",
"lint": "eslint frontend",
"prettier": "prettier --single-quote --trailing-comma es5 --write frontend/**/*.js server/**/*.js",
"deploy": "git push heroku master",
"heroku-postbuild": "npm run build && npm run sequelize db:migrate",
"sequelize": "./node_modules/.bin/sequelize",
@ -21,7 +20,7 @@
},
"lint-staged": {
"*.js": [
"yarn prettier",
"eslint --fix",
"git add"
]
},
@ -51,7 +50,7 @@
]
},
"engines": {
"node": "6.x"
"node": ">= 7.6"
},
"repository": {
"type": "git",
@ -79,10 +78,12 @@
"dotenv": "^4.0.0",
"emoji-name-map": "1.1.2",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^14.1.0",
"eslint-config-react-app": "^0.6.2",
"eslint-import-resolver-webpack": "^0.3.1",
"eslint-plugin-flowtype": "^2.32.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-prettier": "^2.0.1",
"eslint-plugin-react": "^6.10.3",
"exports-loader": "0.6.3",
"extract-text-webpack-plugin": "1.0.1",
@ -155,8 +156,6 @@
"devDependencies": {
"babel-jest": "^15.0.0",
"enzyme": "^2.4.1",
"eslint-config-prettier": "^1.7.0",
"eslint-plugin-prettier": "^2.0.1",
"fetch-test-server": "^1.1.0",
"identity-obj-proxy": "^3.0.0",
"ignore-loader": "0.1.1",

View File

@ -2640,21 +2640,9 @@ escope@^3.6.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-config-airbnb-base@^11.1.0:
version "11.1.3"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.1.3.tgz#0e8db71514fa36b977fbcf977c01edcf863e0cf0"
eslint-config-airbnb@^14.1.0:
version "14.1.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-14.1.0.tgz#355d290040bbf8e00bf8b4b19f4b70cbe7c2317f"
dependencies:
eslint-config-airbnb-base "^11.1.0"
eslint-config-prettier@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-1.7.0.tgz#cda3ce22df1e852daa9370f1f3446e8b8a02ce44"
dependencies:
get-stdin "^5.0.1"
eslint-config-react-app@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-0.6.2.tgz#ee535cbaaf9e3576ea16b99afe720353d8730ec0"
eslint-import-resolver-node@^0.2.0:
version "0.2.3"
@ -2684,6 +2672,12 @@ eslint-module-utils@^2.0.0:
debug "2.2.0"
pkg-dir "^1.0.0"
eslint-plugin-flowtype@^2.32.1:
version "2.32.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.32.1.tgz#bbee185dedf97e5f63ec975cdcddd199bd2a2501"
dependencies:
lodash "^4.15.0"
eslint-plugin-import@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e"
@ -3230,7 +3224,7 @@ get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-stdin@5.0.1, get-stdin@^5.0.1:
get-stdin@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
@ -5259,7 +5253,7 @@ lodash@4.12.0:
version "4.12.0"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.12.0.tgz#2bd6dc46a040f59e686c972ed21d93dc59053258"
lodash@^4.0.0, lodash@^4.1.0, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1:
lodash@^4.0.0, lodash@^4.1.0, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"