mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
restructure DONE
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,7 +1,4 @@
|
|||||||
build/
|
|
||||||
node_modules/
|
|
||||||
electron_build/
|
|
||||||
.env
|
.env
|
||||||
dist/
|
node_modules/*
|
||||||
vendor/
|
!node_modules/boost
|
||||||
Boost-darwin-x64/
|
Boost-darwin-x64/
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var BrowserWindow = require('browser-window')
|
var BrowserWindow = require('browser-window')
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
var mainWindow = new BrowserWindow({
|
var mainWindow = new BrowserWindow({
|
||||||
width: 1080,
|
width: 1080,
|
||||||
@@ -10,7 +11,9 @@ var mainWindow = new BrowserWindow({
|
|||||||
'standard-window': false
|
'standard-window': false
|
||||||
})
|
})
|
||||||
|
|
||||||
mainWindow.loadUrl('file://' + __dirname + '/browser/main/index.html')
|
var url = path.resolve(__dirname, '../browser/main/index.html')
|
||||||
|
|
||||||
|
mainWindow.loadUrl('file://' + url)
|
||||||
|
|
||||||
mainWindow.setVisibleOnAllWorkspaces(true)
|
mainWindow.setVisibleOnAllWorkspaces(true)
|
||||||
|
|
||||||
11
bower.json
11
bower.json
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "codexen-app",
|
|
||||||
"dependencies": {
|
|
||||||
"react": "~0.13.3",
|
|
||||||
"fontawesome": "~4.3.0",
|
|
||||||
"react-router": "~0.13.3",
|
|
||||||
"reflux": "~0.2.8",
|
|
||||||
"moment": "~2.10.3",
|
|
||||||
"markdown-it": "~4.3.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var ExternalLink = require('../Mixins/ExternalLink')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ExternalLink, KeyCaster('aboutModal')],
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var version = global.version
|
|
||||||
return (
|
|
||||||
<div className='PreferencesModal sideNavModal modal'>
|
|
||||||
<div className='about1'>
|
|
||||||
<img className='logo' src='resources/favicon-230x230.png'/>
|
|
||||||
<div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='about2'>
|
|
||||||
<div className='externalLabel'>External links</div>
|
|
||||||
<ul className='externalList'>
|
|
||||||
<li><a onClick={this.openExternal} href='http://b00st.io'>Boost Homepage <i className='fa fa-external-link'/></a></li>
|
|
||||||
<li><a>Regulation <i className='fa fa-external-link'/></a></li>
|
|
||||||
<li><a>Private policy <i className='fa fa-external-link'/></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var Select = require('react-select')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var getOptions = function (input, callback) {
|
|
||||||
Hq.searchUser(input)
|
|
||||||
.then(function (res) {
|
|
||||||
callback(null, {
|
|
||||||
options: res.body.map(function (user) {
|
|
||||||
return {
|
|
||||||
label: user.name,
|
|
||||||
value: user.name
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
complete: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('addMemberModal')],
|
|
||||||
propTypes: {
|
|
||||||
team: React.PropTypes.object,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
userName: '',
|
|
||||||
role: 'member'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
case 'submitAddMemberModal':
|
|
||||||
this.handleSubmit()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit: function () {
|
|
||||||
this.setState({errorMessage: null}, function () {
|
|
||||||
Hq
|
|
||||||
.addMember(this.props.team.name, {
|
|
||||||
userName: this.state.userName,
|
|
||||||
role: this.state.role
|
|
||||||
})
|
|
||||||
.then(function (res) {
|
|
||||||
console.log(res.body)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
if (err.status === 403) {
|
|
||||||
this.setState({errorMessage: err.response.body.message})
|
|
||||||
}
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleChange: function (value) {
|
|
||||||
this.setState({userName: value})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='AddMemberModal modal'>
|
|
||||||
<Select
|
|
||||||
name='userName'
|
|
||||||
value={this.state.userName}
|
|
||||||
placeholder='Username to add'
|
|
||||||
asyncOptions={getOptions}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
className='userNameSelect'
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className='formField'>
|
|
||||||
Add member as
|
|
||||||
<select valueLink={this.linkState('role')}>
|
|
||||||
<option value={'member'}>Member</option>
|
|
||||||
<option value={'owner'}>Owner</option>
|
|
||||||
</select>
|
|
||||||
role
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.state.errorMessage != null ? (<p className='errorAlert'>{this.state.errorMessage}</p>) : null}
|
|
||||||
|
|
||||||
<button onClick={this.handleSubmit} className='submitButton'><i className='fa fa-check'/></button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var moment = require('moment')
|
|
||||||
var _ = require('lodash')
|
|
||||||
|
|
||||||
var CodeEditor = require('./CodeEditor')
|
|
||||||
var MarkdownPreview = require('./MarkdownPreview')
|
|
||||||
var ModeIcon = require('./ModeIcon')
|
|
||||||
var Select = require('react-select')
|
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
|
||||||
var ForceUpdate = require('../Mixins/ForceUpdate')
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
|
|
||||||
var aceModes = require('../../../modules/ace-modes')
|
|
||||||
|
|
||||||
var modeOptions = aceModes.map(function (mode) {
|
|
||||||
return {
|
|
||||||
label: mode,
|
|
||||||
value: mode
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ForceUpdate(60000), Modal, LinkedState],
|
|
||||||
propTypes: {
|
|
||||||
currentArticle: React.PropTypes.object,
|
|
||||||
showOnlyWithTag: React.PropTypes.func,
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
switchDetailMode: React.PropTypes.func,
|
|
||||||
user: React.PropTypes.shape({
|
|
||||||
id: React.PropTypes.number,
|
|
||||||
name: React.PropTypes.string,
|
|
||||||
Folders: React.PropTypes.array
|
|
||||||
}),
|
|
||||||
article: React.PropTypes.object,
|
|
||||||
saveCurrentArticle: React.PropTypes.func,
|
|
||||||
detailMode: React.PropTypes.string
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var article = this.props.currentArticle != null ? {
|
|
||||||
id: this.props.currentArticle.id,
|
|
||||||
title: this.props.currentArticle.title,
|
|
||||||
content: this.props.currentArticle.CurrentRevision.title,
|
|
||||||
tags: this.props.currentArticle.Tags.map(function (tag) {
|
|
||||||
return tag.name
|
|
||||||
}),
|
|
||||||
mode: this.props.currentArticle.mode,
|
|
||||||
status: this.props.currentArticle.status
|
|
||||||
} : null
|
|
||||||
// console.log('init staet')
|
|
||||||
// console.log(article)
|
|
||||||
return {
|
|
||||||
isEditModalOpen: false,
|
|
||||||
article: article
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentWillReceiveProps: function (nextProps) {
|
|
||||||
if (nextProps.detailMode === 'edit') {
|
|
||||||
var article = {
|
|
||||||
id: nextProps.currentArticle.id,
|
|
||||||
title: nextProps.currentArticle.title,
|
|
||||||
content: nextProps.currentArticle.CurrentRevision.content,
|
|
||||||
tags: nextProps.currentArticle.Tags.map(function (tag) {
|
|
||||||
return tag.name
|
|
||||||
}),
|
|
||||||
mode: nextProps.currentArticle.mode,
|
|
||||||
FolderId: nextProps.currentArticle.FolderId,
|
|
||||||
status: nextProps.currentArticle.status
|
|
||||||
}
|
|
||||||
this.setState({article: article})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openDeleteModal: function () {
|
|
||||||
if (this.props.article == null) return
|
|
||||||
},
|
|
||||||
handleFolderIdChange: function (FolderId) {
|
|
||||||
this.state.article.FolderId = FolderId
|
|
||||||
this.setState({article: this.state.article})
|
|
||||||
},
|
|
||||||
handleTagsChange: function (tag, tags) {
|
|
||||||
tags = _.uniq(tags, function (tag) {
|
|
||||||
return tag.value
|
|
||||||
})
|
|
||||||
|
|
||||||
this.state.article.tags = tags.map(function (tag) {
|
|
||||||
return tag.value
|
|
||||||
})
|
|
||||||
this.setState({article: this.state.article})
|
|
||||||
},
|
|
||||||
handleModeChange: function (mode) {
|
|
||||||
this.state.article.mode = mode
|
|
||||||
this.setState({article: this.state.article})
|
|
||||||
},
|
|
||||||
handleContentChange: function (e, value) {
|
|
||||||
var article = this.state.article
|
|
||||||
article.content = value
|
|
||||||
this.setState({article: article})
|
|
||||||
},
|
|
||||||
saveArticle: function () {
|
|
||||||
if (this.state.article.mode === '') {
|
|
||||||
return this.refs.mode.focus()
|
|
||||||
}
|
|
||||||
if (this.state.article.FolderId === '') {
|
|
||||||
return this.refs.folder.focus()
|
|
||||||
}
|
|
||||||
this.props.saveCurrentArticle(this.state.article)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
if (this.props.currentArticle == null) {
|
|
||||||
return (
|
|
||||||
<div className='ArticleDetail'>
|
|
||||||
Nothing selected
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.detailMode === 'show') {
|
|
||||||
return this.renderViewer()
|
|
||||||
}
|
|
||||||
if (this.state.article == null) {
|
|
||||||
return (
|
|
||||||
<div className='ArticleDetail'>
|
|
||||||
Nothing selected
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return this.renderEditor()
|
|
||||||
},
|
|
||||||
renderEditor: function () {
|
|
||||||
var article = this.state.article
|
|
||||||
|
|
||||||
var folderOptions = this.props.user.Folders.map(function (folder) {
|
|
||||||
return {
|
|
||||||
label: folder.name,
|
|
||||||
value: folder.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='ArticleDetail edit'>
|
|
||||||
<div className='detailInfo'>
|
|
||||||
<div className='left'>
|
|
||||||
<Select ref='folder' onChange={this.handleFolderIdChange} clearable={false} options={folderOptions} placeholder='select folder...' value={article.FolderId} className='folder'/>
|
|
||||||
<Select onChange={this.handleTagsChange} clearable={false} multi={true} placeholder='add some tags...' allowCreate={true} value={article.tags} className='tags'/>
|
|
||||||
</div>
|
|
||||||
<div className='right'>
|
|
||||||
<button onClick={this.props.switchDetailMode('show')}>Cancel</button>
|
|
||||||
<button onClick={this.saveArticle} className='primary'>Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='detailBody'>
|
|
||||||
<div className='detailPanel'>
|
|
||||||
<div className='header'>
|
|
||||||
<div className='title'>
|
|
||||||
<input ref='title' valueLink={this.linkState('article.title')}/>
|
|
||||||
</div>
|
|
||||||
<Select ref='mode' onChange={this.handleModeChange} clearable={false} options={modeOptions}placeholder='select mode...' value={article.mode} className='mode'/>
|
|
||||||
</div>
|
|
||||||
<CodeEditor onChange={this.handleContentChange} mode={article.mode} code={article.content}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderViewer: function () {
|
|
||||||
var article = this.props.currentArticle
|
|
||||||
var tags = article.Tags.length > 0 ? article.Tags.map(function (tag) {
|
|
||||||
return (
|
|
||||||
<a key={tag.id}>{tag.name}</a>
|
|
||||||
)
|
|
||||||
}) : (
|
|
||||||
<span className='noTags'>Not tagged yet</span>
|
|
||||||
)
|
|
||||||
|
|
||||||
var folder = _.findWhere(this.props.user.Folders, {id: article.FolderId})
|
|
||||||
var folderName = folder != null ? folder.name : null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='ArticleDetail show'>
|
|
||||||
<div className='detailInfo'>
|
|
||||||
<div className='left'>
|
|
||||||
<div className='info'>
|
|
||||||
<i className='fa fa-fw fa-square'/> {folderName}
|
|
||||||
by {article.User.profileName}
|
|
||||||
Created {moment(article.createdAt).format('YYYY/MM/DD')}
|
|
||||||
Updated {moment(article.updatedAt).format('YYYY/MM/DD')}
|
|
||||||
</div>
|
|
||||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='right'>
|
|
||||||
<button onClick={this.props.switchDetailMode('edit')}><i className='fa fa-fw fa-edit'/></button>
|
|
||||||
<button><i className='fa fa-fw fa-trash'/></button>
|
|
||||||
<button><i className='fa fa-fw fa-share-alt'/></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='detailBody'>
|
|
||||||
<div className='detailPanel'>
|
|
||||||
<div className='header'>
|
|
||||||
<ModeIcon className='mode' mode={article.mode}/>
|
|
||||||
<div className='title'>{article.title}</div>
|
|
||||||
</div>
|
|
||||||
{article.mode === 'markdown' ? <MarkdownPreview content={article.CurrentRevision.content}/> : <CodeEditor readOnly={true} onChange={this.handleContentChange} mode={article.mode} code={article.CurrentRevision.content}/>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var moment = require('moment')
|
|
||||||
var _ = require('lodash')
|
|
||||||
|
|
||||||
var ForceUpdate = require('../Mixins/ForceUpdate')
|
|
||||||
var Markdown = require('../Mixins/Markdown')
|
|
||||||
|
|
||||||
var ProfileImage = require('../Components/ProfileImage')
|
|
||||||
var ModeIcon = require('../Components/ModeIcon')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ReactRouter.Navigation, ReactRouter.State, ForceUpdate(60000), Markdown],
|
|
||||||
propTypes: {
|
|
||||||
articles: React.PropTypes.array
|
|
||||||
},
|
|
||||||
handleArticleClick: function (article) {
|
|
||||||
return function () {
|
|
||||||
this.props.selectArticle(article.id)
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var articles = this.props.articles.map(function (article) {
|
|
||||||
if (article == null) return null
|
|
||||||
var tags = _.isArray(article.Tags) && article.Tags.length > 0 ? article.Tags.map(function (tag) {
|
|
||||||
return (
|
|
||||||
<a key={tag.id}>#{tag.name}</a>
|
|
||||||
)
|
|
||||||
}.bind(this)) : (
|
|
||||||
<span>Not tagged yet</span>
|
|
||||||
)
|
|
||||||
var params = this.getParams()
|
|
||||||
var isActive = this.props.currentArticle.id === article.id
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li key={'article-' + article.id}>
|
|
||||||
<div onClick={this.handleArticleClick(article)} className={'articleItem' + (isActive ? ' active' : '')}>
|
|
||||||
<div className='top'>
|
|
||||||
<i className='fa fa-fw fa-square'/>
|
|
||||||
by <ProfileImage className='profileImage' size='20' email={article.User.email}/> {article.User.profileName}
|
|
||||||
<span className='updatedAt'>{article.status != null ? article.status : moment(article.updatedAt).fromNow()}</span>
|
|
||||||
</div>
|
|
||||||
<div className='middle'>
|
|
||||||
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{article.status !== 'new' ? article.title : '(New article)'}</div>
|
|
||||||
</div>
|
|
||||||
<div className='bottom'>
|
|
||||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='divider'></div>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}.bind(this))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='ArticleList'>
|
|
||||||
<ul ref='articles'>
|
|
||||||
{articles}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [KeyCaster('codeDeleteModal')],
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
code: React.PropTypes.object,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'submitCodeDeleteModal':
|
|
||||||
this.submit()
|
|
||||||
break
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
submit: function () {
|
|
||||||
var planet = this.props.planet
|
|
||||||
Hq.destroyCode(planet.Owner.name, planet.name, this.props.code.localId)
|
|
||||||
.then(function (res) {
|
|
||||||
PlanetStore.Actions.destroyCode(res.body)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='CodeDeleteModal modal'>
|
|
||||||
<div className='modal-header'>
|
|
||||||
<h1>Delete Code</h1>
|
|
||||||
</div>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<p>Are you sure to delete it?</p>
|
|
||||||
</div>
|
|
||||||
<div className='modal-footer'>
|
|
||||||
<div className='modal-control'>
|
|
||||||
<button onClick={this.props.close} className='btn-default'>Cancel</button>
|
|
||||||
<button ref='submit' onClick={this.submit} className='btn-primary'>Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var CodeForm = require('./CodeForm')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func,
|
|
||||||
code: React.PropTypes.object,
|
|
||||||
planet: React.PropTypes.object
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
// TODO: Hacked!! should fix later
|
|
||||||
setTimeout(function () {
|
|
||||||
React.findDOMNode(this.refs.form.refs.description).focus()
|
|
||||||
}.bind(this), 1)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='CodeEditModal modal'>
|
|
||||||
<div className='modal-header'>
|
|
||||||
<h1>Edit Code</h1>
|
|
||||||
</div>
|
|
||||||
<CodeForm ref='form' code={this.props.code} planet={this.props.planet} close={this.props.close}/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var CodeEditor = require('./CodeEditor')
|
|
||||||
var Select = require('react-select')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
var aceModes = require('../../../modules/ace-modes')
|
|
||||||
|
|
||||||
var getOptions = function (input, callback) {
|
|
||||||
Hq.searchTag(input)
|
|
||||||
.then(function (res) {
|
|
||||||
callback(null, {
|
|
||||||
options: res.body.map(function (tag) {
|
|
||||||
return {
|
|
||||||
label: tag.name,
|
|
||||||
value: tag.name
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
complete: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('codeForm')],
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
close: React.PropTypes.func,
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
code: React.PropTypes.object
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var code = Object.assign({
|
|
||||||
description: '',
|
|
||||||
mode: '',
|
|
||||||
content: '',
|
|
||||||
Tags: []
|
|
||||||
}, this.props.code)
|
|
||||||
|
|
||||||
code.Tags = code.Tags.map(function (tag) {
|
|
||||||
return {
|
|
||||||
label: tag.name,
|
|
||||||
value: tag.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: code
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'submitCodeForm':
|
|
||||||
this.submit()
|
|
||||||
break
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleModeChange: function (selected) {
|
|
||||||
var code = this.state.code
|
|
||||||
code.mode = selected
|
|
||||||
this.setState({code: code})
|
|
||||||
},
|
|
||||||
handleTagsChange: function (selected, all) {
|
|
||||||
var code = this.state.code
|
|
||||||
code.Tags = all
|
|
||||||
this.setState({code: code})
|
|
||||||
},
|
|
||||||
handleContentChange: function (e, value) {
|
|
||||||
var code = this.state.code
|
|
||||||
code.content = value
|
|
||||||
this.setState({code: code})
|
|
||||||
},
|
|
||||||
submit: function () {
|
|
||||||
var planet = this.props.planet
|
|
||||||
var code = this.state.code
|
|
||||||
code.Tags = code.Tags.map(function (tag) {
|
|
||||||
return tag.value
|
|
||||||
})
|
|
||||||
if (this.props.code == null) {
|
|
||||||
Hq.createCode(planet.Owner.name, planet.name, this.state.code)
|
|
||||||
.then(function (res) {
|
|
||||||
var code = res.body
|
|
||||||
PlanetStore.Actions.updateCode(code)
|
|
||||||
this.props.close()
|
|
||||||
this.props.transitionTo('codes', {userName: planet.Owner.name, planetName: planet.name, localId: code.localId})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Hq.updateCode(planet.Owner.name, planet.name, this.props.code.localId, this.state.code)
|
|
||||||
.then(function (res) {
|
|
||||||
var code = res.body
|
|
||||||
PlanetStore.Actions.updateCode(code)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleKeyDown: function (e) {
|
|
||||||
if (e.keyCode === 13 && e.metaKey) {
|
|
||||||
this.submit()
|
|
||||||
e.stopPropagation()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var modeOptions = aceModes.map(function (mode) {
|
|
||||||
return {
|
|
||||||
label: mode,
|
|
||||||
value: mode
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return (
|
|
||||||
<div className='CodeForm'>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<div className='form-group'>
|
|
||||||
<textarea ref='description' className='codeDescription block-input' valueLink={this.linkState('code.description')} placeholder='Description'/>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<Select
|
|
||||||
name='mode'
|
|
||||||
className='modeSelect'
|
|
||||||
value={this.state.code.mode}
|
|
||||||
placeholder='Select Language'
|
|
||||||
options={modeOptions}
|
|
||||||
onChange={this.handleModeChange}/>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<CodeEditor onChange={this.handleContentChange} code={this.state.code.content} mode={this.state.code.mode}/>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<Select
|
|
||||||
name='Tags'
|
|
||||||
multi={true}
|
|
||||||
allowCreate={true}
|
|
||||||
value={this.state.code.Tags}
|
|
||||||
placeholder='Tags...'
|
|
||||||
asyncOptions={getOptions}
|
|
||||||
onChange={this.handleTagsChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='modal-footer'>
|
|
||||||
<div className='modal-control'>
|
|
||||||
<button onClick={this.props.close} className='btn-default'>Cancel</button>
|
|
||||||
<button onClick={this.submit} className='btn-primary'>{this.props.code == null ? 'Launch' : 'Relaunch'}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var ace = window.ace
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
code: React.PropTypes.string,
|
|
||||||
mode: React.PropTypes.string,
|
|
||||||
className: React.PropTypes.string
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
var el = React.findDOMNode(this.refs.target)
|
|
||||||
var editor = ace.edit(el)
|
|
||||||
editor.$blockScrolling = Infinity
|
|
||||||
editor.setValue(this.props.code)
|
|
||||||
editor.renderer.setShowGutter(false)
|
|
||||||
editor.setReadOnly(true)
|
|
||||||
editor.setTheme('ace/theme/xcode')
|
|
||||||
editor.setHighlightActiveLine(false)
|
|
||||||
editor.clearSelection()
|
|
||||||
|
|
||||||
var session = editor.getSession()
|
|
||||||
if (this.props.mode != null && this.props.mode.length > 0) {
|
|
||||||
session.setMode('ace/mode/' + this.props.mode)
|
|
||||||
} else {
|
|
||||||
session.setMode('ace/mode/text')
|
|
||||||
}
|
|
||||||
session.setUseSoftTabs(true)
|
|
||||||
session.setOption('useWorker', false)
|
|
||||||
session.setUseWrapMode(true)
|
|
||||||
|
|
||||||
this.setState({editor: editor})
|
|
||||||
},
|
|
||||||
componentDidUpdate: function (prevProps) {
|
|
||||||
if (this.state.editor.getValue() !== this.props.code) {
|
|
||||||
this.state.editor.setValue(this.props.code)
|
|
||||||
this.state.editor.clearSelection()
|
|
||||||
}
|
|
||||||
if (prevProps.mode !== this.props.mode) {
|
|
||||||
var session = this.state.editor.getSession()
|
|
||||||
if (this.props.mode != null && this.props.mode.length > 0) {
|
|
||||||
session.setMode('ace/mode/' + this.props.mode)
|
|
||||||
} else {
|
|
||||||
session.setMode('ace/mode/text')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div ref='target' className={this.props.className}></div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('editProfileModal')],
|
|
||||||
propTypes: {
|
|
||||||
user: React.PropTypes.shape({
|
|
||||||
name: React.PropTypes.string,
|
|
||||||
profileName: React.PropTypes.string,
|
|
||||||
email: React.PropTypes.string
|
|
||||||
}),
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var user = this.props.user
|
|
||||||
return {
|
|
||||||
currentTab: 'userInfo',
|
|
||||||
user: {
|
|
||||||
profileName: user.profileName,
|
|
||||||
email: user.email
|
|
||||||
},
|
|
||||||
userSubmitStatus: null,
|
|
||||||
password: {
|
|
||||||
currentPassword: '',
|
|
||||||
newPassword: '',
|
|
||||||
passwordConfirmation: ''
|
|
||||||
},
|
|
||||||
passwordSubmitStatus: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectTab: function (tabName) {
|
|
||||||
return function () {
|
|
||||||
this.setState({currentTab: tabName})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
saveUserInfo: function () {
|
|
||||||
this.setState({
|
|
||||||
userSubmitStatus: 'sending'
|
|
||||||
}, function () {
|
|
||||||
Hq.updateUser(this.props.user.name, this.state.user)
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({userSubmitStatus: 'done'}, function () {
|
|
||||||
localStorage.setItem('currentUser', JSON.stringify(res.body))
|
|
||||||
UserStore.Actions.update(res.body)
|
|
||||||
})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({userSubmitStatus: 'error'})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
savePassword: function () {
|
|
||||||
this.setState({
|
|
||||||
passwordSubmitStatus: 'sending'
|
|
||||||
}, function () {
|
|
||||||
Hq.changePassword(this.state.password)
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({
|
|
||||||
passwordSubmitStatus: 'done',
|
|
||||||
currentPassword: '',
|
|
||||||
newPassword: '',
|
|
||||||
passwordConfirmation: ''
|
|
||||||
})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({
|
|
||||||
passwordSubmitStatus: 'error',
|
|
||||||
currentPassword: '',
|
|
||||||
newPassword: '',
|
|
||||||
passwordConfirmation: ''
|
|
||||||
})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var content
|
|
||||||
|
|
||||||
switch (this.state.currentTab) {
|
|
||||||
case 'userInfo':
|
|
||||||
content = this.renderUserInfoTab()
|
|
||||||
break
|
|
||||||
case 'password':
|
|
||||||
content = this.renderPasswordTab()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='EditProfileModal sideNavModal modal'>
|
|
||||||
<div className='leftPane'>
|
|
||||||
<div className='modalLabel'>Edit profile</div>
|
|
||||||
<div className='tabList'>
|
|
||||||
<button className={this.state.currentTab === 'userInfo' ? 'active' : ''} onClick={this.selectTab('userInfo')}><i className='fa fa-user fa-fw'/> User Info</button>
|
|
||||||
<button className={this.state.currentTab === 'password' ? 'active' : ''} onClick={this.selectTab('password')}><i className='fa fa-lock fa-fw'/> Password</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='rightPane'>
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderUserInfoTab: function () {
|
|
||||||
return (
|
|
||||||
<div className='userInfoTab tab'>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Profile Name</label>
|
|
||||||
<input valueLink={this.linkState('user.profileName')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>E-mail</label>
|
|
||||||
<input valueLink={this.linkState('user.email')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button disabled={this.state.userSubmitStatus === 'sending'} onClick={this.saveUserInfo}>Save</button>
|
|
||||||
|
|
||||||
<div className={'alertInfo' + (this.state.userSubmitStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
|
|
||||||
|
|
||||||
<div className={'alertError' + (this.state.userSubmitStatus === 'error' ? '' : ' hide')}>Connection failed.. Try again.</div>
|
|
||||||
|
|
||||||
<div className={'alertSuccess' + (this.state.userSubmitStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderPasswordTab: function () {
|
|
||||||
return (
|
|
||||||
<div className='passwordTab tab'>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Current password</label>
|
|
||||||
<input type='password' valueLink={this.linkState('password.currentPassword')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>New password</label>
|
|
||||||
<input type='password' valueLink={this.linkState('password.newPassword')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Confirmation</label>
|
|
||||||
<input type='password' valueLink={this.linkState('password.passwordConfirmation')}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button disabled={this.state.password.newPassword.length === 0 || this.state.password.newPassword !== this.state.password.passwordConfirmation || this.state.passwordSubmitStatus === 'sending'} onClick={this.savePassword}>Save</button>
|
|
||||||
|
|
||||||
<div className={'alertInfo' + (this.state.passwordSubmitStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
|
|
||||||
|
|
||||||
<div className={'alertError' + (this.state.passwordSubmitStatus === 'error' ? '' : ' hide')}>Connection failed.. Try again.</div>
|
|
||||||
|
|
||||||
<div className={'alertSuccess' + (this.state.passwordSubmitStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var Navigation = ReactRouter.Navigation
|
|
||||||
var State = ReactRouter.State
|
|
||||||
var Link = ReactRouter.Link
|
|
||||||
var Reflux = require('reflux')
|
|
||||||
var _ = require('lodash')
|
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
|
||||||
|
|
||||||
var PreferencesModal = require('./PreferencesModal')
|
|
||||||
var PlanetCreateModal = require('./PlanetCreateModal')
|
|
||||||
var TeamCreateModal = require('./TeamCreateModal')
|
|
||||||
var LogoutModal = require('./LogoutModal')
|
|
||||||
var ProfileImage = require('./ProfileImage')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [Navigation, State, Reflux.listenTo(UserStore, 'onUserChange'), Modal],
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
isPlanetCreateModalOpen: false,
|
|
||||||
currentUser: JSON.parse(localStorage.getItem('currentUser'))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onUserChange: function (res) {
|
|
||||||
switch (res.status) {
|
|
||||||
case 'userUpdated':
|
|
||||||
var user = res.data
|
|
||||||
var currentUser = this.state.currentUser
|
|
||||||
if (currentUser.id === user.id) {
|
|
||||||
this.setState({currentUser: user})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.userType === 'team') {
|
|
||||||
var isMyTeam = user.Members.some(function (member) {
|
|
||||||
if (currentUser.id === member.id) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isMyTeam) {
|
|
||||||
var isNew = !currentUser.Teams.some(function (team, index) {
|
|
||||||
if (user.id === team.id) {
|
|
||||||
currentUser.Teams.splice(index, 1, user)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isNew) {
|
|
||||||
currentUser.Teams.push(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({currentUser: currentUser})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openTeamCreateModal: function () {
|
|
||||||
this.openModal(TeamCreateModal, {user: this.state.currentUser, transitionTo: this.transitionTo})
|
|
||||||
},
|
|
||||||
handleLogoutClick: function () {
|
|
||||||
this.openModal(LogoutModal, {transitionTo: this.transitionTo})
|
|
||||||
},
|
|
||||||
switchUserByIndex: function (index) {
|
|
||||||
var userProp = this.refs.users.props.children[index - 1].props
|
|
||||||
this.transitionTo('user', {userId: userProp.id})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var params = this.getParams()
|
|
||||||
|
|
||||||
if (this.state.currentUser == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
console.log(this.state.currentUser.Teams)
|
|
||||||
|
|
||||||
var users = [this.state.currentUser]
|
|
||||||
if (_.isArray(this.state.currentUser.Teams)) users = users.concat(this.state.currentUser.Teams)
|
|
||||||
|
|
||||||
var userButtons = users.map(function (user, index) {
|
|
||||||
return (
|
|
||||||
<li key={'user-' + user.id}>
|
|
||||||
<Link to='user' params={{userId: user.id}}>
|
|
||||||
{user.userType === 'person' ? (<ProfileImage email={user.email} size='44'/>): user.name[0]}
|
|
||||||
<div className='userTooltip'>{user.name}</div>
|
|
||||||
</Link>
|
|
||||||
{index < 9 ? (<div className='shortCut'>⌘{index + 1}</div>) : null}
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='HomeNavigator'>
|
|
||||||
<ul ref='users' className='userList'>
|
|
||||||
{userButtons}
|
|
||||||
</ul>
|
|
||||||
<button onClick={this.openTeamCreateModal} className='newTeamButton'>
|
|
||||||
<i className='fa fa-plus'/>
|
|
||||||
<div className='tooltip'>Create new team</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var CodeForm = require('./CodeForm')
|
|
||||||
var NoteForm = require('./NoteForm')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
currentTab: 'code'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
var codeButton = React.findDOMNode(this.refs.codeButton)
|
|
||||||
codeButton.addEventListener('keydown', this.handleKeyDown)
|
|
||||||
React.findDOMNode(this.refs.noteButton).addEventListener('keydown', this.handleKeyDown)
|
|
||||||
codeButton.focus()
|
|
||||||
},
|
|
||||||
componentWillUnmount: function () {
|
|
||||||
React.findDOMNode(this.refs.codeButton).removeEventListener('keydown', this.handleKeyDown)
|
|
||||||
React.findDOMNode(this.refs.noteButton).removeEventListener('keydown', this.handleKeyDown)
|
|
||||||
},
|
|
||||||
handleKeyDown: function (e) {
|
|
||||||
if (e.keyCode === 37 && e.metaKey) {
|
|
||||||
this.selectCodeTab()
|
|
||||||
e.stopPropagation()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (e.keyCode === 39 && e.metaKey) {
|
|
||||||
this.selectNoteTab()
|
|
||||||
e.stopPropagation()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (e.keyCode === 9) {
|
|
||||||
if (this.state.currentTab === 'code') React.findDOMNode(this.refs.form.refs.description).focus()
|
|
||||||
else React.findDOMNode(this.refs.form.refs.title).focus()
|
|
||||||
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectCodeTab: function () {
|
|
||||||
this.setState({currentTab: 'code'}, function () {
|
|
||||||
React.findDOMNode(this.refs.codeButton).focus()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
selectNoteTab: function () {
|
|
||||||
this.setState({currentTab: 'note'}, function () {
|
|
||||||
React.findDOMNode(this.refs.noteButton).focus()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var modalBody
|
|
||||||
if (this.state.currentTab === 'code') {
|
|
||||||
modalBody = (
|
|
||||||
<CodeForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
modalBody = (
|
|
||||||
<NoteForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='LaunchModal modal'>
|
|
||||||
<div className='modal-header'>
|
|
||||||
<div className='modal-tab'>
|
|
||||||
<button ref='codeButton' className={this.state.currentTab === 'code' ? 'btn-primary active' : 'btn-default'} onClick={this.selectCodeTab}>Code</button>
|
|
||||||
<button ref='noteButton' className={this.state.currentTab === 'note' ? 'btn-primary active' : 'btn-default'} onClick={this.selectNoteTab}>Note</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{modalBody}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var socket = require('../Services/socket')
|
|
||||||
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [KeyCaster('logoutModal')],
|
|
||||||
propTypes: {
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
case 'submitLogoutModal':
|
|
||||||
this.logout()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
logout: function () {
|
|
||||||
localStorage.removeItem('currentUser')
|
|
||||||
localStorage.removeItem('token')
|
|
||||||
socket.reconnect()
|
|
||||||
|
|
||||||
this.props.transitionTo('login')
|
|
||||||
this.props.close()
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='LogoutModal modal'>
|
|
||||||
<div className='messageLabel'>Are you sure to log out?</div>
|
|
||||||
<div className='formControl'>
|
|
||||||
<button onClick={this.props.close}>Cancel</button>
|
|
||||||
<button className='logoutButton' onClick={this.logout}>Log out</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [KeyCaster('noteDeleteModal')],
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
note: React.PropTypes.object,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'submitNoteDeleteModal':
|
|
||||||
this.submit()
|
|
||||||
break
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
submit: function () {
|
|
||||||
var planet = this.props.planet
|
|
||||||
Hq.destroyNote(planet.Owner.name, planet.name, this.props.note.localId)
|
|
||||||
.then(function (res) {
|
|
||||||
PlanetStore.Actions.destroyNote(res.body)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='NoteDeleteModal modal'>
|
|
||||||
<div className='modal-header'>
|
|
||||||
<h1>Delete Note</h1>
|
|
||||||
</div>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<p>Are you sure to delete it?</p>
|
|
||||||
</div>
|
|
||||||
<div className='modal-footer'>
|
|
||||||
<div className='modal-control'>
|
|
||||||
<button onClick={this.props.close} className='btn-default'>Cancel</button>
|
|
||||||
<button ref='submit' onClick={this.submit} className='btn-primary'>Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var NoteForm = require('./NoteForm')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func,
|
|
||||||
note: React.PropTypes.object,
|
|
||||||
planet: React.PropTypes.object
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
// TODO: Hacked!! should fix later
|
|
||||||
setTimeout(function () {
|
|
||||||
React.findDOMNode(this.refs.form.refs.title).focus()
|
|
||||||
}.bind(this), 1)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='NoteEditModal modal'>
|
|
||||||
<div className='modal-header'>
|
|
||||||
<h1>Edit Note</h1>
|
|
||||||
</div>
|
|
||||||
<NoteForm ref='form' note={this.props.note} planet={this.props.planet} close={this.props.close}/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var Select = require('react-select')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var Markdown = require('../Mixins/Markdown')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
var CodeEditor = require('./CodeEditor')
|
|
||||||
var MarkdownPreview = require('./MarkdownPreview')
|
|
||||||
|
|
||||||
var getOptions = function (input, callback) {
|
|
||||||
Hq.searchTag(input)
|
|
||||||
.then(function (res) {
|
|
||||||
callback(null, {
|
|
||||||
options: res.body.map(function (tag) {
|
|
||||||
return {
|
|
||||||
label: tag.name,
|
|
||||||
value: tag.name
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
complete: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var EDIT_MODE = 0
|
|
||||||
var PREVIEW_MODE = 1
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, Markdown, KeyCaster('noteForm')],
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.object,
|
|
||||||
close: React.PropTypes.func,
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
note: React.PropTypes.object
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var note = Object.assign({
|
|
||||||
title: '',
|
|
||||||
content: '',
|
|
||||||
Tags: []
|
|
||||||
}, this.props.note)
|
|
||||||
note.Tags = note.Tags.map(function (tag) {
|
|
||||||
return {
|
|
||||||
label: tag.name,
|
|
||||||
value: tag.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
note: note,
|
|
||||||
mode: EDIT_MODE
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'submitNoteForm':
|
|
||||||
this.submit()
|
|
||||||
break
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleTagsChange: function (selected, all) {
|
|
||||||
var note = this.state.note
|
|
||||||
note.Tags = all
|
|
||||||
this.setState({note: note})
|
|
||||||
},
|
|
||||||
handleContentChange: function (e, value) {
|
|
||||||
var note = this.state.note
|
|
||||||
note.content = value
|
|
||||||
this.setState({note: note})
|
|
||||||
},
|
|
||||||
togglePreview: function () {
|
|
||||||
this.setState({mode: this.state.mode === EDIT_MODE ? PREVIEW_MODE : EDIT_MODE})
|
|
||||||
},
|
|
||||||
submit: function () {
|
|
||||||
var planet = this.props.planet
|
|
||||||
var note = this.state.note
|
|
||||||
note.Tags = note.Tags.map(function (tag) {
|
|
||||||
return tag.value
|
|
||||||
})
|
|
||||||
|
|
||||||
if (this.props.note == null) {
|
|
||||||
Hq.createNote(planet.Owner.name, planet.name, this.state.note)
|
|
||||||
.then(function (res) {
|
|
||||||
var note = res.body
|
|
||||||
PlanetStore.Actions.updateNote(note)
|
|
||||||
this.props.close()
|
|
||||||
this.props.transitionTo('notes', {userName: planet.Owner.name, planetName: planet.name, localId: note.localId})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Hq.updateNote(planet.Owner.name, planet.name, this.props.note.localId, this.state.note)
|
|
||||||
.then(function (res) {
|
|
||||||
var note = res.body
|
|
||||||
PlanetStore.Actions.updateNote(note)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var content = this.state.mode === EDIT_MODE ? (
|
|
||||||
<div className='form-group'>
|
|
||||||
<CodeEditor onChange={this.handleContentChange} code={this.state.note.content} mode={'markdown'}/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className='form-group relative'>
|
|
||||||
<div className='previewMode'>Preview mode</div>
|
|
||||||
<MarkdownPreview className='marked' content={this.state.note.content}/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='NoteForm'>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<div className='form-group'>
|
|
||||||
<input ref='title' className='block-input' valueLink={this.linkState('note.title')} placeholder='Title'/>
|
|
||||||
</div>
|
|
||||||
{content}
|
|
||||||
<div className='form-group'>
|
|
||||||
<Select
|
|
||||||
name='Tags'
|
|
||||||
multi={true}
|
|
||||||
allowCreate={true}
|
|
||||||
value={this.state.note.Tags}
|
|
||||||
placeholder='Tags...'
|
|
||||||
asyncOptions={getOptions}
|
|
||||||
onChange={this.handleTagsChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='modal-footer'>
|
|
||||||
<button onClick={this.togglePreview} className={'btn-default' + (this.state.mode === PREVIEW_MODE ? ' active' : '')}>Preview mode</button>
|
|
||||||
<div className='modal-control'>
|
|
||||||
<button onClick={this.props.close} className='btn-default'>Cancel</button>
|
|
||||||
<button onClick={this.submit} className='btn-primary'>Launch</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/* global localStorage */
|
|
||||||
|
|
||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('planetCreateModal')],
|
|
||||||
propTypes: {
|
|
||||||
ownerName: React.PropTypes.string,
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
|
|
||||||
var ownerName = this.props.ownerName != null ? this.props.ownerName : currentUser.name
|
|
||||||
return {
|
|
||||||
user: currentUser,
|
|
||||||
planet: {
|
|
||||||
name: '',
|
|
||||||
public: true
|
|
||||||
},
|
|
||||||
ownerName: ownerName,
|
|
||||||
error: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
React.findDOMNode(this.refs.name).focus()
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
case 'submitPlanetCreateModal':
|
|
||||||
this.handleSubmit()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit: function () {
|
|
||||||
this.setState({error: null}, function () {
|
|
||||||
Hq.createPlanet(this.state.ownerName, this.state.planet)
|
|
||||||
.then(function (res) {
|
|
||||||
var planet = res.body
|
|
||||||
|
|
||||||
PlanetStore.Actions.update(planet)
|
|
||||||
|
|
||||||
if (this.props.transitionTo != null) {
|
|
||||||
this.props.transitionTo('planetHome', {userName: planet.Owner.name, planetName: planet.name})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
|
|
||||||
if (err.status == null) return this.setState({error: {message: 'Check your network connection'}})
|
|
||||||
|
|
||||||
switch (err.status) {
|
|
||||||
case 403:
|
|
||||||
this.setState({error: err.response.body})
|
|
||||||
break
|
|
||||||
case 422:
|
|
||||||
this.setState({error: {message: 'Planet name should be Alphanumeric with _, -'}})
|
|
||||||
break
|
|
||||||
case 409:
|
|
||||||
this.setState({error: {message: 'The entered name already in use'}})
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
this.setState({error: {message: 'Unexpected error occured! please try again'}})
|
|
||||||
}
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var teamOptions = this.state.user.Teams.map(function (team) {
|
|
||||||
return (
|
|
||||||
<option key={'user-' + team.id} value={team.name}>{team.profileName} ({team.name})</option>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
return (
|
|
||||||
<div className='PlanetCreateModal modal'>
|
|
||||||
<input ref='name' valueLink={this.linkState('planet.name')} className='nameInput stripInput' placeholder='Crate new Planet'/>
|
|
||||||
|
|
||||||
<div className='formField'>
|
|
||||||
of
|
|
||||||
<select valueLink={this.linkState('ownerName')}>
|
|
||||||
<option value={this.state.user.name}>Me({this.state.user.name})</option>
|
|
||||||
{teamOptions}
|
|
||||||
</select>
|
|
||||||
as
|
|
||||||
<select valueLink={this.linkState('planet.public')}>
|
|
||||||
<option value={true}>Public</option>
|
|
||||||
<option value={false}>Private</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.state.error != null ? (<p className='errorAlert'>{this.state.error.message != null ? this.state.error.message : 'Error message undefined'}</p>) : null}
|
|
||||||
|
|
||||||
<button onClick={this.handleSubmit} className='submitButton'>
|
|
||||||
<i className='fa fa-check'/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var Link = ReactRouter.Link
|
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
|
||||||
var ExternalLink = require('../Mixins/ExternalLink')
|
|
||||||
|
|
||||||
var PlanetSettingModal = require('./PlanetSettingModal')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ReactRouter.State, Modal, ExternalLink],
|
|
||||||
propTypes: {
|
|
||||||
search: React.PropTypes.string,
|
|
||||||
fetchPlanet: React.PropTypes.func,
|
|
||||||
onSearchChange: React.PropTypes.func,
|
|
||||||
currentPlanet: React.PropTypes.object
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
search: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
var search = React.findDOMNode(this.refs.search)
|
|
||||||
search.addEventListener('keydown', this.handleSearchKeyDown)
|
|
||||||
},
|
|
||||||
componentWillUnmount: function () {
|
|
||||||
var search = React.findDOMNode(this.refs.search)
|
|
||||||
search.removeEventListener('keydown', this.handleSearchKeyDown)
|
|
||||||
},
|
|
||||||
handleSearchKeyDown: function (e) {
|
|
||||||
if (e.keyCode === 38 || e.keyCode === 40) {
|
|
||||||
var search = React.findDOMNode(this.refs.search)
|
|
||||||
search.blur()
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
if (e.keyCode !== 27 && (e.keyCode !== 13 || !e.metaKey)) {
|
|
||||||
e.stopPropagation()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openPlanetSettingModal: function () {
|
|
||||||
this.openModal(PlanetSettingModal, {planet: this.props.currentPlanet})
|
|
||||||
},
|
|
||||||
refresh: function () {
|
|
||||||
this.props.fetchPlanet()
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var currentPlanetName = this.props.currentPlanet.name
|
|
||||||
var currentUserName = this.props.currentPlanet.Owner.name
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='PlanetHeader'>
|
|
||||||
<div className='headerLabel'>
|
|
||||||
<Link to='userHome' params={{userName: currentUserName}} className='userName'>{currentUserName}</Link>
|
|
||||||
<span className='planetName'>{currentPlanetName}</span>
|
|
||||||
|
|
||||||
{this.props.currentPlanet.public ? null : (
|
|
||||||
<div className='private'>
|
|
||||||
<i className='fa fa-lock'/>
|
|
||||||
<div className='tooltip'>Private planet</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<button onClick={this.openPlanetSettingModal} className='planetSettingButton'>
|
|
||||||
<i className='fa fa-chevron-down'></i>
|
|
||||||
<div className='tooltip'>Planet setting</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='headerControl'>
|
|
||||||
<div className='searchInput'>
|
|
||||||
<i className='fa fa-search'/>
|
|
||||||
<input onChange={this.props.onSearchChange} value={this.props.search} ref='search' type='text' className='inline-input circleInput' placeholder='Search...'/>
|
|
||||||
</div>
|
|
||||||
<button onClick={this.refresh} className='refreshButton'>
|
|
||||||
<i className='fa fa-refresh'/>
|
|
||||||
<div className='tooltip'>Refresh planet</div>
|
|
||||||
</button>
|
|
||||||
<a onClick={this.openExternal} href='http://b00st.io' className='logo'>
|
|
||||||
<img width='44' height='44' src='resources/favicon-230x230.png'/>
|
|
||||||
<div className='tooltip'>Boost official page</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var Navigation = ReactRouter.Navigation
|
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
|
||||||
|
|
||||||
var LaunchModal = require('../Components/LaunchModal')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [Modal, Navigation],
|
|
||||||
propTypes: {
|
|
||||||
planet: React.PropTypes.shape({
|
|
||||||
name: React.PropTypes.string,
|
|
||||||
Owner: React.PropTypes.shape({
|
|
||||||
id: React.PropTypes.number,
|
|
||||||
userType: React.PropTypes.string
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
search: React.PropTypes.string,
|
|
||||||
toggleCodeFilter: React.PropTypes.func,
|
|
||||||
toggleNoteFilter: React.PropTypes.func,
|
|
||||||
currentUser: React.PropTypes.shape({
|
|
||||||
id: React.PropTypes.number,
|
|
||||||
userType: React.PropTypes.string,
|
|
||||||
Teams: React.PropTypes.array
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
isLaunchModalOpen: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openLaunchModal: function () {
|
|
||||||
this.openModal(LaunchModal, {planet: this.props.planet, transitionTo: this.transitionTo})
|
|
||||||
},
|
|
||||||
isMyPlanet: function () {
|
|
||||||
if (this.props.currentUser == null) return false
|
|
||||||
if (this.props.planet.Owner.userType === 'person' && this.props.planet.Owner.id !== this.props.currentUser.id) return false
|
|
||||||
if (this.props.planet.Owner.userType === 'team' && !this.props.currentUser.Teams.some(function (team) {
|
|
||||||
if (team.id === this.props.planet.Owner.id) return true
|
|
||||||
return false
|
|
||||||
}.bind(this))) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var keywords = this.props.search.split(' ')
|
|
||||||
var usingCodeFilter = keywords.some(function (keyword) {
|
|
||||||
if (keyword === '$c') return true
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
var usingNoteFilter = keywords.some(function (keyword) {
|
|
||||||
if (keyword === '$n') return true
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='PlanetNavigator'>
|
|
||||||
{this.isMyPlanet() ? (
|
|
||||||
<button onClick={this.openLaunchModal} className='launchButton btn-primary btn-block'>
|
|
||||||
<i className='fa fa-rocket fa-fw'/> Launch
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
<nav className='articleFilters'>
|
|
||||||
<a className={usingCodeFilter && !usingNoteFilter ? 'active' : ''} onClick={this.props.toggleCodeFilter}>
|
|
||||||
<i className='fa fa-code fa-fw'/> Codes
|
|
||||||
</a>
|
|
||||||
<a className={!usingCodeFilter && usingNoteFilter ? 'active' : ''} onClick={this.props.toggleNoteFilter}>
|
|
||||||
<i className='fa fa-file-text-o fa-fw'/> Notes
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('planetSettingModal')],
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func,
|
|
||||||
planet: React.PropTypes.shape({
|
|
||||||
name: React.PropTypes.string,
|
|
||||||
public: React.PropTypes.bool,
|
|
||||||
Owner: React.PropTypes.shape({
|
|
||||||
name: React.PropTypes.string
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var deleteTextCandidates = [
|
|
||||||
'Confirm',
|
|
||||||
'Exterminatus',
|
|
||||||
'Avada Kedavra'
|
|
||||||
]
|
|
||||||
var random = Math.round(Math.random() * 10) % 10
|
|
||||||
var randomDeleteText = random > 1 ? deleteTextCandidates[0] : random === 1 ? deleteTextCandidates[1] : deleteTextCandidates[2]
|
|
||||||
|
|
||||||
return {
|
|
||||||
currentTab: 'profile',
|
|
||||||
planet: {
|
|
||||||
name: this.props.planet.name,
|
|
||||||
public: this.props.planet.public
|
|
||||||
},
|
|
||||||
randomDeleteText: randomDeleteText,
|
|
||||||
deleteConfirmation: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
activePlanetProfile: function () {
|
|
||||||
this.setState({currentTab: 'profile'})
|
|
||||||
},
|
|
||||||
activePlanetDelete: function () {
|
|
||||||
this.setState({currentTab: 'delete'})
|
|
||||||
},
|
|
||||||
handlePublicChange: function (value) {
|
|
||||||
return function () {
|
|
||||||
this.state.planet.public = value
|
|
||||||
this.setState({planet: this.state.planet})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
handleSavePlanetProfile: function (e) {
|
|
||||||
var planet = this.props.planet
|
|
||||||
|
|
||||||
this.setState({profileFormStatus: 'sending', profileFormError: null}, function () {
|
|
||||||
Hq.updatePlanet(planet.Owner.name, planet.name, this.state.planet)
|
|
||||||
.then(function (res) {
|
|
||||||
var planet = res.body
|
|
||||||
console.log(planet)
|
|
||||||
this.setState({profileFormStatus: 'done'})
|
|
||||||
|
|
||||||
PlanetStore.Actions.update(planet)
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
var newState = {
|
|
||||||
profileFormStatus: 'error'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err.status == null) {
|
|
||||||
newState.profileFormError = {message: 'Check your network connection'}
|
|
||||||
return this.setState(newState)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (err.status) {
|
|
||||||
case 403:
|
|
||||||
newState.profileFormError = err.response.body
|
|
||||||
this.setState(newState)
|
|
||||||
break
|
|
||||||
case 422:
|
|
||||||
newState.profileFormError = {message: 'Planet name should be Alphanumeric with _, -'}
|
|
||||||
this.setState(newState)
|
|
||||||
break
|
|
||||||
case 409:
|
|
||||||
newState.profileFormError = {message: 'The entered name already in use'}
|
|
||||||
this.setState(newState)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
newState.profileFormError = {message: 'Undefined error please try again'}
|
|
||||||
this.setState(newState)
|
|
||||||
}
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleDeletePlanetClick: function () {
|
|
||||||
var planet = this.props.planet
|
|
||||||
|
|
||||||
this.setState({deleteSubmitStatus: 'sending'}, function () {
|
|
||||||
Hq.destroyPlanet(planet.Owner.name, planet.name)
|
|
||||||
.then(function (res) {
|
|
||||||
var planet = res.body
|
|
||||||
|
|
||||||
PlanetStore.Actions.destroy(planet)
|
|
||||||
this.setState({deleteSubmitStatus: 'done'}, function () {
|
|
||||||
this.props.close()
|
|
||||||
})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
this.setState({deleteSubmitStatus: 'error'})
|
|
||||||
console.error(err)
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var content
|
|
||||||
|
|
||||||
content = this.state.currentTab === 'profile' ? this.renderPlanetProfileTab() : this.renderPlanetDeleteTab()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='PlanetSettingModal sideNavModal modal'>
|
|
||||||
<div className='leftPane'>
|
|
||||||
<h1 className='modalLabel'>Planet setting</h1>
|
|
||||||
<nav className='tabList'>
|
|
||||||
<button onClick={this.activePlanetProfile} className={this.state.currentTab === 'profile' ? 'active' : ''}><i className='fa fa-globe fa-fw'/> Planet profile</button>
|
|
||||||
<button onClick={this.activePlanetDelete} className={this.state.currentTab === 'delete' ? 'active' : ''}><i className='fa fa-trash fa-fw'/> Delete Planet</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='rightPane'>
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderPlanetProfileTab: function () {
|
|
||||||
return (
|
|
||||||
<div className='planetProfileTab tab'>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Planet name </label>
|
|
||||||
<input valueLink={this.linkState('planet.name')}/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='formRadioField'>
|
|
||||||
<input id='publicOption' checked={this.state.planet.public} onChange={this.handlePublicChange(true)} name='public' type='radio'/> <label htmlFor='publicOption'>Public</label>
|
|
||||||
|
|
||||||
<input id='privateOption' checked={!this.state.planet.public} onChange={this.handlePublicChange(false)} name='public' type='radio'/> <label htmlFor='privateOption'>Private</label>
|
|
||||||
</div>
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button onClick={this.handleSavePlanetProfile} className='saveButton btn-primary'>Save</button>
|
|
||||||
|
|
||||||
<div className={'alertInfo' + (this.state.profileFormStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
|
|
||||||
|
|
||||||
<div className={'alertError' + (this.state.profileFormStatus === 'error' ? '' : ' hide')}>{this.state.profileFormError != null ? this.state.profileFormError.message : 'Unexpected error occured! please try again'}</div>
|
|
||||||
|
|
||||||
<div className={'alertSuccess' + (this.state.profileFormStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderPlanetDeleteTab: function () {
|
|
||||||
var disabled = !this.state.deleteConfirmation.match(new RegExp('^' + this.props.planet.Owner.name + '/' + this.props.planet.name + '$'))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='planetDeleteTab tab'>
|
|
||||||
<p>Are you sure to destroy <strong>'{this.props.planet.Owner.name + '/' + this.props.planet.name}'</strong>?</p>
|
|
||||||
<p>If you are sure, write <strong>'{this.props.planet.Owner.name + '/' + this.props.planet.name}'</strong> to input below and click <strong>'{this.state.randomDeleteText}'</strong> button.</p>
|
|
||||||
<input valueLink={this.linkState('deleteConfirmation')} placeholder='userName/planetName'/>
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button disabled={disabled} onClick={this.handleDeletePlanetClick}>{this.state.randomDeleteText}</button>
|
|
||||||
|
|
||||||
<div className={'alertInfo' + (this.state.deleteSubmitStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
|
|
||||||
|
|
||||||
<div className={'alertError' + (this.state.deleteSubmitStatus === 'error' ? '' : ' hide')}>Connection failed.. Try again.</div>
|
|
||||||
|
|
||||||
<div className={'alertSuccess' + (this.state.deleteSubmitStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
var ipc = require('ipc')
|
|
||||||
var remote = require('remote')
|
|
||||||
|
|
||||||
var React = require('react')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var ExternalLink = require('../Mixins/ExternalLink')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, ExternalLink, KeyCaster('aboutModal')],
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
var keymap = remote.getGlobal('keymap')
|
|
||||||
console.log(keymap)
|
|
||||||
return {
|
|
||||||
currentTab: 'settings',
|
|
||||||
keymap: keymap
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
activeSettings: function () {
|
|
||||||
this.setState({currentTab: 'settings'})
|
|
||||||
},
|
|
||||||
activeAbout: function () {
|
|
||||||
this.setState({currentTab: 'about'})
|
|
||||||
},
|
|
||||||
saveKeymap: function () {
|
|
||||||
ipc.send('hotkeyUpdated', JSON.stringify(this.state.keymap))
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var content = this.state.currentTab === 'settings' ? this.renderSettingsTab() : this.renderAboutTab()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='PreferencesModal sideNavModal modal'>
|
|
||||||
<div className='leftPane'>
|
|
||||||
<h1 className='modalLabel'>Preferences</h1>
|
|
||||||
<nav className='tabList'>
|
|
||||||
<button onClick={this.activeSettings} className={this.state.currentTab === 'settings' ? 'active' : ''}><i className='fa fa-gear fa-fw'/> Settings</button>
|
|
||||||
<button onClick={this.activeAbout} className={this.state.currentTab === 'about' ? 'active' : ''}><i className='fa fa-info-circle fa-fw'/> About this app</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div className='rightPane'>
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderSettingsTab: function () {
|
|
||||||
return (
|
|
||||||
<div className='settingsTab tab'>
|
|
||||||
<div className='categoryLabel'>Hotkey</div>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Toggle finder</label>
|
|
||||||
<input valueLink={this.linkState('keymap.toggleFinder')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button onClick={this.saveKeymap}>Save</button>
|
|
||||||
</div>
|
|
||||||
<div className='example'>
|
|
||||||
<h3>Example</h3>
|
|
||||||
<ul>
|
|
||||||
<li><code>0</code> to <code>9</code></li>
|
|
||||||
<li><code>A</code> to <code>Z</code></li>
|
|
||||||
<li><code>F1</code> to <code>F24</code></li>
|
|
||||||
<li>Punctuations like <code>~</code>, <code>!</code>, <code>@</code>, <code>#</code>, <code>$</code>, etc.</li>
|
|
||||||
<li><code>Plus</code></li>
|
|
||||||
<li><code>Space</code></li>
|
|
||||||
<li><code>Backspace</code></li>
|
|
||||||
<li><code>Delete</code></li>
|
|
||||||
<li><code>Insert</code></li>
|
|
||||||
<li><code>Return</code> (or <code>Enter</code> as alias)</li>
|
|
||||||
<li><code>Up</code>, <code>Down</code>, <code>Left</code> and <code>Right</code></li>
|
|
||||||
<li><code>Home</code> and <code>End</code></li>
|
|
||||||
<li><code>PageUp</code> and <code>PageDown</code></li>
|
|
||||||
<li><code>Escape</code> (or <code>Esc</code> for short)</li>
|
|
||||||
<li><code>VolumeUp</code>, <code>VolumeDown</code> and <code>VolumeMute</code></li>
|
|
||||||
<li><code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>, <code>MediaStop</code> and <code>MediaPlayPause</code></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderAboutTab: function () {
|
|
||||||
var version = global.version
|
|
||||||
return (
|
|
||||||
<div className='aboutTab tab'>
|
|
||||||
<div className='about1'>
|
|
||||||
<img className='logo' src='resources/favicon-230x230.png'/>
|
|
||||||
<div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='about2'>
|
|
||||||
<div className='externalLabel'>External links</div>
|
|
||||||
<ul className='externalList'>
|
|
||||||
<li><a onClick={this.openExternal} href='http://b00st.io'>Boost Homepage <i className='fa fa-external-link'/></a></li>
|
|
||||||
<li><a onClick={this.openExternal} href='http://boostio.github.io/regulations.html'>Regulation <i className='fa fa-external-link'/></a></li>
|
|
||||||
<li><a onClick={this.openExternal} href='http://boostio.github.io/privacypolicies.html'>Private policy <i className='fa fa-external-link'/></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/* global localStorage */
|
|
||||||
|
|
||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
var socket = require('../Services/socket')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, KeyCaster('teamCreateModal')],
|
|
||||||
propTypes: {
|
|
||||||
user: React.PropTypes.shape({
|
|
||||||
name: React.PropTypes.string
|
|
||||||
}),
|
|
||||||
transitionTo: React.PropTypes.func,
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
team: {
|
|
||||||
name: ''
|
|
||||||
},
|
|
||||||
error: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
React.findDOMNode(this.refs.teamName).focus()
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
case 'submitTeamCreateModal':
|
|
||||||
this.handleSubmit()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleSubmit: function () {
|
|
||||||
this.setState({error: null}, function () {
|
|
||||||
Hq.createTeam(this.props.user.name, this.state.team)
|
|
||||||
.then(function (res) {
|
|
||||||
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
|
|
||||||
var team = res.body
|
|
||||||
|
|
||||||
currentUser.Teams.push(team)
|
|
||||||
localStorage.setItem('currentUser', JSON.stringify(currentUser))
|
|
||||||
socket.reconnect(currentUser)
|
|
||||||
UserStore.Actions.update(currentUser)
|
|
||||||
|
|
||||||
if (this.props.transitionTo != null) {
|
|
||||||
this.props.transitionTo('userHome', {userName: team.name})
|
|
||||||
}
|
|
||||||
this.props.close()
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
|
|
||||||
if (err.status == null) return this.setState({error: {message: 'Check your network connection'}})
|
|
||||||
|
|
||||||
switch (err.status) {
|
|
||||||
case 422:
|
|
||||||
this.setState({error: {message: 'Team name should be Alphanumeric with _, -'}})
|
|
||||||
break
|
|
||||||
case 409:
|
|
||||||
this.setState({error: {message: 'The entered name already in use'}})
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
this.setState({error: {message: 'Error message undefined'}})
|
|
||||||
}
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='TeamCreateModal modal'>
|
|
||||||
<input ref='teamName' valueLink={this.linkState('team.name')} className='nameInput stripInput' placeholder='Create new team'/>
|
|
||||||
{this.state.error != null ? (<p className='errorAlert'>{this.state.error.message != null ? this.state.error.message : 'Unintended error occured'}</p>) : null}
|
|
||||||
<button onClick={this.handleSubmit} className='submitButton'>
|
|
||||||
<i className='fa fa-check'/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
/* global localStorage */
|
|
||||||
|
|
||||||
var React = require('react')
|
|
||||||
var Reflux = require('reflux')
|
|
||||||
var Select = require('react-select')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
|
||||||
var Helper = require('../Mixins/Helper')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
|
||||||
|
|
||||||
var getOptions = function (input, callback) {
|
|
||||||
Hq.searchUser(input)
|
|
||||||
.then(function (res) {
|
|
||||||
callback(null, {
|
|
||||||
options: res.body.map(function (user) {
|
|
||||||
return {
|
|
||||||
label: user.name,
|
|
||||||
value: user.name
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
complete: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper, KeyCaster('teamSettingsModal')],
|
|
||||||
propTypes: {
|
|
||||||
team: React.PropTypes.shape({
|
|
||||||
id: React.PropTypes.number,
|
|
||||||
name: React.PropTypes.string,
|
|
||||||
profileName: React.PropTypes.string,
|
|
||||||
email: React.PropTypes.string,
|
|
||||||
Members: React.PropTypes.array
|
|
||||||
}),
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
currentTab: 'teamInfo',
|
|
||||||
team: this.props.team,
|
|
||||||
userSubmitStatus: null,
|
|
||||||
member: {
|
|
||||||
name: '',
|
|
||||||
role: 'member'
|
|
||||||
},
|
|
||||||
updatingMember: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'closeModal':
|
|
||||||
this.props.close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onUserChange: function (res) {
|
|
||||||
switch (res.status) {
|
|
||||||
case 'userUpdated':
|
|
||||||
var user = res.data
|
|
||||||
if (user.id === this.props.team.id) {
|
|
||||||
this.forceUpdate()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectTab: function (tabName) {
|
|
||||||
return function () {
|
|
||||||
this.setState({currentTab: tabName})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
saveUserInfo: function () {
|
|
||||||
this.setState({
|
|
||||||
userSubmitStatus: 'sending'
|
|
||||||
}, function () {
|
|
||||||
Hq.updateUser(this.props.team.name, this.state.team)
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({userSubmitStatus: 'done'}, function () {
|
|
||||||
UserStore.Actions.update(res.body)
|
|
||||||
this.forceUpdate()
|
|
||||||
})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({userSubmitStatus: 'error'})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleMemberNameChange: function (value) {
|
|
||||||
var member = this.state.member
|
|
||||||
member.name = value
|
|
||||||
this.setState({member: member})
|
|
||||||
},
|
|
||||||
addMember: function () {
|
|
||||||
this.setState({updatingMember: true}, function () {
|
|
||||||
Hq
|
|
||||||
.addMember(this.props.team.name, {
|
|
||||||
userName: this.state.member.name,
|
|
||||||
role: this.state.member.role
|
|
||||||
})
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({updatingMember: false, team: res.body})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({updatingMember: false})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
roleChange: function (memberName) {
|
|
||||||
return function (e) {
|
|
||||||
var role = e.target.value
|
|
||||||
this.setState({updatingMember: true}, function () {
|
|
||||||
Hq
|
|
||||||
.addMember(this.props.team.name, {
|
|
||||||
userName: memberName,
|
|
||||||
role: role
|
|
||||||
})
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({updatingMember: false, team: res.body})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({updatingMember: false})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
removeMember: function (memberName) {
|
|
||||||
return function () {
|
|
||||||
this.setState({updatingMember: true}, function () {
|
|
||||||
Hq
|
|
||||||
.removeMember(this.props.team.name, {
|
|
||||||
userName: memberName
|
|
||||||
})
|
|
||||||
.then(function (res) {
|
|
||||||
this.setState({updatingMember: false, team: res.body})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
this.setState({updatingMember: false})
|
|
||||||
}.bind(this))
|
|
||||||
})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var content
|
|
||||||
|
|
||||||
switch (this.state.currentTab) {
|
|
||||||
case 'teamInfo':
|
|
||||||
content = this.renderTeamInfoTab()
|
|
||||||
break
|
|
||||||
case 'members':
|
|
||||||
content = this.renderMembersTab()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='TeamSettingsModal sideNavModal modal'>
|
|
||||||
<div className='leftPane'>
|
|
||||||
<div className='modalLabel'>Team settings</div>
|
|
||||||
<div className='tabList'>
|
|
||||||
<button className={this.state.currentTab === 'teamInfo' ? 'active' : ''} onClick={this.selectTab('teamInfo')}><i className='fa fa-info-circle fa-fw'/> Team Info</button>
|
|
||||||
<button className={this.state.currentTab === 'members' ? 'active' : ''} onClick={this.selectTab('members')}><i className='fa fa-users fa-fw'/> Members</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='rightPane'>
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderTeamInfoTab: function () {
|
|
||||||
return (
|
|
||||||
<div className='userInfoTab tab'>
|
|
||||||
<div className='formField'>
|
|
||||||
<label>Profile Name</label>
|
|
||||||
<input valueLink={this.linkState('team.profileName')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formConfirm'>
|
|
||||||
<button disabled={this.state.userSubmitStatus === 'sending'} onClick={this.saveUserInfo}>Save</button>
|
|
||||||
|
|
||||||
<div className={'alertInfo' + (this.state.userSubmitStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
|
|
||||||
|
|
||||||
<div className={'alertError' + (this.state.userSubmitStatus === 'error' ? '' : ' hide')}>Connection failed.. Try again.</div>
|
|
||||||
|
|
||||||
<div className={'alertSuccess' + (this.state.userSubmitStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
renderMembersTab: function () {
|
|
||||||
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
|
|
||||||
|
|
||||||
var members = this.state.team.Members.map(function (member) {
|
|
||||||
var isCurrentUser = currentUser.id === member.id
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
<td>{member.profileName}({member.name})</td>
|
|
||||||
<td>
|
|
||||||
{isCurrentUser ? (
|
|
||||||
'Owner'
|
|
||||||
) : (
|
|
||||||
<select disabled={this.state.updatingMember} onChange={this.roleChange(member.name)} className='roleSelect' value={member.TeamMember.role}>
|
|
||||||
<option value='owner'>Owner</option>
|
|
||||||
<option value='member'>Member</option>
|
|
||||||
</select>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{isCurrentUser ? '-' : (
|
|
||||||
<button disabled={this.state.updatingMember} onClick={this.removeMember(member.name)}><i className='fa fa-close fa-fw'/></button>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
}.bind(this))
|
|
||||||
|
|
||||||
var belowLimit = members.length < 5
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='membersTab tab'>
|
|
||||||
<table className='memberTable'>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Role</th>
|
|
||||||
<th>Control</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{members}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{belowLimit ? (
|
|
||||||
<div className='addMemberForm'>
|
|
||||||
<div className='formLabel'>Add Member</div>
|
|
||||||
<div className='formGroup'>
|
|
||||||
<Select
|
|
||||||
name='userName'
|
|
||||||
value={this.state.member.name}
|
|
||||||
placeholder='Username to add'
|
|
||||||
asyncOptions={getOptions}
|
|
||||||
onChange={this.handleMemberNameChange}
|
|
||||||
className='userNameSelect'
|
|
||||||
/>
|
|
||||||
<select valueLink={this.linkState('member.role')} className='roleSelect'>
|
|
||||||
<option value={'member'}>Member</option>
|
|
||||||
<option value={'owner'}>Owner</option>
|
|
||||||
</select>
|
|
||||||
<button disabled={this.state.updatingMember} onClick={this.addMember} className='confirmButton'>Add Member</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
Maximum number of members is 5 on Beta version. Please contact us if you want futher use.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var ExternalLink = require('../Mixins/ExternalLink')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ExternalLink],
|
|
||||||
propTypes: {
|
|
||||||
search: React.PropTypes.string,
|
|
||||||
changeSearch: React.PropTypes.func
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className='TopBar'>
|
|
||||||
<div className='left'>
|
|
||||||
<div className='search'>
|
|
||||||
<i className='fa fa-search'/>
|
|
||||||
<input value={this.props.search} onChange={this.props.changeSearch} className='searchInput' placeholder='Search...'/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='right'>
|
|
||||||
<a onClick={this.openExternal} href='http://b00st.io' className='logo'>
|
|
||||||
<img width='44' height='44' src='resources/favicon-230x230.png'/>
|
|
||||||
<div className='tooltip'>Boost official page</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
/* global localStorage*/
|
|
||||||
var React = require('react')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var Reflux = require('reflux')
|
|
||||||
|
|
||||||
var PlanetHeader = require('../Components/PlanetHeader')
|
|
||||||
var PlanetNavigator = require('../Components/PlanetNavigator')
|
|
||||||
var PlanetArticleList = require('../Components/PlanetArticleList')
|
|
||||||
var PlanetArticleDetail = require('../Components/PlanetArticleDetail')
|
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
|
||||||
var ArticleFilter = require('../Mixins/ArticleFilter')
|
|
||||||
var Helper = require('../Mixins/Helper')
|
|
||||||
var KeyCaster = require('../Mixins/KeyCaster')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper, KeyCaster('planetContainer')],
|
|
||||||
propTypes: {
|
|
||||||
params: React.PropTypes.object,
|
|
||||||
planetName: React.PropTypes.string
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
currentUser: JSON.parse(localStorage.getItem('currentUser')),
|
|
||||||
planet: null,
|
|
||||||
search: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
this.fetchPlanet(this.props.params.userName, this.props.params.planetName)
|
|
||||||
},
|
|
||||||
componentDidUpdate: function () {
|
|
||||||
if (this.isActive('planetHome') && this.refs.list != null && this.refs.list.props.articles.length > 0) {
|
|
||||||
var article = this.refs.list.props.articles[0]
|
|
||||||
var planet = this.state.planet
|
|
||||||
switch (article.type) {
|
|
||||||
case 'code':
|
|
||||||
this.transitionTo('codes', {userName: planet.Owner.name, planetName: planet.name, localId: article.localId})
|
|
||||||
break
|
|
||||||
case 'note':
|
|
||||||
this.transitionTo('notes', {userName: planet.Owner.name, planetName: planet.name, localId: article.localId})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentWillReceiveProps: function (nextProps) {
|
|
||||||
if (this.state.planet == null) {
|
|
||||||
this.fetchPlanet(nextProps.params.userName, nextProps.params.planetName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextProps.params.userName !== this.state.planet.Owner.name || nextProps.params.planetName !== this.state.planet.name) {
|
|
||||||
this.setState({
|
|
||||||
planet: null
|
|
||||||
}, function () {
|
|
||||||
this.fetchPlanet(nextProps.params.userName, nextProps.params.planetName)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onKeyCast: function (e) {
|
|
||||||
switch (e.status) {
|
|
||||||
case 'openLaunchModal':
|
|
||||||
this.refs.navigator.openLaunchModal()
|
|
||||||
break
|
|
||||||
case 'selectNextArticle':
|
|
||||||
this.selectNextArticle()
|
|
||||||
break
|
|
||||||
case 'selectPriorArticle':
|
|
||||||
this.selectPriorArticle()
|
|
||||||
break
|
|
||||||
case 'toggleFocusSearchInput':
|
|
||||||
this.toggleFocusSearchInput()
|
|
||||||
break
|
|
||||||
case 'openEditModal':
|
|
||||||
this.refs.detail.openEditModal()
|
|
||||||
break
|
|
||||||
case 'openDeleteModal':
|
|
||||||
this.refs.detail.openDeleteModal()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onPlanetChange: function (res) {
|
|
||||||
if (this.state.planet == null) return
|
|
||||||
|
|
||||||
var planet, code, note, articleIndex, articlesCount
|
|
||||||
switch (res.status) {
|
|
||||||
case 'updated':
|
|
||||||
planet = res.data
|
|
||||||
if (this.state.planet.id === planet.id) {
|
|
||||||
if (this.state.planet.name === planet.name) {
|
|
||||||
this.setState({planet: planet})
|
|
||||||
} else {
|
|
||||||
this.transitionTo('planetHome', {userName: planet.Owner.name, planetName: planet.name})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'destroyed':
|
|
||||||
planet = res.data
|
|
||||||
if (this.state.planet.id === planet.id) {
|
|
||||||
this.transitionTo('userHome', {userName: this.state.planet.Owner.name})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'codeUpdated':
|
|
||||||
code = res.data
|
|
||||||
if (code.PlanetId === this.state.planet.id) {
|
|
||||||
this.state.planet.Codes = this.updateItemToTargetArray(code, this.state.planet.Codes)
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'noteUpdated':
|
|
||||||
note = res.data
|
|
||||||
if (note.PlanetId === this.state.planet.id) {
|
|
||||||
this.state.planet.Notes = this.updateItemToTargetArray(note, this.state.planet.Notes)
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'codeDestroyed':
|
|
||||||
code = res.data
|
|
||||||
if (code.PlanetId === this.state.planet.id) {
|
|
||||||
this.state.planet.Codes = this.deleteItemFromTargetArray(code, this.state.planet.Codes)
|
|
||||||
|
|
||||||
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === code.type && this.refs.detail.props.article.localId === code.localId) {
|
|
||||||
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
|
||||||
articlesCount = this.refs.list.props.articles.length
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet}, function () {
|
|
||||||
if (articlesCount > 1) {
|
|
||||||
if (articleIndex > 0) {
|
|
||||||
this.selectArticleByListIndex(articleIndex - 1)
|
|
||||||
} else {
|
|
||||||
this.selectArticleByListIndex(articleIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'noteDestroyed':
|
|
||||||
note = res.data
|
|
||||||
if (note.PlanetId === this.state.planet.id) {
|
|
||||||
this.state.planet.Notes = this.deleteItemFromTargetArray(note, this.state.planet.Notes)
|
|
||||||
|
|
||||||
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === note.type && this.refs.detail.props.article.localId === note.localId) {
|
|
||||||
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
|
||||||
articlesCount = this.refs.list.props.articles.length
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet}, function () {
|
|
||||||
if (articlesCount > 1) {
|
|
||||||
if (articleIndex > 0) {
|
|
||||||
this.selectArticleByListIndex(articleIndex - 1)
|
|
||||||
} else {
|
|
||||||
this.selectArticleByListIndex(articleIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onUserChange: function () {
|
|
||||||
|
|
||||||
},
|
|
||||||
fetchPlanet: function (userName, planetName) {
|
|
||||||
if (userName == null) userName = this.props.params.userName
|
|
||||||
if (planetName == null) planetName = this.props.params.planetName
|
|
||||||
|
|
||||||
Hq.fetchPlanet(userName, planetName)
|
|
||||||
.then(function (res) {
|
|
||||||
var planet = res.body
|
|
||||||
|
|
||||||
planet.Codes.forEach(function (code) {
|
|
||||||
code.type = 'code'
|
|
||||||
})
|
|
||||||
|
|
||||||
planet.Notes.forEach(function (note) {
|
|
||||||
note.type = 'note'
|
|
||||||
})
|
|
||||||
|
|
||||||
localStorage.setItem('planet-' + planet.id, JSON.stringify(planet))
|
|
||||||
|
|
||||||
this.setState({planet: planet})
|
|
||||||
}.bind(this))
|
|
||||||
.catch(function (err) {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getFilteredIndexOfCurrentArticle: function () {
|
|
||||||
var params = this.props.params
|
|
||||||
var index = 0
|
|
||||||
|
|
||||||
if (this.isActive('codes')) {
|
|
||||||
this.refs.list.props.articles.some(function (_article, _index) {
|
|
||||||
if (_article.type === 'code' && _article.localId === parseInt(params.localId, 10)) {
|
|
||||||
index = _index
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (this.isActive('notes')) {
|
|
||||||
this.refs.list.props.articles.some(function (_article, _index) {
|
|
||||||
if (_article.type === 'note' && _article.localId === parseInt(params.localId, 10)) {
|
|
||||||
index = _index
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return index
|
|
||||||
},
|
|
||||||
selectArticleByListIndex: function (index) {
|
|
||||||
var article = this.refs.list.props.articles[index]
|
|
||||||
var params = this.props.params
|
|
||||||
|
|
||||||
if (article == null) {
|
|
||||||
this.transitionTo('planetHome', params)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var listElement = this.refs.list.refs.articles.getDOMNode()
|
|
||||||
var articleElement = listElement.querySelectorAll('li')[index]
|
|
||||||
|
|
||||||
var overflowBelow = listElement.clientHeight + listElement.scrollTop < articleElement.offsetTop + articleElement.clientHeight
|
|
||||||
if (overflowBelow) {
|
|
||||||
listElement.scrollTop = articleElement.offsetTop + articleElement.clientHeight - listElement.clientHeight
|
|
||||||
}
|
|
||||||
var overflowAbove = listElement.scrollTop > articleElement.offsetTop
|
|
||||||
if (overflowAbove) {
|
|
||||||
listElement.scrollTop = articleElement.offsetTop
|
|
||||||
}
|
|
||||||
|
|
||||||
if (article.type === 'code') {
|
|
||||||
params.localId = article.localId
|
|
||||||
this.transitionTo('codes', params)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (article.type === 'note') {
|
|
||||||
params.localId = article.localId
|
|
||||||
this.transitionTo('notes', params)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectNextArticle: function () {
|
|
||||||
if (this.state.planet == null) return
|
|
||||||
|
|
||||||
var index = this.getFilteredIndexOfCurrentArticle()
|
|
||||||
|
|
||||||
if (index < this.refs.list.props.articles.length - 1) {
|
|
||||||
this.selectArticleByListIndex(index + 1)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectPriorArticle: function () {
|
|
||||||
if (this.state.planet == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var index = this.getFilteredIndexOfCurrentArticle()
|
|
||||||
|
|
||||||
if (index > 0) {
|
|
||||||
this.selectArticleByListIndex(index - 1)
|
|
||||||
} else {
|
|
||||||
React.findDOMNode(this.refs.header.refs.search).focus()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleFocusSearchInput: function () {
|
|
||||||
var search = React.findDOMNode(this.refs.header.refs.search)
|
|
||||||
if (document.activeElement === search) {
|
|
||||||
React.findDOMNode(this.refs.header.refs.search).blur()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
React.findDOMNode(this.refs.header.refs.search).focus()
|
|
||||||
},
|
|
||||||
handleSearchChange: function (e) {
|
|
||||||
this.setState({search: e.target.value}, function () {
|
|
||||||
this.selectArticleByListIndex(0)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showAll: function () {
|
|
||||||
this.setState({search: ''})
|
|
||||||
},
|
|
||||||
toggleCodeFilter: function () {
|
|
||||||
var keywords = typeof this.state.search === 'string' ? this.state.search.split(' ') : []
|
|
||||||
|
|
||||||
var usingCodeFilter = false
|
|
||||||
var usingNoteFilter = false
|
|
||||||
keywords = keywords.filter(function (keyword) {
|
|
||||||
if (keyword === '$n') {
|
|
||||||
usingNoteFilter = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (keyword === '$c') usingCodeFilter = true
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (usingCodeFilter && !usingNoteFilter) {
|
|
||||||
keywords = keywords.filter(function (keyword) {
|
|
||||||
return keyword !== '$c'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usingCodeFilter) {
|
|
||||||
keywords.unshift('$c')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({search: keywords.join(' ')}, function () {
|
|
||||||
this.selectArticleByListIndex(0)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
toggleNoteFilter: function () {
|
|
||||||
var keywords = typeof this.state.search === 'string' ? this.state.search.split(' ') : []
|
|
||||||
|
|
||||||
var usingCodeFilter = false
|
|
||||||
var usingNoteFilter = false
|
|
||||||
keywords = keywords.filter(function (keyword) {
|
|
||||||
if (keyword === '$c') {
|
|
||||||
usingCodeFilter = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (keyword === '$n') usingNoteFilter = true
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (usingNoteFilter && !usingCodeFilter) {
|
|
||||||
keywords = keywords.filter(function (keyword) {
|
|
||||||
return keyword !== '$n'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usingNoteFilter) {
|
|
||||||
keywords.unshift('$n')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({search: keywords.join(' ')}, function () {
|
|
||||||
this.selectArticleByListIndex(0)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
applyTagFilter: function (tag) {
|
|
||||||
return function () {
|
|
||||||
this.setState({search: '#' + tag})
|
|
||||||
}.bind(this)
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
if (this.state.planet == null) return (<div/>)
|
|
||||||
|
|
||||||
var localId = parseInt(this.props.params.localId, 10)
|
|
||||||
|
|
||||||
var codes = this.state.planet.Codes
|
|
||||||
var notes = this.state.planet.Notes
|
|
||||||
|
|
||||||
var article
|
|
||||||
if (this.isActive('codes')) {
|
|
||||||
codes.some(function (_article) {
|
|
||||||
if (localId === _article.localId) {
|
|
||||||
article = _article
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
} else if (this.isActive('notes')) {
|
|
||||||
notes.some(function (_article) {
|
|
||||||
if (localId === _article.localId) {
|
|
||||||
article = _article
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var articles = codes.concat(notes)
|
|
||||||
|
|
||||||
var filteredArticles = this.searchArticle(this.state.search, articles)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='PlanetContainer'>
|
|
||||||
<PlanetHeader
|
|
||||||
ref='header'
|
|
||||||
search={this.state.search}
|
|
||||||
fetchPlanet={this.fetchPlanet}
|
|
||||||
onSearchChange={this.handleSearchChange}
|
|
||||||
currentPlanet={this.state.planet}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PlanetNavigator
|
|
||||||
ref='navigator'
|
|
||||||
search={this.state.search}
|
|
||||||
showAll={this.showAll}
|
|
||||||
toggleCodeFilter={this.toggleCodeFilter}
|
|
||||||
toggleNoteFilter={this.toggleNoteFilter}
|
|
||||||
planet={this.state.planet}
|
|
||||||
currentUser={this.state.currentUser}/>
|
|
||||||
|
|
||||||
<PlanetArticleList showOnlyWithTag={this.applyTagFilter} ref='list' articles={filteredArticles}/>
|
|
||||||
|
|
||||||
<PlanetArticleDetail
|
|
||||||
ref='detail'
|
|
||||||
article={article}
|
|
||||||
planet={this.state.planet}
|
|
||||||
showOnlyWithTag={this.applyTagFilter}/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, { PropTypes} from 'react'
|
import React, { PropTypes} from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { switchUser } from './actions'
|
import { switchUser } from './actions'
|
||||||
import UserNavigator from './Components/UserNavigator'
|
import UserNavigator from './HomePage/UserNavigator'
|
||||||
import ArticleNavigator from './Components/ArticleNavigator'
|
import ArticleNavigator from './HomePage/ArticleNavigator'
|
||||||
import ArticleTopBar from './Components/ArticleTopBar'
|
import ArticleTopBar from './HomePage/ArticleTopBar'
|
||||||
import ArticleList from './Components/ArticleList'
|
import ArticleList from './HomePage/ArticleList'
|
||||||
import ArticleDetail from './Components/ArticleDetail'
|
import ArticleDetail from './HomePage/ArticleDetail'
|
||||||
import { findWhere } from 'lodash'
|
import { findWhere } from 'lodash'
|
||||||
|
|
||||||
// var AuthFilter = require('../Mixins/AuthFilter')
|
// var AuthFilter = require('../Mixins/AuthFilter')
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { findWhere } from 'lodash'
|
import { findWhere } from 'lodash'
|
||||||
import ModeIcon from '../../Components/ModeIcon'
|
import ModeIcon from 'boost/components/ModeIcon'
|
||||||
import MarkdownPreview from '../../Components/MarkdownPreview'
|
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
||||||
import CodeEditor from '../../Components/CodeEditor'
|
import CodeEditor from 'boost/components/CodeEditor'
|
||||||
|
|
||||||
export default class ArticleDetail extends React.Component {
|
export default class ArticleDetail extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ProfileImage from '../../components/ProfileImage'
|
import ProfileImage from 'boost/components/ProfileImage'
|
||||||
import ModeIcon from '../../Components/ModeIcon'
|
import ModeIcon from 'boost/components/ModeIcon'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { IDLE_MODE, CREATE_MODE, EDIT_MODE } from '../actions'
|
import { IDLE_MODE, CREATE_MODE, EDIT_MODE } from '../actions'
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ProfileImage from '../../components/ProfileImage'
|
import ProfileImage from 'boost/components/ProfileImage'
|
||||||
import { findWhere } from 'lodash'
|
import { findWhere } from 'lodash'
|
||||||
|
|
||||||
export default class ArticleNavigator extends React.Component {
|
export default class ArticleNavigator extends React.Component {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ExternalLink from '../../components/ExternalLink'
|
import ExternalLink from 'boost/components/ExternalLink'
|
||||||
|
|
||||||
const ArticleTopBar = React.createClass({
|
const ArticleTopBar = React.createClass({
|
||||||
render () {
|
render () {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { Component, PropTypes } from 'react'
|
import React, { Component, PropTypes } from 'react'
|
||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
import ProfileImage from '../../components/ProfileImage'
|
import ProfileImage from 'boost/components/ProfileImage'
|
||||||
import { openModal } from '../lib/modal'
|
import { openModal } from 'boost/modal'
|
||||||
import CreateNewTeam from '../lib/modal/CreateNewTeam'
|
import CreateNewTeam from 'boost/components/modal/CreateNewTeam'
|
||||||
|
|
||||||
export default class UserNavigator extends Component {
|
export default class UserNavigator extends Component {
|
||||||
handleClick (e) {
|
handleClick (e) {
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
var Hq = require('../Services/Hq')
|
|
||||||
var socket = require('../Services/socket')
|
|
||||||
|
|
||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
import linkState from '../helpers/linkState'
|
import linkState from 'boost/linkState'
|
||||||
|
import { login } from 'boost/api'
|
||||||
|
|
||||||
export default class LoginPage extends React.Component {
|
export default class LoginPage extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -23,15 +21,14 @@ export default class LoginPage extends React.Component {
|
|||||||
isSending: true,
|
isSending: true,
|
||||||
error: null
|
error: null
|
||||||
}, function () {
|
}, function () {
|
||||||
console.log(this.state.user)
|
login(this.state.user)
|
||||||
Hq.login(this.state.user)
|
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
localStorage.setItem('token', res.body.token)
|
localStorage.setItem('token', res.body.token)
|
||||||
localStorage.setItem('currentUser', JSON.stringify(res.body.user))
|
localStorage.setItem('currentUser', JSON.stringify(res.body.user))
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.props.history.pushState('home')
|
this.props.history.pushState('home')
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
var ipc = require('ipc')
|
import ipc from 'ipc'
|
||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
|
||||||
var ContactModal = require('../Components/ContactModal')
|
var ContactModal = require('boost/components/modal/ContactModal')
|
||||||
|
|
||||||
export default class MainContainer extends React.Component {
|
export default class MainContainer extends React.Component {
|
||||||
// mixins: [Modal],
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {updateAvailable: false}
|
this.state = {updateAvailable: false}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
function basicFilter (keyword, articles) {
|
|
||||||
if (keyword === '' || keyword == null) return articles
|
|
||||||
var firstFiltered = articles.filter(function (article) {
|
|
||||||
|
|
||||||
var first = article.type === 'code' ? article.description : article.title
|
|
||||||
if (first.match(new RegExp(keyword, 'i'))) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
var secondFiltered = articles.filter(function (article) {
|
|
||||||
var second = article.type === 'code' ? article.content : article.content
|
|
||||||
if (second.match(new RegExp(keyword, 'i'))) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return firstFiltered.concat(secondFiltered).filter(function (value, index, self) {
|
|
||||||
return self.indexOf(value) === index
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function codeFilter (articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.type === 'code'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function noteFilter (articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.type === 'note'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function tagFilter (keyword, articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.Tags.some(function (tag) {
|
|
||||||
return tag.name.match(new RegExp('^' + keyword, 'i'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchArticle (search, articles) {
|
|
||||||
var keywords = search.split(' ')
|
|
||||||
|
|
||||||
for (var keyword of keywords) {
|
|
||||||
if (keyword.match(/^\$c/, 'i')) {
|
|
||||||
articles = codeFilter(articles)
|
|
||||||
continue
|
|
||||||
} else if (keyword.match(/^\$n/, 'i')) {
|
|
||||||
articles = noteFilter(articles)
|
|
||||||
continue
|
|
||||||
} else if (keyword.match(/^#[A-Za-z0-9]+/)) {
|
|
||||||
articles = tagFilter(keyword.substring(1, keyword.length), articles)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
articles = basicFilter(keyword, articles)
|
|
||||||
}
|
|
||||||
|
|
||||||
return articles.sort(function (a, b) {
|
|
||||||
return new Date(b.updatedAt) - new Date(a.updatedAt)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
searchArticle: searchArticle
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/* global localStorage*/
|
|
||||||
|
|
||||||
var mixin = {}
|
|
||||||
|
|
||||||
mixin.OnlyGuest = {
|
|
||||||
componentDidMount: function () {
|
|
||||||
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
|
|
||||||
|
|
||||||
if (currentUser == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.transitionTo('homeDefault')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin.OnlyUser = {
|
|
||||||
componentDidMount: function () {
|
|
||||||
var currentUser = localStorage.getItem('currentUser')
|
|
||||||
|
|
||||||
if (currentUser == null) {
|
|
||||||
this.transitionTo('login')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = mixin
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
var shell = require('shell')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
openExternal: function (e) {
|
|
||||||
shell.openExternal(e.currentTarget.href)
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
var ForceUpdate = function (interval) {
|
|
||||||
return {
|
|
||||||
componentDidMount: function () {
|
|
||||||
this.refreshTimer = setInterval(function () {
|
|
||||||
this.forceUpdate()
|
|
||||||
}.bind(this), interval)
|
|
||||||
},
|
|
||||||
componentWillUnmount: function () {
|
|
||||||
clearInterval(this.refreshTimer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ForceUpdate
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
function deleteItemFromTargetArray (item, targetArray) {
|
|
||||||
if (targetArray == null) targetArray = []
|
|
||||||
targetArray.some(function (_item, index) {
|
|
||||||
if (_item.id === item.id) {
|
|
||||||
targetArray.splice(index, 1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return targetArray
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateItemToTargetArray (item, targetArray) {
|
|
||||||
if (targetArray == null) targetArray = []
|
|
||||||
|
|
||||||
var isNew = !targetArray.some(function (_item, index) {
|
|
||||||
if (_item.id === item.id) {
|
|
||||||
targetArray.splice(index, 1, item)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isNew) targetArray.push(item)
|
|
||||||
|
|
||||||
return targetArray
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
deleteItemFromTargetArray: deleteItemFromTargetArray,
|
|
||||||
updateItemToTargetArray: updateItemToTargetArray
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
var Reflux = require('reflux')
|
|
||||||
|
|
||||||
var state = {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyDown = Reflux.createAction()
|
|
||||||
|
|
||||||
var KeyStore = Reflux.createStore({
|
|
||||||
init: function () {
|
|
||||||
this.listenTo(keyDown, this.onKeyDown)
|
|
||||||
document.addEventListener('keydown', function (e) {
|
|
||||||
keyDown(e)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setState: function (newState, cb) {
|
|
||||||
for (var key in newState) {
|
|
||||||
state[key] = newState[key]
|
|
||||||
}
|
|
||||||
if (typeof cb === 'function') cb()
|
|
||||||
},
|
|
||||||
onKeyDown: function (e) {
|
|
||||||
/*
|
|
||||||
Modals
|
|
||||||
*/
|
|
||||||
if (state.codeForm || state.noteForm || state.noteDeleteModal || state.codeDeleteModal || state.addMemberModal || state.aboutModal || state.editProfileModal || state.contactModal || state.teamCreateModal || state.planetCreateModal || state.planetSettingModal || state.teamSettingsModal || state.logoutModal) {
|
|
||||||
// ESC
|
|
||||||
if (e.keyCode === 27) this.cast('closeModal')
|
|
||||||
|
|
||||||
// Cmd + Enter
|
|
||||||
if (e.keyCode === 13 && e.metaKey) {
|
|
||||||
if (state.codeForm) this.cast('submitCodeForm')
|
|
||||||
if (state.noteForm) this.cast('submitNoteForm')
|
|
||||||
if (state.codeDeleteModal) this.cast('submitCodeDeleteModal')
|
|
||||||
if (state.noteDeleteModal) this.cast('submitNoteDeleteModal')
|
|
||||||
if (state.addMemberModal) this.cast('submitAddMemberModal')
|
|
||||||
if (state.contactModal) this.cast('submitContactModal')
|
|
||||||
if (state.teamCreateModal) this.cast('submitTeamCreateModal')
|
|
||||||
if (state.planetCreateModal) this.cast('submitPlanetCreateModal')
|
|
||||||
if (state.logoutModal) this.cast('submitLogoutModal')
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
PlanetContainer
|
|
||||||
*/
|
|
||||||
if (state.planetContainer) {
|
|
||||||
// Cmd + Enter, A
|
|
||||||
if ((e.keyCode === 13 && e.metaKey) || e.keyCode === 65) this.cast('openLaunchModal')
|
|
||||||
|
|
||||||
// Esc
|
|
||||||
if (e.keyCode === 27) this.cast('toggleFocusSearchInput')
|
|
||||||
|
|
||||||
// Up
|
|
||||||
if (e.keyCode === 38) this.cast('selectPriorArticle')
|
|
||||||
|
|
||||||
// Down
|
|
||||||
if (e.keyCode === 40) this.cast('selectNextArticle')
|
|
||||||
|
|
||||||
// E
|
|
||||||
if (e.keyCode === 69) this.cast('openEditModal')
|
|
||||||
|
|
||||||
// D
|
|
||||||
if (e.keyCode === 68) this.cast('openDeleteModal')
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
HomeContainer
|
|
||||||
*/
|
|
||||||
if (state.homeContainer) {
|
|
||||||
if (e.keyCode > 48 && e.keyCode < 58 && e.metaKey) {
|
|
||||||
this.cast('switchPlanet', e.keyCode - 48)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cast: function (status, data) {
|
|
||||||
this.trigger({
|
|
||||||
status: status,
|
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = function (stateKey) {
|
|
||||||
return {
|
|
||||||
mixins: [Reflux.listenTo(KeyStore, 'onKeyCast')],
|
|
||||||
componentDidMount: function () {
|
|
||||||
var newState = {}
|
|
||||||
newState[stateKey] = true
|
|
||||||
KeyStore.setState(newState)
|
|
||||||
},
|
|
||||||
componentWillUnmount: function () {
|
|
||||||
var newState = {}
|
|
||||||
newState[stateKey] = false
|
|
||||||
KeyStore.setState(newState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
var markdownit = require('markdown-it')
|
|
||||||
var md = markdownit({
|
|
||||||
typographer: true,
|
|
||||||
linkify: true
|
|
||||||
})
|
|
||||||
|
|
||||||
var Markdown = {
|
|
||||||
markdown: function (content) {
|
|
||||||
if (content == null) content = ''
|
|
||||||
return md.render(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Markdown
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
var ModalBase = React.createClass({
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
component: null,
|
|
||||||
componentProps: {},
|
|
||||||
isHidden: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
close: function () {
|
|
||||||
this.setState({component: null, componentProps: null, isHidden: true})
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var componentProps = this.state.componentProps
|
|
||||||
return (
|
|
||||||
<div className={'ModalBase' + (this.state.isHidden ? ' hide' : '')}>
|
|
||||||
<div onClick={this.close} className='modalBack'/>
|
|
||||||
{this.state.component == null ? null : (
|
|
||||||
<this.state.component {...componentProps} close={this.close}/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var modalBase = null
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
componentDidMount: function () {
|
|
||||||
if (modalBase == null) {
|
|
||||||
var el = document.createElement('div')
|
|
||||||
document.body.appendChild(el)
|
|
||||||
modalBase = React.render(<ModalBase/>, el)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openModal: function (component, props) {
|
|
||||||
modalBase.setState({component: component, componentProps: props, isHidden: false})
|
|
||||||
},
|
|
||||||
closeModal: function () {
|
|
||||||
modalBase.setState({isHidden: true})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
function getIn (object, path) {
|
|
||||||
var stack = path.split('.')
|
|
||||||
while (stack.length > 1) {
|
|
||||||
object = object[stack.shift()]
|
|
||||||
}
|
|
||||||
return object[stack.shift()]
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateIn (object, path, value) {
|
|
||||||
var current = object
|
|
||||||
var stack = path.split('.')
|
|
||||||
while (stack.length > 1) {
|
|
||||||
current = current[stack.shift()]
|
|
||||||
}
|
|
||||||
current[stack.shift()] = value
|
|
||||||
return object
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPartialState (component, path, value) {
|
|
||||||
component.setState(
|
|
||||||
updateIn(component.state, path, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function linkState (path) {
|
|
||||||
return {
|
|
||||||
value: getIn(this.state, path),
|
|
||||||
requestChange: setPartialState.bind(null, this, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
var request = require('superagent-promise')(require('superagent'), Promise)
|
|
||||||
var apiUrl = require('../../../config').apiUrl
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// Auth
|
|
||||||
login: function (input) {
|
|
||||||
return request
|
|
||||||
.post(apiUrl + 'auth/login')
|
|
||||||
.send(input)
|
|
||||||
},
|
|
||||||
signup: function (input) {
|
|
||||||
return request
|
|
||||||
.post(apiUrl + 'auth/register')
|
|
||||||
.send(input)
|
|
||||||
},
|
|
||||||
getUser: function () {
|
|
||||||
return request
|
|
||||||
.get(apiUrl + 'auth/user')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
},
|
|
||||||
changePassword: function (input) {
|
|
||||||
return request
|
|
||||||
.post(apiUrl + 'auth/password')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
},
|
|
||||||
fetchArticles: function (userId) {
|
|
||||||
return request
|
|
||||||
.get(apiUrl + 'teams/' + userId +'/articles')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fetchArticlesByFolderId: function (folderId) {
|
|
||||||
return request
|
|
||||||
.get(apiUrl + 'folders/' + folderId +'/articles')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
},
|
|
||||||
createArticle: function (input) {
|
|
||||||
return request
|
|
||||||
.post(apiUrl + 'folders/' + input.FolderId + '/articles')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
},
|
|
||||||
updateArticle: function (articleId, input) {
|
|
||||||
return request
|
|
||||||
.put(apiUrl + 'articles/' + articleId)
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
},
|
|
||||||
// Search
|
|
||||||
searchTag: function (tagName) {
|
|
||||||
return request
|
|
||||||
.get(apiUrl + 'search/tags')
|
|
||||||
.query({name: tagName})
|
|
||||||
},
|
|
||||||
searchUser: function (userName) {
|
|
||||||
return request
|
|
||||||
.get(apiUrl + 'search/users')
|
|
||||||
.query({name: userName})
|
|
||||||
},
|
|
||||||
|
|
||||||
// Mail
|
|
||||||
sendEmail: function (input) {
|
|
||||||
return request
|
|
||||||
.post(apiUrl + 'mail')
|
|
||||||
.set({
|
|
||||||
Authorization: 'Bearer ' + localStorage.getItem('token')
|
|
||||||
})
|
|
||||||
.send(input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/* global localStorage */
|
|
||||||
|
|
||||||
var config = require('../../../config')
|
|
||||||
|
|
||||||
var io = require('socket.io-client')(config.apiUrl)
|
|
||||||
|
|
||||||
io.on('connected', function (data) {
|
|
||||||
console.log('connected by WS')
|
|
||||||
})
|
|
||||||
|
|
||||||
io.on('userUpdated', function (data) {
|
|
||||||
console.log('userUpdated')
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
io: io
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
import linkState from '../helpers/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import openExternal from '../helpers/openExternal'
|
import openExternal from 'boost/openExternal'
|
||||||
|
import { signup } from 'boost/api'
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
export default class SignupContainer extends React.Component {
|
export default class SignupContainer extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -26,7 +25,7 @@ export default class SignupContainer extends React.Component {
|
|||||||
isSending: true,
|
isSending: true,
|
||||||
error: null
|
error: null
|
||||||
}, function () {
|
}, function () {
|
||||||
Hq.signup(this.state.user)
|
signup(this.state.user)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
localStorage.setItem('token', res.body.token)
|
localStorage.setItem('token', res.body.token)
|
||||||
localStorage.setItem('currentUser', JSON.stringify(res.body.user))
|
localStorage.setItem('currentUser', JSON.stringify(res.body.user))
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { createStore } from 'redux'
|
import { createStore } from 'redux'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { updateUser, updateArticles } from './HomeContainer/actions'
|
import { updateUser, updateArticles } from './actions'
|
||||||
import reducer from './HomeContainer/reducer'
|
import reducer from './reducer'
|
||||||
import { fetchCurrentUser, fetchArticles } from './HomeContainer/lib/api'
|
import { fetchCurrentUser, fetchArticles } from 'boost/api'
|
||||||
import { Router, Route, IndexRoute } from 'react-router'
|
import { Router, Route, IndexRoute } from 'react-router'
|
||||||
import MainContainer from './Containers/MainContainer'
|
import MainPage from './MainPage'
|
||||||
import LoginContainer from './Containers/LoginContainer'
|
import LoginPage from './LoginPage'
|
||||||
import SignupContainer from './Containers/SignupContainer'
|
import SignupPage from './SignupPage'
|
||||||
import HomeContainer from './HomeContainer'
|
import HomePage from './HomePage'
|
||||||
require('../styles/main/index.styl')
|
require('../styles/main/index.styl')
|
||||||
|
|
||||||
function onlyUser (state, replaceState) {
|
function onlyUser (state, replaceState) {
|
||||||
@@ -18,11 +18,11 @@ function onlyUser (state, replaceState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let routes = (
|
let routes = (
|
||||||
<Route path='/' component={MainContainer}>
|
<Route path='/' component={MainPage}>
|
||||||
<Route name='login' path='login' component={LoginContainer}/>
|
<Route name='login' path='login' component={LoginPage}/>
|
||||||
<Route name='signup' path='signup' component={SignupContainer}/>
|
<Route name='signup' path='signup' component={SignupPage}/>
|
||||||
<IndexRoute name='home' component={HomeContainer} onEnter={onlyUser}/>
|
<IndexRoute name='home' component={HomePage} onEnter={onlyUser}/>
|
||||||
<Route name='user' path='/users/:userId' component={HomeContainer} onEnter={onlyUser}/>
|
<Route name='user' path='/users/:userId' component={HomePage} onEnter={onlyUser}/>
|
||||||
</Route>
|
</Route>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,17 @@
|
|||||||
var request = require('superagent-promise')(require('superagent'), Promise)
|
var request = require('superagent-promise')(require('superagent'), Promise)
|
||||||
var apiUrl = require('../../../../config').apiUrl
|
var apiUrl = require('../config').apiUrl
|
||||||
|
|
||||||
|
export function login (input) {
|
||||||
|
return request
|
||||||
|
.post(apiUrl + 'auth/login')
|
||||||
|
.send(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signup (input) {
|
||||||
|
return request
|
||||||
|
.post(apiUrl + 'auth/register')
|
||||||
|
.send(input)
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchCurrentUser () {
|
export function fetchCurrentUser () {
|
||||||
return request
|
return request
|
||||||
@@ -49,3 +61,12 @@ export function deleteMember (teamId, input) {
|
|||||||
})
|
})
|
||||||
.send(input)
|
.send(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function sendEmail (input) {
|
||||||
|
return request
|
||||||
|
.post(apiUrl + 'mail')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
.send(input)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
var React = require('react')
|
import React from 'react'
|
||||||
|
|
||||||
var ace = window.ace
|
var ace = window.ace
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import shell from 'shell'
|
import shell from 'shell'
|
||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import markdown from '../HomeContainer/lib/markdown'
|
import markdown from 'boost/markdown'
|
||||||
|
|
||||||
function handleAnchorClick (e) {
|
function handleAnchorClick (e) {
|
||||||
shell.openExternal(e.target.href)
|
shell.openExternal(e.target.href)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { PropTypes, findDOMNode } from 'react'
|
import React, { PropTypes, findDOMNode } from 'react'
|
||||||
import linkState from '../helpers/linkState'
|
import linkState from 'boost/linkState'
|
||||||
var Hq = require('../Services/Hq')
|
import { sendEmail } from 'boost/api'
|
||||||
|
|
||||||
export default class ContactModal extends React.Component {
|
export default class ContactModal extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -37,7 +37,7 @@ export default class ContactModal extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendEmail () {
|
sendEmail () {
|
||||||
Hq.sendEmail(this.state.mail)
|
sendEmail(this.state.mail)
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
this.setState({isSent: !this.state.isSent})
|
this.setState({isSent: !this.state.isSent})
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ProfileImage from '../../../components/ProfileImage'
|
import ProfileImage from 'boost/components/ProfileImage'
|
||||||
import { searchUser, createTeam, setMember, deleteMember } from '../api'
|
import { searchUser, createTeam, setMember, deleteMember } from 'boost/api'
|
||||||
import linkState from '../../../helpers/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import Select from 'react-select'
|
import Select from 'react-select'
|
||||||
|
|
||||||
function getUsers (input, cb) {
|
function getUsers (input, cb) {
|
||||||
8
main.js
8
main.js
@@ -21,7 +21,7 @@ var update = null
|
|||||||
var version = app.getVersion()
|
var version = app.getVersion()
|
||||||
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
||||||
var nn = require('node-notifier')
|
var nn = require('node-notifier')
|
||||||
var updater = require('./updater')
|
var updater = require('./atom-lib/updater')
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
|
|
||||||
var appQuit = false
|
var appQuit = false
|
||||||
@@ -48,7 +48,7 @@ app.on('ready', function () {
|
|||||||
updater.setFeedUrl('http://orbital.b00st.io/rokt33r/boost/latest?version=' + version)
|
updater.setFeedUrl('http://orbital.b00st.io/rokt33r/boost/latest?version=' + version)
|
||||||
updater.checkForUpdates()
|
updater.checkForUpdates()
|
||||||
// menu start
|
// menu start
|
||||||
var template = require('./modules/menu-template')
|
var template = require('./atom-lib/menu-template')
|
||||||
|
|
||||||
ipc.on('update-app', function (event, msg) {
|
ipc.on('update-app', function (event, msg) {
|
||||||
if (update != null) {
|
if (update != null) {
|
||||||
@@ -78,7 +78,7 @@ app.on('ready', function () {
|
|||||||
}))
|
}))
|
||||||
appIcon.setContextMenu(trayMenu)
|
appIcon.setContextMenu(trayMenu)
|
||||||
|
|
||||||
mainWindow = require('./main-window')
|
mainWindow = require('./atom-lib/main-window')
|
||||||
mainWindow.on('close', function (e) {
|
mainWindow.on('close', function (e) {
|
||||||
if (appQuit) return true
|
if (appQuit) return true
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -95,7 +95,7 @@ app.on('ready', function () {
|
|||||||
mainWindow.show()
|
mainWindow.show()
|
||||||
})
|
})
|
||||||
|
|
||||||
finderWindow = require('./finder-window')
|
finderWindow = require('./atom-lib/finder-window')
|
||||||
|
|
||||||
var globalShortcut = require('global-shortcut')
|
var globalShortcut = require('global-shortcut')
|
||||||
console.log('jetpack launch')
|
console.log('jetpack launch')
|
||||||
|
|||||||
1
node_modules/boost
generated
vendored
Symbolic link
1
node_modules/boost
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../lib
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"version": "--version=0.33.0 --app-version=$npm_package_version --app-bundle-id=com.maisin.boost",
|
"version": "--version=0.33.0 --app-version=$npm_package_version --app-bundle-id=com.maisin.boost",
|
||||||
"platform": "--platform=darwin --arch=x64 --prune --icon=app.icns",
|
"platform": "--platform=darwin --arch=x64 --prune --icon=resources/app.icns",
|
||||||
"ignore": "--ignore=Boost-darwin-x64 --ignore=node_modules/devicon/icons --ignore=submodules/ace/(?!src-min)|submodules/ace/(?=src-min-noconflict)"
|
"ignore": "--ignore=Boost-darwin-x64 --ignore=node_modules/devicon/icons --ignore=submodules/ace/(?!src-min)|submodules/ace/(?=src-min-noconflict)"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -73,7 +73,6 @@
|
|||||||
},
|
},
|
||||||
"standard": {
|
"standard": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"/browser/ace/"
|
|
||||||
],
|
],
|
||||||
"globals": [
|
"globals": [
|
||||||
"localStorage"
|
"localStorage"
|
||||||
|
|||||||
Reference in New Issue
Block a user