diff --git a/SingularityUI/app/actions/api/base.es6 b/SingularityUI/app/actions/api/base.es6
index 223f6838a6..a6ee76a8a7 100644
--- a/SingularityUI/app/actions/api/base.es6
+++ b/SingularityUI/app/actions/api/base.es6
@@ -29,7 +29,7 @@ export function buildApiAction(actionName, opts = {}, keyFunc = undefined) {
function error(err, options, apiResponse, key = undefined) {
const action = { type: ERROR, error: err, key, statusCode: apiResponse.status };
- if (Utils.isIn(apiResponse.status, options.catchStatusCodes) || apiResponse.status === 404 && options.isMainApiCall) {
+ if (Utils.isIn(apiResponse.status, options.catchStatusCodes) || apiResponse.status === 404 && options.renderNotFoundIf404) {
return action;
}
if (apiResponse.status === 502) { // Singularity is deploying
diff --git a/SingularityUI/app/actions/api/history.es6 b/SingularityUI/app/actions/api/history.es6
index 841de9d724..4b3aa8c2df 100644
--- a/SingularityUI/app/actions/api/history.es6
+++ b/SingularityUI/app/actions/api/history.es6
@@ -3,8 +3,9 @@ import Utils from '../../utils';
export const FetchTaskHistory = buildApiAction(
'FETCH_TASK_HISTORY',
- (taskId) => ({
- url: `/history/task/${taskId}`
+ (taskId, renderNotFoundIf404) => ({
+ url: `/history/task/${taskId}`,
+ renderNotFoundIf404
}),
(taskId) => taskId
);
@@ -41,9 +42,9 @@ export const FetchTaskHistoryForDeploy = buildApiAction(
export const FetchDeployForRequest = buildApiAction(
'FETCH_DEPLOY',
- (requestId, deployId, isMainApiCall) => ({
+ (requestId, deployId, renderNotFoundIf404) => ({
url: `/history/request/${requestId}/deploy/${deployId}`,
- isMainApiCall
+ renderNotFoundIf404
})
);
diff --git a/SingularityUI/app/actions/api/requests.es6 b/SingularityUI/app/actions/api/requests.es6
index 5d2a3ebd18..b84efa2676 100644
--- a/SingularityUI/app/actions/api/requests.es6
+++ b/SingularityUI/app/actions/api/requests.es6
@@ -19,8 +19,9 @@ export const FetchRequestsInState = buildApiAction(
export const FetchRequest = buildApiAction(
'FETCH_REQUEST',
- (requestId) => ({
- url: `/requests/request/${requestId}`
+ (requestId, renderNotFoundIf404) => ({
+ url: `/requests/request/${requestId}`,
+ renderNotFoundIf404
}),
(requestId) => requestId
);
diff --git a/SingularityUI/app/components/deployDetail/DeployDetail.jsx b/SingularityUI/app/components/deployDetail/DeployDetail.jsx
index 80d0f3d5df..50c5ebb7a5 100644
--- a/SingularityUI/app/components/deployDetail/DeployDetail.jsx
+++ b/SingularityUI/app/components/deployDetail/DeployDetail.jsx
@@ -21,7 +21,6 @@ import JSONButton from '../common/JSONButton';
import UITable from '../common/table/UITable';
import Column from '../common/table/Column';
import CollapsableSection from '../common/CollapsableSection';
-import NotFound from '../common/NotFound';
import ActiveTasksTable from './ActiveTasksTable';
@@ -307,10 +306,7 @@ class DeployDetail extends React.Component {
}
render() {
- const { notFound, deploy, activeTasks, taskHistory, latestHealthchecks } = this.props;
- if (notFound) {
- return ;
- }
+ const { deploy, activeTasks, taskHistory, latestHealthchecks } = this.props;
return (
{this.renderHeader(deploy)}
@@ -333,7 +329,7 @@ function mapDispatchToProps(dispatch) {
};
}
-function mapStateToProps(state) {
+function mapStateToProps(state, ownProps) {
let latestHealthchecks = _.mapObject(state.api.task, (val) => {
if (val.data && val.data.healthcheckResults && val.data.healthcheckResults.length > 0) {
return _.max(val.data.healthcheckResults, (hc) => {
@@ -346,6 +342,7 @@ function mapStateToProps(state) {
return {
notFound: state.api.deploy.statusCode === 404,
+ pathname: ownProps.location.pathname,
deploy: state.api.deploy.data,
taskHistory: state.api.taskHistoryForDeploy.data,
isTaskHistoryFetching: state.api.taskHistoryForDeploy.isFetching,
diff --git a/SingularityUI/app/components/newDeployForm/NewDeployForm.jsx b/SingularityUI/app/components/newDeployForm/NewDeployForm.jsx
index 3485bbdfc5..17eac5d5c6 100644
--- a/SingularityUI/app/components/newDeployForm/NewDeployForm.jsx
+++ b/SingularityUI/app/components/newDeployForm/NewDeployForm.jsx
@@ -1446,6 +1446,8 @@ class NewDeployForm extends Component {
function mapStateToProps(state, ownProps) {
return {
request: Utils.maybe(state.api.request, [ownProps.params.requestId, 'data']),
+ notFound: Utils.maybe(state.api.request, [ownProps.params.requestId, 'statusCode']) === 404,
+ pathname: ownProps.location.pathname,
form: state.ui.form[FORM_ID],
saveApiCall: state.api.saveDeploy
};
@@ -1464,7 +1466,7 @@ function mapDispatchToProps(dispatch, ownProps) {
});
},
fetchRequest(requestId) {
- return dispatch(FetchRequest.trigger(requestId));
+ return dispatch(FetchRequest.trigger(requestId, true));
},
clearForm() {
return dispatch(ClearForm('newDeployForm'));
diff --git a/SingularityUI/app/components/requestDetail/RequestDetailPage.jsx b/SingularityUI/app/components/requestDetail/RequestDetailPage.jsx
index 021eca7d86..d867da8049 100644
--- a/SingularityUI/app/components/requestDetail/RequestDetailPage.jsx
+++ b/SingularityUI/app/components/requestDetail/RequestDetailPage.jsx
@@ -24,6 +24,8 @@ import TaskHistoryTable from './TaskHistoryTable';
import DeployHistoryTable from './DeployHistoryTable';
import RequestHistoryTable from './RequestHistoryTable';
+import Utils from '../../utils';
+
function refresh(props) {
props.fetchRequest(props.params.requestId);
props.fetchActiveTasksForRequest(props.params.requestId);
@@ -71,6 +73,14 @@ RequestDetailPage.propTypes = {
cancelRefresh: PropTypes.func.isRequired
};
+const mapStateToProps = (state, ownProps) => {
+ const statusCode = Utils.maybe(state, ['api', 'request', ownProps.params.requestId, 'statusCode']);
+ return {
+ notFound: statusCode === 404,
+ pathname: ownProps.location.pathname
+ };
+};
+
const mapDispatchToProps = (dispatch, ownProps) => {
const refreshActions = [
FetchRequest.trigger(ownProps.params.requestId),
@@ -87,7 +97,7 @@ const mapDispatchToProps = (dispatch, ownProps) => {
cancelRefresh: () => dispatch(
RefreshActions.CancelAutoRefresh('RequestDetailPage')
),
- fetchRequest: (requestId) => dispatch(FetchRequest.trigger(requestId)),
+ fetchRequest: (requestId) => dispatch(FetchRequest.trigger(requestId, true)),
fetchActiveTasksForRequest: (requestId) => dispatch(FetchActiveTasksForRequest.trigger(requestId)),
fetchScheduledTasksForRequest: (requestId) => dispatch(FetchScheduledTasksForRequest.trigger(requestId)),
fetchTaskCleanups: () => dispatch(FetchTaskCleanups.trigger()),
@@ -98,6 +108,6 @@ const mapDispatchToProps = (dispatch, ownProps) => {
};
export default connect(
- null,
+ mapStateToProps,
mapDispatchToProps
)(rootComponent(RequestDetailPage, (props) => props.params.requestId, refresh, false));
diff --git a/SingularityUI/app/components/requestForm/RequestForm.jsx b/SingularityUI/app/components/requestForm/RequestForm.jsx
index ca3b3c345d..396cc36a0c 100644
--- a/SingularityUI/app/components/requestForm/RequestForm.jsx
+++ b/SingularityUI/app/components/requestForm/RequestForm.jsx
@@ -502,6 +502,8 @@ class RequestForm extends React.Component {
function mapStateToProps(state, ownProps) {
const request = ownProps.params.requestId && state.api.request[ownProps.params.requestId];
return {
+ notFound: request && request.statusCode === 404,
+ pathname: ownProps.location.pathname,
racks: state.api.racks.data,
request: request && request.data,
form: state.ui.form[FORM_ID],
@@ -525,7 +527,7 @@ function mapDispatchToProps(dispatch, ownProps) {
});
},
fetchRequest(requestId) {
- dispatch(FetchRequest.trigger(requestId));
+ dispatch(FetchRequest.trigger(requestId, true));
},
fetchRacks() {
dispatch(FetchRacks.trigger());
diff --git a/SingularityUI/app/components/taskDetail/TaskDetail.jsx b/SingularityUI/app/components/taskDetail/TaskDetail.jsx
index dfe30fb245..65c4e957a7 100644
--- a/SingularityUI/app/components/taskDetail/TaskDetail.jsx
+++ b/SingularityUI/app/components/taskDetail/TaskDetail.jsx
@@ -450,8 +450,15 @@ function mapTaskToProps(task) {
}
function mapStateToProps(state, ownProps) {
- let task = state.api.task[ownProps.params.taskId];
+ const apiCallData = state.api.task[ownProps.params.taskId];
+ let task = apiCallData;
if (!(task && task.data)) return {};
+ if (apiCallData.statusCode === 404) {
+ return {
+ notFound: true,
+ pathname: ownProps.location.pathname
+ };
+ }
task = mapTaskToProps(task.data);
task = mapHealthchecksToProps(task);
return {
@@ -472,7 +479,7 @@ function mapDispatchToProps(dispatch) {
return {
runCommandOnTask: (taskId, commandName) => dispatch(RunCommandOnTask.trigger(taskId, commandName)),
killTask: (taskId, data) => dispatch(KillTask.trigger(taskId, data)),
- fetchTaskHistory: (taskId) => dispatch(FetchTaskHistory.trigger(taskId)),
+ fetchTaskHistory: (taskId) => dispatch(FetchTaskHistory.trigger(taskId, true)),
fetchTaskStatistics: (taskId) => dispatch(FetchTaskStatistics.trigger(taskId)),
fetchTaskFiles: (taskId, path, catchStatusCodes = []) => dispatch(FetchTaskFiles.trigger(taskId, path, catchStatusCodes.concat([404]))),
fetchDeployForRequest: (taskId, deployId) => dispatch(FetchDeployForRequest.trigger(taskId, deployId)),
@@ -483,11 +490,13 @@ function mapDispatchToProps(dispatch) {
}
function refresh(props) {
- props.fetchTaskFiles(props.params.taskId, props.params.splat || props.params.taskId, [400]);
+ props.fetchTaskFiles(props.params.taskId, props.params.splat || props.params.taskId, [400, 404]);
const promises = [];
const taskPromise = props.fetchTaskHistory(props.params.taskId);
taskPromise.then(() => {
- const task = props.route.store.getState().api.task[props.params.taskId].data;
+ const apiData = props.route.store.getState().api.task[props.params.taskId];
+ if (apiData.statusCode === 404) return;
+ const task = apiData.data;
promises.push(props.fetchDeployForRequest(task.task.taskId.requestId, task.task.taskId.deployId));
if (task.isStillRunning) {
promises.push(props.fetchTaskStatistics(props.params.taskId));
diff --git a/SingularityUI/app/rootComponent.jsx b/SingularityUI/app/rootComponent.jsx
index 4d0db32995..ef1d7b15f3 100644
--- a/SingularityUI/app/rootComponent.jsx
+++ b/SingularityUI/app/rootComponent.jsx
@@ -1,7 +1,13 @@
-import React from 'react';
+import React, { PropTypes, Component } from 'react';
import classNames from 'classnames';
+import NotFound from 'components/common/NotFound';
-const rootComponent = (Wrapped, title, refresh = _.noop, refreshInterval = true, pageMargin = true) => class extends React.Component {
+const rootComponent = (Wrapped, title, refresh = _.noop, refreshInterval = true, pageMargin = true) => class extends Component {
+
+ static propTypes = {
+ notFound: PropTypes.bool,
+ pathname: PropTypes.string
+ }
constructor(props) {
super(props);
@@ -69,6 +75,13 @@ const rootComponent = (Wrapped, title, refresh = _.noop, refreshInterval = true,
}
render() {
+ if (this.props.notFound) {
+ return (
+
+
+
+ );
+ }
const loader = this.state.loading &&
;
const page = !this.state.loading &&
;
return (