Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions frontend/interfaces/errors500.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import PropTypes from 'prop-types';

export default PropTypes.shape({
http_status: PropTypes.number,
base: PropTypes.string,
});
82 changes: 78 additions & 4 deletions frontend/pages/Kolide500/Kolide500.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,72 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { noop } from 'lodash';
import { resetErrors } from 'redux/nodes/errors500/actions';
import errorsInterface from 'interfaces/errors500';

import kolideLogo from '../../../assets/images/kolide-logo-condensed.svg';
import gopher from '../../../assets/images/500.svg';

const baseClass = 'kolide-500';

class Kolide404 extends Component {
class Kolide500 extends Component {
static propTypes = {
errors: errorsInterface,
dispatch: PropTypes.func,
};

static defaultProps = {
dispatch: noop,
};

constructor (props) {
super(props);

this.state = {
showErrorMessage: false,
};
}

componentWillUnmount() {
const { dispatch } = this.props;
dispatch(resetErrors());
}

onShowErrorMessage = () => {
this.setState({ showErrorMessage: true });
}

renderError = () => {
const { errors } = this.props;
const errorMessage = errors ? errors.base : null;
const { showErrorMessage } = this.state;
const { onShowErrorMessage } = this;

if (errorMessage && !showErrorMessage) {
// We only show the button when errorMessage exists
// and showErrorMessage is set to false
return (
<button className="button button--muted" onClick={onShowErrorMessage}>SHOW ERROR</button>
);
}

if (errorMessage && showErrorMessage) {
// We only show the error message when errorMessage exists
// and showErrorMessage is set to true
return (
<div className="error-message-container">
<p>{errorMessage}</p>
</div>
);
}

return false;
}

render () {
const { renderError } = this;

return (
<div className={baseClass}>
<header className="primary-header">
Expand All @@ -18,15 +78,29 @@ class Kolide404 extends Component {
<h1>Uh oh!</h1>
<h2>Error 500</h2>
<p>Something went wrong on our end.</p>
<p>We have alerted the engineers and they are working on a solution.</p>
{renderError()}
<p>Please file an issue if you believe this is a bug.</p>
<a
href="https://github.com/fleetdm/fleet/issues"
target="_blank"
rel="noopener noreferrer"
>
File an issue
</a>
<div className="gopher-container">
<img src={gopher} alt="" />
<p>Need assistance? <a href="https://github.com/kolide/fleet/issues">File an issue</a>.</p>
</div>
</main>
</div>
);
}
}

export default Kolide404;
const mapStateToProps = (state) => {
const { errors } = state.errors500;
return {
errors,
};
};

export default connect(mapStateToProps)(Kolide500);
4 changes: 4 additions & 0 deletions frontend/pages/Kolide500/_styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
}
}

.error-message-container {
display: inline;
}

main {
text-align: center;

Expand Down
7 changes: 7 additions & 0 deletions frontend/redux/nodes/errors500/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const RESET_ERRORS = 'RESET_ERRORS';

export const resetErrors = () => {
return {
type: RESET_ERRORS,
};
};
22 changes: 22 additions & 0 deletions frontend/redux/nodes/errors500/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
RESET_ERRORS,
} from './actions';

const initialState = {
errors: null,
};

const reducer = (state = initialState, { type, payload }) => {
if (payload && payload.errors) {
return {
errors: payload.errors,
};
} else if (type === RESET_ERRORS) {
return {
errors: null,
};
}
return state;
};

export default reducer;
39 changes: 39 additions & 0 deletions frontend/redux/nodes/errors500/reducer.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import expect from 'expect';

import reducer from './reducer';

describe('Errors - reducer', () => {
it('Updates state with errors object when an action that has a payload with an errors object is dispatched', () => {
const payload = {
errors: {
base: "inserting pack: Error 1136: Column count doesn't match value count at row 1",
http_status: 500,
},
};
const packsCreateFailureAction = { type: 'packs_CREATE_FAILURE', payload };
const initialState = {
errors: null,
};
const newState = reducer(initialState, packsCreateFailureAction);

expect(newState).toEqual({
errors: {
base: "inserting pack: Error 1136: Column count doesn't match value count at row 1",
http_status: 500,
},
});
});

it('Updates state by setting errors to null when the RESET_ERRORS action is dipatched', () => {
const errorsState = {
errors: {
base: "inserting pack: Error 1136: Column count doesn't match value count at row 1",
http_status: 500,
},
};
const newState = reducer(errorsState, { type: 'RESET_ERRORS' });
expect(newState).toEqual({
errors: null,
});
});
});
2 changes: 2 additions & 0 deletions frontend/redux/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import app from './nodes/app/reducer';
import auth from './nodes/auth/reducer';
import components from './nodes/components/reducer';
import entities from './nodes/entities/reducer';
import errors500 from './nodes/errors500/reducer';
import notifications from './nodes/notifications/reducer';
import persistentFlash from './nodes/persistent_flash/reducer';
import redirectLocation from './nodes/redirectLocation/reducer';
Expand All @@ -15,6 +16,7 @@ export default combineReducers({
auth,
components,
entities,
errors500,
loadingBar: loadingBarReducer,
notifications,
persistentFlash,
Expand Down