add server rendering of loaded compares and clean up saving of compares, switch to using isomorphic fetch (and save much compiled size)
This commit is contained in:
parent
0a3a37e64e
commit
6bb76ccd17
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,3 +7,6 @@ data/*
|
|||||||
|
|
||||||
browser-bundle.js.map
|
browser-bundle.js.map
|
||||||
npm-debug.log.*
|
npm-debug.log.*
|
||||||
|
|
||||||
|
stats.json
|
||||||
|
stats.analyzed.txt
|
||||||
|
21781
dist/browser-bundle.js
vendored
21781
dist/browser-bundle.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/themes/default/assets/fonts/icons.woff2
vendored
Normal file
BIN
dist/themes/default/assets/fonts/icons.woff2
vendored
Normal file
Binary file not shown.
@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "src/server/babel.index.js",
|
"main": "src/server/babel.index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"copy-css": "copyfiles -f ./node_modules/semantic-ui-css/semantic.min.css ./dist",
|
"copy-css": "cpy --parents --cwd=./node_modules/semantic-ui-css semantic.min.css themes/default/assets/fonts/icons.woff2 ../../dist",
|
||||||
"build": "npm run copy-css && webpack --colors",
|
"build": "npm run copy-css && webpack --colors",
|
||||||
"start": "npm run copy-css && webpack --progress --colors --watch",
|
"start": "npm run copy-css && webpack --progress --colors --watch",
|
||||||
"serve": "node src/server/babel.index.js",
|
"serve": "node src/server/babel.index.js",
|
||||||
@ -20,15 +20,15 @@
|
|||||||
"body-parser": "^1.15.2",
|
"body-parser": "^1.15.2",
|
||||||
"diff": "^3.0.1",
|
"diff": "^3.0.1",
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"jsonfile": "^2.4.0",
|
"jsonfile": "^2.4.0",
|
||||||
"markdown-it": "^5.1.0",
|
"markdown-it": "^5.1.0",
|
||||||
"markdown-to-jsx": "^4.0.3",
|
"markdown-to-jsx": "^4.0.3",
|
||||||
"react": "^0.14.5",
|
"react": "^0.14.5",
|
||||||
"react-dom": "^0.14.5",
|
"react-dom": "^0.14.5",
|
||||||
"react-redux": "^4.4.6",
|
"react-redux": "^4.4.6",
|
||||||
"react-router": "^1.0.0",
|
"react-router": "~3.0.0",
|
||||||
"redux": "^3.5.1",
|
"redux": "^3.5.1",
|
||||||
"redux-router": "^1.0.0-beta5",
|
|
||||||
"redux-thunk": "^2.1.0",
|
"redux-thunk": "^2.1.0",
|
||||||
"request": "^2.79.0",
|
"request": "^2.79.0",
|
||||||
"request-promise-native": "^1.0.3",
|
"request-promise-native": "^1.0.3",
|
||||||
|
@ -5,8 +5,8 @@ import * as Redux from 'redux'
|
|||||||
|
|
||||||
import {Provider} from 'react-redux'
|
import {Provider} from 'react-redux'
|
||||||
|
|
||||||
import createBrowserHistory from 'history/lib/createBrowserHistory'
|
//import createBrowserHistory from 'history/lib/createBrowserHistory'
|
||||||
import {Router, Route, IndexRoute, Redirect } from 'react-router'
|
import {Router, Route, IndexRoute, Redirect, browserHistory } from 'react-router'
|
||||||
|
|
||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
|
|
||||||
@ -38,8 +38,11 @@ const store = Redux.createStore(
|
|||||||
Redux.applyMiddleware(...middlewares)
|
Redux.applyMiddleware(...middlewares)
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(store)
|
//this way of reading local input isn't working:
|
||||||
|
// it's just overriding what comes from the server
|
||||||
|
// and it's not respecting the comparison that is loaded from the server
|
||||||
|
|
||||||
|
/*
|
||||||
const localInput = localStore.get('dubdiff')
|
const localInput = localStore.get('dubdiff')
|
||||||
if (localInput.input) {
|
if (localInput.input) {
|
||||||
//dispatch localStore data to store
|
//dispatch localStore data to store
|
||||||
@ -47,6 +50,7 @@ if (localInput.input) {
|
|||||||
store.dispatch(Actions.updateFinalInput(localInput.input.final))
|
store.dispatch(Actions.updateFinalInput(localInput.input.final))
|
||||||
//should this be done after the first render?
|
//should this be done after the first render?
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//save the state whenever the state changes
|
//save the state whenever the state changes
|
||||||
function saveState() {
|
function saveState() {
|
||||||
@ -60,7 +64,7 @@ store.subscribe(saveState)
|
|||||||
function render() {
|
function render() {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router history={createBrowserHistory()}>
|
<Router history={browserHistory}>
|
||||||
{routes}
|
{routes}
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import requestPromise from 'request-promise-native'
|
import fetch from 'isomorphic-fetch'
|
||||||
import uuid from 'uuid/v4'
|
import uuid from 'uuid/v4'
|
||||||
|
|
||||||
export const updateOriginalInput = (text) =>
|
export const updateOriginalInput = (text) =>
|
||||||
@ -24,43 +24,82 @@ export const clearInput = () =>
|
|||||||
dispatch({ type: 'SAVE_STATUS_EMPTY'})
|
dispatch({ type: 'SAVE_STATUS_EMPTY'})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateOriginalCompare = (text) => ({ type: 'UPDATE_ORIGINAL_COMPARE', data:text})
|
|
||||||
export const updateFinalCompare = (text) => ({ type: 'UPDATE_FINAL_COMPARE', data:text})
|
|
||||||
export const clearCompare = () => ({ type: 'CLEAR_COMPARE'})
|
|
||||||
export const setPlaintextFormat = () => ({ type: 'SET_PLAINTEXT_FORMAT'})
|
export const setPlaintextFormat = () => ({ type: 'SET_PLAINTEXT_FORMAT'})
|
||||||
export const setMarkdownFormat = () => ({ type: 'SET_MARKDOWN_FORMAT'})
|
export const setMarkdownFormat = () => ({ type: 'SET_MARKDOWN_FORMAT'})
|
||||||
export const showOriginal = () => ({ type: 'SHOW_ORIGINAL'})
|
export const showOriginal = () => ({ type: 'SHOW_ORIGINAL'})
|
||||||
export const showFinal = () => ({ type: 'SHOW_FINAL'})
|
export const showFinal = () => ({ type: 'SHOW_FINAL'})
|
||||||
export const showDifference = () => ({ type: 'SHOW_DIFFERENCE'})
|
export const showDifference = () => ({ type: 'SHOW_DIFFERENCE'})
|
||||||
|
|
||||||
|
|
||||||
|
//saves the current input fields to the server
|
||||||
|
//creates and returns a new id for the
|
||||||
export const save = () =>
|
export const save = () =>
|
||||||
(dispatch, getState) => {
|
(dispatch, getState) => {
|
||||||
|
|
||||||
console.log("!!! SAVING")
|
|
||||||
|
|
||||||
//generate an id
|
//generate an id
|
||||||
const id = uuid()
|
const id = uuid()
|
||||||
dispatch( {type: 'SAVE_STATUS_ASSIGN_ID', id})
|
|
||||||
|
|
||||||
//set waiting state
|
//set waiting state
|
||||||
dispatch( {type: 'SAVE_STATUS_WAITING'})
|
dispatch( {type: 'SAVE_STATUS_WAITING'})
|
||||||
|
|
||||||
const reqOptions = {
|
const endpointUri = `/api/compare/${id}`
|
||||||
|
const fetchOptions = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: `${location.origin}/api/compare/${id}`,
|
body: JSON.stringify({
|
||||||
body: {
|
|
||||||
a: getState().input.original,
|
a: getState().input.original,
|
||||||
b: getState().input.final
|
b: getState().input.final
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
json: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//dispatch post request
|
//dispatch post request
|
||||||
requestPromise(reqOptions)
|
fetch(endpointUri, fetchOptions)
|
||||||
.then(returnBodyJson => {
|
.then(response => {
|
||||||
dispatch( {type: 'SAVE_STATUS_SAVED'})
|
dispatch( {type: 'SAVE_STATUS_SAVED'})
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
dispatch( {type: 'SAVE_STATUS_FAILED', error})
|
dispatch( {type: 'SAVE_STATUS_FAILED', error})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//return the id after the request has been sent
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
const load = (id) =>
|
||||||
|
(dispatch, getState) => {
|
||||||
|
|
||||||
|
//set waiting state
|
||||||
|
dispatch( {type: 'SAVE_STATUS_WAITING'})
|
||||||
|
|
||||||
|
const endpointUri = `/api/compare/${id}`
|
||||||
|
const fetchOptions = {
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//dispatch post request
|
||||||
|
fetch(endpointUri, fetchOptions)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
dispatch( {type: 'UPDATE_ORIGINAL_INPUT', data:json.a})
|
||||||
|
dispatch( {type: 'UPDATE_FINAL_INPUT', data:json.b})
|
||||||
|
dispatch( {type: 'LOAD_STATUS_LOADED'})
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
dispatch( {type: 'LOAD_STATUS_FAILED', error})
|
||||||
|
})
|
||||||
|
|
||||||
|
//return the id after the request has been sent
|
||||||
|
return id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadIfNeeded = (id) =>
|
||||||
|
(dispatch, getState) => {
|
||||||
|
if
|
||||||
|
}
|
||||||
|
*/
|
@ -18,19 +18,24 @@ const mapStateToProps = (state) => ({
|
|||||||
isShowOriginal: Selectors.isShowOriginal(state),
|
isShowOriginal: Selectors.isShowOriginal(state),
|
||||||
isShowFinal: Selectors.isShowFinal(state),
|
isShowFinal: Selectors.isShowFinal(state),
|
||||||
isShowDifference: Selectors.isShowDifference(state),
|
isShowDifference: Selectors.isShowDifference(state),
|
||||||
compare: state.compare,
|
safeInput: Selectors.safeInput(state),
|
||||||
diff: Selectors.diff(state)
|
diff: Selectors.diff(state)
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
//loadIfNeeded: (id) => dispatch(Actions.loadIfNeeded())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Compare extends React.Component {
|
class Compare extends React.Component {
|
||||||
|
/*
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.loadIfNeeded(this.props.routeParams.compareId)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log({isMarkdownFormat: this.props.isMarkdownFormat, isShowDifference: this.props.isShowDifference})
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header/>
|
<Header/>
|
||||||
@ -49,11 +54,11 @@ class Compare extends React.Component {
|
|||||||
<ShowMarkdown diff={this.props.diff}>{this.props.diff}</ShowMarkdown>:
|
<ShowMarkdown diff={this.props.diff}>{this.props.diff}</ShowMarkdown>:
|
||||||
(!this.props.isMarkdownFormat && !this.props.isShowDifference) ?
|
(!this.props.isMarkdownFormat && !this.props.isShowDifference) ?
|
||||||
<ShowPlaintext
|
<ShowPlaintext
|
||||||
text={this.props.isShowOriginal? this.props.compare.original: this.props.compare.final}
|
text={this.props.isShowOriginal? this.props.safeInput.original: this.props.safeInput.final}
|
||||||
/> :
|
/> :
|
||||||
(this.props.isMarkdownFormat && !this.props.isShowDifference) ?
|
(this.props.isMarkdownFormat && !this.props.isShowDifference) ?
|
||||||
<ShowMarkdown
|
<ShowMarkdown
|
||||||
text={this.props.isShowOriginal? this.props.compare.original: this.props.compare.final}
|
text={this.props.isShowOriginal? this.props.safeInput.original: this.props.safeInput.final}
|
||||||
/> :
|
/> :
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ const mapStateToProps = (state) => ({
|
|||||||
isShowOriginal: Selectors.isShowOriginal(state),
|
isShowOriginal: Selectors.isShowOriginal(state),
|
||||||
isShowFinal: Selectors.isShowFinal(state),
|
isShowFinal: Selectors.isShowFinal(state),
|
||||||
isShowDifference: Selectors.isShowDifference(state),
|
isShowDifference: Selectors.isShowDifference(state),
|
||||||
compare: state.compare
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -22,17 +21,14 @@ const mapDispatchToProps = dispatch => ({
|
|||||||
onShowOriginal: () => dispatch(Actions.showOriginal()),
|
onShowOriginal: () => dispatch(Actions.showOriginal()),
|
||||||
onShowFinal: () => dispatch(Actions.showFinal()),
|
onShowFinal: () => dispatch(Actions.showFinal()),
|
||||||
onShowDifference: () => dispatch(Actions.showDifference()),
|
onShowDifference: () => dispatch(Actions.showDifference()),
|
||||||
onEdit: (compare) => {
|
onEdit: () => {
|
||||||
dispatch(Actions.updateOriginalInput(compare.original))
|
|
||||||
dispatch(Actions.updateFinalInput(compare.final))
|
|
||||||
dispatch(Actions.clearCompare())
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
class CompareControls extends React.Component {
|
class CompareControls extends React.Component {
|
||||||
|
|
||||||
onClickEdit() {
|
onClickEdit() {
|
||||||
this.props.onEdit(this.props.compare)
|
this.props.onEdit()
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickMarkdownFormat() {
|
onClickMarkdownFormat() {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
import {Segment, Header} from 'semantic-ui-react'
|
import {Segment, Header, Rail, Container} from 'semantic-ui-react'
|
||||||
import {Link} from 'react-router'
|
import {Link} from 'react-router'
|
||||||
|
|
||||||
import * as Actions from '../actions'
|
import * as Actions from '../actions'
|
||||||
|
import SaveStatus from './SaveStatus'
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
})
|
})
|
||||||
@ -18,8 +19,20 @@ const mapDispatchToProps = dispatch => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const SiteHeader = (props) => (
|
const SiteHeader = (props) => (
|
||||||
|
|
||||||
|
|
||||||
|
<Segment basic >
|
||||||
|
|
||||||
<Segment basic padded textAlign="center" as="header" id='masthead'>
|
<Segment basic padded textAlign="center" as="header" id='masthead'>
|
||||||
<Link to="/"><Header onClick={props.onClear}>dubdiff</Header></Link>
|
<Header><Link onClick={props.onClear} to="/">dubdiff</Link></Header>
|
||||||
|
</Segment>
|
||||||
|
|
||||||
|
<Rail internal position="right">
|
||||||
|
<Segment basic padded>
|
||||||
|
<SaveStatus/>
|
||||||
|
</Segment>
|
||||||
|
</Rail>
|
||||||
|
|
||||||
</Segment>
|
</Segment>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {Link} from 'react-router'
|
import {browserHistory} from 'react-router'
|
||||||
|
|
||||||
import {Button, Icon, Segment} from 'semantic-ui-react'
|
import {Button, Icon, Segment} from 'semantic-ui-react'
|
||||||
|
|
||||||
@ -10,27 +10,30 @@ import * as Selectors from '../selectors'
|
|||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
format: state.format,
|
format: state.format,
|
||||||
isMarkdownFormat: Selectors.isMarkdownFormat(state),
|
isMarkdownFormat: Selectors.isMarkdownFormat(state),
|
||||||
safeInput: Selectors.safeInput(state)
|
saveStatus: state.saveStatus
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onSetPlaintextFormat: (format) => dispatch(Actions.setPlaintextFormat()),
|
onSetPlaintextFormat: (format) => dispatch(Actions.setPlaintextFormat()),
|
||||||
onSetMarkdownFormat: (format) => dispatch(Actions.setMarkdownFormat()),
|
onSetMarkdownFormat: (format) => dispatch(Actions.setMarkdownFormat()),
|
||||||
onCompare: (safeInput) => {
|
|
||||||
dispatch(Actions.save())
|
//returns an id for the record to be saved
|
||||||
dispatch(Actions.updateOriginalCompare(safeInput.original))
|
startSaveAsync: () => {
|
||||||
dispatch(Actions.updateFinalCompare(safeInput.final))
|
return dispatch(Actions.save())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
class MainControls extends React.Component {
|
class MainControls extends React.Component {
|
||||||
|
|
||||||
onClickCompare() {
|
onClickCompare() {
|
||||||
//generate new id? (or should the id be baked into the link route?)
|
//start saving the input to the server
|
||||||
//post safeInput to db
|
const id = this.props.startSaveAsync()
|
||||||
|
|
||||||
|
//we can use the id created by the save method to build a path
|
||||||
|
const comparePath = `/${id}`
|
||||||
|
browserHistory.replace(comparePath)
|
||||||
|
|
||||||
this.props.onCompare(this.props.safeInput)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +49,7 @@ class MainControls extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Segment.Group>
|
<Segment.Group>
|
||||||
<Segment >
|
<Segment >
|
||||||
<Link to="compare"><Button fluid onClick={this.onClickCompare.bind(this)}>Compare</Button></Link>
|
<Button fluid onClick={this.onClickCompare.bind(this)}>Compare</Button>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
|
||||||
<Segment >
|
<Segment >
|
||||||
|
52
src/common/components/SaveStatus.js
Normal file
52
src/common/components/SaveStatus.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
|
import { Message, Icon, Button} from 'semantic-ui-react'
|
||||||
|
import { browserHistory} from 'react-router'
|
||||||
|
|
||||||
|
import * as Actions from '../actions'
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
saveStatus: state.saveStatus
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
retrySave: () => dispatch(Actions.save())
|
||||||
|
})
|
||||||
|
|
||||||
|
const onRetrySaveClick = (props) => {
|
||||||
|
//we can use the id created by the save method to build a path
|
||||||
|
const id = props.retrySave()
|
||||||
|
const comparePath = `/${id}`
|
||||||
|
browserHistory.replace(comparePath)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const SaveStatus = (props) => {
|
||||||
|
if (props.saveStatus.waiting) return (
|
||||||
|
<Message size='tiny' floating compact icon>
|
||||||
|
<Icon name='circle notched' loading />
|
||||||
|
<Message.Content>
|
||||||
|
<Message.Header>Saving diff</Message.Header>
|
||||||
|
</Message.Content>
|
||||||
|
</Message>
|
||||||
|
)
|
||||||
|
else if (props.saveStatus.failed) return (
|
||||||
|
<Message size='tiny' floating compact icon>
|
||||||
|
<Icon name='exclamation' />
|
||||||
|
<Message.Content>
|
||||||
|
<Message.Header>Error saving diff</Message.Header>
|
||||||
|
The server returned {props.saveStatus.error.message}.
|
||||||
|
<Button onClick={()=>onRetrySaveClick(props)}>Retry</Button>
|
||||||
|
</Message.Content>
|
||||||
|
</Message>
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
else return ( <div></div> )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(SaveStatus)
|
10
src/common/constants.js
Normal file
10
src/common/constants.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const Format = {
|
||||||
|
PLAINTEXT: 'PLAINTEXT',
|
||||||
|
MARKDOWN: 'MARKDOWN'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Show = {
|
||||||
|
ORIGINAL:'ORIGINAL',
|
||||||
|
FINAL:'FINAL',
|
||||||
|
DIFFERENCE:'DIFFERENCE'
|
||||||
|
}
|
@ -14,20 +14,6 @@ export function input (state, action ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compare (state, action ) {
|
|
||||||
switch (action.type) {
|
|
||||||
case 'UPDATE_ORIGINAL_COMPARE':
|
|
||||||
return Object.assign({}, state, {original:action.data})
|
|
||||||
case 'UPDATE_FINAL_COMPARE':
|
|
||||||
return Object.assign({}, state, {final:action.data})
|
|
||||||
case 'CLEAR_COMPARE':
|
|
||||||
return {original:'', final:''}
|
|
||||||
default:
|
|
||||||
return state || {original:'', final:''}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function format (state, action) {
|
export function format (state, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SET_PLAINTEXT_FORMAT':
|
case 'SET_PLAINTEXT_FORMAT':
|
||||||
@ -57,18 +43,30 @@ export function show (state, action) {
|
|||||||
export function saveStatus (state, action) {
|
export function saveStatus (state, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'SAVE_STATUS_DIRTY':
|
case 'SAVE_STATUS_DIRTY':
|
||||||
return {dirty:true, id:null}
|
return {dirty: true}
|
||||||
case 'SAVE_STATUS_EMPTY':
|
case 'SAVE_STATUS_EMPTY':
|
||||||
return {dirty:false, id:null}
|
return {dirty: false, empty: true}
|
||||||
case 'SAVE_STATUS_SAVED':
|
case 'SAVE_STATUS_SAVED':
|
||||||
return Object.assign({}, state, {waiting: false, dirty:false, failed: false, error:null})
|
return {dirty: false, saved: true}
|
||||||
case 'SAVE_STATUS_FAILED' :
|
case 'SAVE_STATUS_FAILED' :
|
||||||
return Object.assign({}, state, {waiting: false, failed: true, error: action.error})
|
return Object.assign({}, state, {waiting: false, failed: true, error: action.error})
|
||||||
case 'SAVE_STATUS_WAITING' :
|
case 'SAVE_STATUS_WAITING' :
|
||||||
return Object.assign({}, state, {waiting: true, failed: false, error: null})
|
return Object.assign({}, state, {waiting: true, failed: false, error: null})
|
||||||
case 'SAVE_STATUS_ASSIGN_ID':
|
|
||||||
return Object.assign({}, state, {id: action.id})
|
|
||||||
default:
|
default:
|
||||||
return state || {empty: true, dirty:false, id:null}
|
return state || {empty: true, dirty:false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
export function loadStatus (state, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'LOAD_STATUS_WAITING':
|
||||||
|
return {waiting: true}
|
||||||
|
case 'LOAD_STATUS_FAILED':
|
||||||
|
return {failed: true, error: action.error }
|
||||||
|
case 'LOAD_STATUS_LOADED':
|
||||||
|
return {loaded: true}
|
||||||
|
default:
|
||||||
|
return state || {waiting: false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -13,7 +13,6 @@ import * as Dubdiff from './util/dubdiff'
|
|||||||
const input = (state) => state.input
|
const input = (state) => state.input
|
||||||
const format = (state) => state.format
|
const format = (state) => state.format
|
||||||
const show = (state) => state.show
|
const show = (state) => state.show
|
||||||
const compare = (state) => state.compare
|
|
||||||
|
|
||||||
export const safeInput = createSelector(
|
export const safeInput = createSelector(
|
||||||
[input],
|
[input],
|
||||||
@ -43,9 +42,9 @@ export const isShowDifference= isShow(Show.DIFFERENCE)
|
|||||||
|
|
||||||
|
|
||||||
export const diff = createSelector(
|
export const diff = createSelector(
|
||||||
[format, compare],
|
[format, safeInput],
|
||||||
(format, compare) => {
|
(format, safeInput) => {
|
||||||
return Dubdiff.plaintextDiff(compare.original, compare.final)
|
return Dubdiff.plaintextDiff(safeInput.original, safeInput.final)
|
||||||
/*
|
/*
|
||||||
let diff = JsDiff.diffWords (input.original.replace(/ /g, ' '), input.final.replace(/ /g, ' '))
|
let diff = JsDiff.diffWords (input.original.replace(/ /g, ' '), input.final.replace(/ /g, ' '))
|
||||||
return diff.map(({added, removed, value})=>({added, removed, value:value.replace(/ /g, ' ')})).map(part => (
|
return diff.map(({added, removed, value})=>({added, removed, value:value.replace(/ /g, ' ')})).map(part => (
|
||||||
|
@ -31,7 +31,6 @@ function createComparisonWithId(req, res) {
|
|||||||
const id = req.params.id
|
const id = req.params.id
|
||||||
const {a, b} = req.body
|
const {a, b} = req.body
|
||||||
|
|
||||||
|
|
||||||
return writeRecord(res, id, {a, b, id})
|
return writeRecord(res, id, {a, b, id})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,12 +81,12 @@ function writeRecord(res, id, data) {
|
|||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
||||||
function handleError(res, err) {
|
function handleError(res, err) {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
return res.send(500, err);
|
return res.send(500, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns a filename for the given comparison
|
// returns a filename for the given comparison
|
||||||
function fnData (id) {
|
function fnData (id) {
|
||||||
return "./data/" + "id-" + id + ".json";
|
return `./data/${id}.json`
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ import path from 'path'
|
|||||||
import bodyParser from 'body-parser'
|
import bodyParser from 'body-parser'
|
||||||
import * as Redux from 'redux'
|
import * as Redux from 'redux'
|
||||||
|
|
||||||
|
import fetch from 'isomorphic-fetch'
|
||||||
|
|
||||||
import comparisonRouter from './comparison'
|
import comparisonRouter from './comparison'
|
||||||
|
|
||||||
|
|
||||||
@ -11,6 +13,8 @@ import * as actions from '../common/actions'
|
|||||||
|
|
||||||
import render from './render'
|
import render from './render'
|
||||||
|
|
||||||
|
const PORT = 8080
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
//serve the dist static files at /dist
|
//serve the dist static files at /dist
|
||||||
@ -24,27 +28,40 @@ app.use('/api/compare', comparisonRouter);
|
|||||||
|
|
||||||
//the following routes are for server-side rendering of the app
|
//the following routes are for server-side rendering of the app
|
||||||
|
|
||||||
//eventually, we should render the comparison directly from the server
|
//we should render the comparison directly from the server
|
||||||
/*
|
|
||||||
|
//this is garbage, we should use a robust method for loading comparisons, parallel to how saving works
|
||||||
|
//comparisons should be loaded isomorphically
|
||||||
app.route('/:comparisonId')
|
app.route('/:comparisonId')
|
||||||
.get((req, res) => {
|
.get((req, res) => {
|
||||||
|
|
||||||
const store = createSessionStore()
|
const store = createSessionStore()
|
||||||
...
|
|
||||||
|
//fetch the comparison
|
||||||
|
fetchComparison(req.params.comparisonId)
|
||||||
|
.then( ({a,b}) => {
|
||||||
|
store.dispatch({type: 'UPDATE_ORIGINAL_INPUT', data: a})
|
||||||
|
store.dispatch({type: 'UPDATE_FINAL_INPUT', data: b})
|
||||||
|
render(store, req, res)
|
||||||
|
})
|
||||||
|
.catch( error => {
|
||||||
|
//... what to do here?
|
||||||
|
console.log(`Error fetching comparison with id ${req.params.comparisonId}`, error)
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
app.route('/'). ...
|
app.route('/')
|
||||||
*/
|
.get((req, res) => {
|
||||||
|
render(createSessionStore(), req, res)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
//but for now, let's just render the app and let it fetch comparison data
|
app.listen(PORT, function () {
|
||||||
app.use((req, res) => render(createSessionStore(), req, res))
|
|
||||||
|
|
||||||
app.listen(8080, function () {
|
|
||||||
console.log('Server listening on port 8080.')
|
console.log('Server listening on port 8080.')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
//this is pretty much redundant at this point
|
//creates the session store
|
||||||
function createSessionStore() {
|
function createSessionStore() {
|
||||||
//create the redux store
|
//create the redux store
|
||||||
return Redux.createStore(
|
return Redux.createStore(
|
||||||
@ -53,7 +70,16 @@ function createSessionStore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function fetchComparison(id) {
|
||||||
|
const endpointUri = `http://localhost:${PORT}/api/compare/${id}`
|
||||||
|
const fetchOptions = {
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
|
||||||
|
//dispatch post request
|
||||||
|
return fetch(endpointUri, fetchOptions)
|
||||||
|
.then(response => response.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//router.get('/', controller.index);
|
//router.get('/', controller.index);
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { renderToString } from 'react-dom/server'
|
import { renderToString } from 'react-dom/server'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { match, RoutingContext } from 'react-router'
|
import { match, RouterContext } from 'react-router'
|
||||||
|
|
||||||
import routes from '../common/routes.js'
|
import routes from '../common/routes.js'
|
||||||
|
|
||||||
|
|
||||||
export default function render(store, req, res) {
|
export default function render(store, req, res) {
|
||||||
console.log(store.getState())
|
|
||||||
|
|
||||||
// Send the rendered page back to the client
|
// Send the rendered page back to the client
|
||||||
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
|
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
res.status(500).send(renderError('Routing Error', error.message))
|
console.log(error)
|
||||||
|
res.status(500).send(renderError('Routing Error:', error.message))
|
||||||
} else if (redirectLocation) {
|
} else if (redirectLocation) {
|
||||||
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
|
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
|
||||||
} else if (renderProps) {
|
} else if (renderProps) {
|
||||||
@ -20,7 +19,7 @@ export default function render(store, req, res) {
|
|||||||
try {
|
try {
|
||||||
const html = renderToString(
|
const html = renderToString(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<RoutingContext {...renderProps} />
|
<RouterContext {...renderProps} />
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,6 +29,7 @@ export default function render(store, req, res) {
|
|||||||
res.status(200).send(appTemplate(html, initialState))
|
res.status(200).send(appTemplate(html, initialState))
|
||||||
}
|
}
|
||||||
catch(ex) {
|
catch(ex) {
|
||||||
|
console.log("Render Exception:",ex)
|
||||||
res.status(500).send(errorTemplate('Render Exception', ex.message, ex))
|
res.status(500).send(errorTemplate('Render Exception', ex.message, ex))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user