fixed server-side diff loading

This commit is contained in:
Adam Brown 2016-12-17 10:21:00 -05:00
parent d66292047f
commit 660c6e6b19
9 changed files with 2122 additions and 2407 deletions

4434
dist/browser-bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@ -18,9 +18,6 @@ const stateName = "dubdiff_state"
//from the given object
const copyKeys = (obj, keys) => keys.reduce((acc, p)=>{acc[p]=obj[p]; return acc}, {})
console.log(copyKeys({a:1, b:2}, ['a']))
console.log(copyKeys({}, ['a']))
//utility method for retrieving json data from the local store
function getLocalState (keys) {
if (localStorage.getItem(stateName)) {
@ -55,6 +52,7 @@ class LocalStorage extends React.Component {
//load the state from the local storage
componentDidMount() {
//only if the status is EMPTY
/*
if (this.props.input.original=='' && this.props.input.final == '') {
const localState = getLocalState(['input'])
if (localState.input && localState.input.original)
@ -62,6 +60,7 @@ class LocalStorage extends React.Component {
if (localState.input && localState.input.final)
this.props.onChangeFinal(localState.input.final)
}
*/
}
//save the state to local storage
componentWillReceiveProps(nextProps) {

View File

@ -21,6 +21,8 @@ import LocalStorage from './LocalStorage'
//initial state is rehydrated from the server
const initialState = window.__INITIAL_STATE__
console.log('initialState', initialState)
//create the redux store
//initial state is retrieved from localStore
const store = Redux.createStore(

View File

@ -98,9 +98,18 @@ export const save = () =>
//dispatch post request
fetch(endpointUri, fetchOptions)
.then(response => {
dispatch({type: 'STATUS_SET', data: Status.CLEAN})
if (response.ok)
dispatch({type: 'STATUS_SET', data: Status.CLEAN})
else {
response.text().then( (responseText) => {
const error = {message:`${response.status}: ${responseText}`}
dispatch({type: 'STATUS_SET', data: Status.DIRTY})
dispatch({type: 'STATUS_SET_ERROR', data: StatusError.SAVE_ERROR, error})
})
}
})
.catch(error => {
//!!! could use a better error message here
dispatch({type: 'STATUS_SET', data: Status.DIRTY})
dispatch({type: 'STATUS_SET_ERROR', data: StatusError.SAVE_ERROR, error})
})

View File

@ -13,11 +13,11 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = dispatch => ({
onSave: () => dispatch(Actions.save())
onSave: () => dispatch(Actions.save()),
onReset: () => dispatch(Actions.reset())
})
const SaveStatus = (props) => {
console.log(props.status)
if (props.status.type == Status.SAVING) return (
<Message size='tiny' floating compact icon>
<Icon name='circle notched' loading />
@ -40,6 +40,7 @@ const SaveStatus = (props) => {
<Message.Content>
<Message.Header>Error saving diff</Message.Header>
{props.status.error.message}
<br/>
<Button onClick={props.onSave}>Retry</Button>
</Message.Content>
</Message>
@ -49,7 +50,9 @@ const SaveStatus = (props) => {
<Icon name='exclamation' />
<Message.Content>
<Message.Header>Error loading diff</Message.Header>
Server returned {props.status.error}
{props.status.error.message}
<br/>
<Button onClick={props.onReset}>New Diff</Button>
</Message.Content>
</Message>
)

View File

@ -19,6 +19,6 @@ export const Status = {
}
export const StatusError = {
LOADING_ERROR: 'LOAD_ERROR',
SAVING_ERROR: 'SAVE_ERROR'
LOAD_ERROR: 'LOAD_ERROR',
SAVE_ERROR: 'SAVE_ERROR'
}

View File

@ -71,5 +71,5 @@ export function status (state, action) {
else if (action.type == 'STATUS_SET_ERROR' && isValidError(action.data))
return Object.assign({}, state, {error: action.error, hasError: true, errorType:action.data})
else
return {type:Status.EMPTY, hasError: false, error:null}
return state || {type:Status.EMPTY, hasError: false, error:null}
}

View File

@ -9,7 +9,8 @@ import comparisonRouter from './comparison'
import * as reducers from '../common/reducers'
import * as actions from '../common/actions'
import {Status, StatusError} from '../common/constants'
import render from './render'
@ -27,27 +28,33 @@ app.use('/api/compare', comparisonRouter);
//the following routes are for server-side rendering of the app
//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
//this loading logic could be moved into ../common/actions because it is isomorphic
app.route('/:comparisonId')
.get((req, res) => {
const store = createSessionStore()
const endpointUri = `http://localhost:${PORT}/api/compare/${req.params.comparisonId}`
//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)
})
fetch(endpointUri)
.then(response => {
if (response.ok)
return response.json()
else {
response.text().then( () => {
const error = {message:`${response.status}: ${response.statusText}`}
initAndRenderError(error, store, req, res)
})
}
})
.then( ({a,b}) => {
initAndRenderComparison({a,b}, store, req, res)
})
.catch( error => {
initAndRenderError(error, store, req, res)
})
})
app.route('/')
@ -69,17 +76,15 @@ 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())
function initAndRenderComparison({a,b}, store, req, res) {
store.dispatch({type: 'UPDATE_ORIGINAL_INPUT', data: a})
store.dispatch({type: 'UPDATE_FINAL_INPUT', data: b})
store.dispatch({type: 'STATUS_SET', data: Status.CLEAN})
render(store, req, res)
}
//router.get('/', controller.index);
function initAndRenderError(error, store, req, res) {
store.dispatch({type: 'STATUS_SET', data: Status.EMPTY})
store.dispatch({type: 'STATUS_SET_ERROR', data: StatusError.LOAD_ERROR, error})
render(store, req, res)
}

View File

@ -10,7 +10,6 @@ export default function render(store, req, res) {
// Send the rendered page back to the client
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
console.log(error)
res.status(500).send(renderError('Routing Error:', error.message))
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)