render 404 for nonexistent resources (#2341)

This commit is contained in:
IMRAN KHAN 2019-06-17 12:17:27 +05:30 committed by Rikin Kachhia
parent 86c5348959
commit d6a071bd83
29 changed files with 350 additions and 340 deletions

View File

@ -7,27 +7,39 @@ import {
} from '../Services/Metadata/Actions'; } from '../Services/Metadata/Actions';
import Spinner from '../Common/Spinner/Spinner'; import Spinner from '../Common/Spinner/Spinner';
import { Link } from 'react-router'; import PageNotFound, { NotFoundError } from './PageNotFound';
import Helmet from 'react-helmet'; import RuntimeError from './RuntimeError';
class ErrorBoundary extends React.Component { class ErrorBoundary extends React.Component {
initialState = {
hasError: false,
info: null,
error: null,
type: '500',
};
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { hasError: false, info: null, error: null }; this.state = this.initialState;
} }
resetState = () => { resetState = () => {
this.setState({ hasError: false, info: null, error: null }); this.setState({ ...this.initialState });
}; };
componentDidCatch(error, info) { componentDidCatch(error, info) {
this.setState({ hasError: true, info: info, error: error });
// TODO logErrorToMyService(error, info);
const { dispatch } = this.props; const { dispatch } = this.props;
// for invalid path segment errors
if (error instanceof NotFoundError) {
this.setState({
type: '404',
});
}
this.setState({ hasError: true, info: info, error: error });
dispatch(loadInconsistentObjects(true)).then(() => { dispatch(loadInconsistentObjects(true)).then(() => {
if (this.props.metadata.inconsistentObjects.length > 0) { if (this.props.metadata.inconsistentObjects.length > 0) {
if (!isMetadataStatusPage()) { if (!isMetadataStatusPage()) {
@ -41,56 +53,22 @@ class ErrorBoundary extends React.Component {
} }
render() { render() {
const errorImage = require('./error-logo.png');
const styles = require('./ErrorPage.scss');
const { metadata } = this.props; const { metadata } = this.props;
const { hasError, type } = this.state;
if (this.state.hasError && metadata.ongoingRequest) { if (hasError && metadata.ongoingRequest) {
return ( return (
<div> <div>
{' '} <Spinner />
<Spinner />{' '}
</div> </div>
); );
} }
if (this.state.hasError) { if (hasError) {
return ( return type === '404' ? (
<div className={styles.viewContainer}> <PageNotFound resetCallback={this.resetState} />
<Helmet title="Error | Hasura" /> ) : (
<div className={'container ' + styles.centerContent}> <RuntimeError resetCallback={this.resetState} />
<div className={'row ' + styles.message}>
<div className="col-xs-8">
<h1>Error</h1>
<br />
<div>
Something went wrong. Head back{' '}
<Link to="/" onClick={this.resetState}>
Home
</Link>
.
</div>
<br />
<div>
You can report this issue on our{' '}
<a href="https://github.com/hasura/graphql-engine/issues">
GitHub
</a>{' '}
or chat with us on{' '}
<a href="http://discord.gg/hasura">Discord</a>
</div>
</div>
<div className="col-xs-4">
<img
src={errorImage}
className="img-responsive"
name="hasura"
title="Something went wrong!"
/>
</div>
</div>
</div>
</div>
); );
} }

View File

@ -5,11 +5,15 @@ import { connect } from 'react-redux';
import { Link } from 'react-router'; import { Link } from 'react-router';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
export class NotFoundError extends Error {}
class PageNotFound extends Component { class PageNotFound extends Component {
render() { render() {
const errorImage = require('./error-logo.png'); const errorImage = require('./error-logo.png');
const styles = require('./ErrorPage.scss'); const styles = require('./ErrorPage.scss');
const { resetCallback } = this.props;
return ( return (
<div className={styles.viewContainer}> <div className={styles.viewContainer}>
<Helmet title="404 - Page Not Found | Hasura" /> <Helmet title="404 - Page Not Found | Hasura" />
@ -19,7 +23,11 @@ class PageNotFound extends Component {
<h1>404</h1> <h1>404</h1>
<br /> <br />
<div> <div>
This page doesn't exist. Head back <Link to="/">Home</Link>. This page doesn't exist. Head back{' '}
<Link to="/" onClick={resetCallback}>
Home
</Link>
.
</div> </div>
</div> </div>
<div className="col-xs-4"> <div className="col-xs-4">
@ -39,6 +47,7 @@ class PageNotFound extends Component {
PageNotFound.propTypes = { PageNotFound.propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
resetCallback: PropTypes.func.isRequired,
}; };
export default connect()(PageNotFound); export default connect()(PageNotFound);

View File

@ -0,0 +1,60 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import Helmet from 'react-helmet';
class RuntimeError extends Component {
render() {
const errorImage = require('./error-logo.png');
const styles = require('./ErrorPage.scss');
const { resetCallback } = this.props;
return (
<div className={styles.viewContainer}>
<Helmet title="Error | Hasura" />
<div className={'container ' + styles.centerContent}>
<div className={'row ' + styles.message}>
<div className="col-xs-8">
<h1>Error</h1>
<br />
<div>
Something went wrong. Head back{' '}
<Link to="/" onClick={resetCallback}>
Home
</Link>
.
</div>
<br />
<div>
You can report this issue on our{' '}
<a href="https://github.com/hasura/graphql-engine/issues">
GitHub
</a>{' '}
or chat with us on{' '}
<a href="http://discord.gg/hasura">Discord</a>
</div>
</div>
<div className="col-xs-4">
<img
src={errorImage}
className="img-responsive"
name="hasura"
title="Something went wrong!"
/>
</div>
</div>
</div>
</div>
);
}
}
RuntimeError.propTypes = {
dispatch: PropTypes.func.isRequired,
resetCallback: PropTypes.func.isRequired,
};
export default connect()(RuntimeError);

View File

@ -197,8 +197,9 @@ const addResolver = () => {
const customOnSuccess = data => { const customOnSuccess = data => {
Promise.all([ Promise.all([
dispatch({ type: RESET }), dispatch({ type: RESET }),
dispatch(push(`${prefixUrl}/manage/${resolveObj.name}/details`)), dispatch(fetchResolvers()).then(() => {
dispatch(fetchResolvers()), dispatch(push(`${prefixUrl}/manage/${resolveObj.name}/details`));
}),
dispatch({ type: getHeaderEvents.RESET_HEADER, data: data }), dispatch({ type: getHeaderEvents.RESET_HEADER, data: data }),
]); ]);
}; };
@ -304,21 +305,19 @@ const deleteResolver = () => {
const modifyResolver = () => { const modifyResolver = () => {
return (dispatch, getState) => { return (dispatch, getState) => {
const currState = getState().customResolverData.addData; const currState = getState().customResolverData.addData;
const remoteSchemaName = currState.name.trim().replace(/ +/g, '');
// const url = Endpoints.getSchema; // const url = Endpoints.getSchema;
const upQueryArgs = []; const upQueryArgs = [];
const downQueryArgs = []; const downQueryArgs = [];
const migrationName = const migrationName = 'update_remote_schema_' + remoteSchemaName;
'update_remote_schema_' + currState.name.trim().replace(/ +/g, '');
const schemaName = currState.name.trim().replace(/ +/g, '');
const deleteResolverUp = { const deleteResolverUp = {
type: 'remove_remote_schema', type: 'remove_remote_schema',
args: { args: {
name: currState.editState.originalName, name: currState.editState.originalName,
}, },
}; };
const trimmedName = currState.name.trim().replace(/ +/g, '');
const resolveObj = { const resolveObj = {
name: trimmedName, name: remoteSchemaName,
definition: { definition: {
url: currState.manualUrl, url: currState.manualUrl,
url_from_env: currState.envName, url_from_env: currState.envName,
@ -349,7 +348,7 @@ const modifyResolver = () => {
const deleteResolverDown = { const deleteResolverDown = {
type: 'remove_remote_schema', type: 'remove_remote_schema',
args: { args: {
name: trimmedName, name: remoteSchemaName,
}, },
}; };
const resolveDownObj = { const resolveDownObj = {
@ -396,15 +395,12 @@ const modifyResolver = () => {
const customOnSuccess = data => { const customOnSuccess = data => {
// dispatch({ type: REQUEST_SUCCESS }); // dispatch({ type: REQUEST_SUCCESS });
Promise.all([ dispatch({ type: RESET, data: data });
dispatch({ type: RESET, data: data }), dispatch(push(`${prefixUrl}/manage/schemas`)); // Hack to avoid 404
dispatch(fetchResolvers()), dispatch(fetchResolvers()).then(() => {
]).then(() => { dispatch(push(`${prefixUrl}/manage/${remoteSchemaName}/details`));
return Promise.all([
dispatch(fetchResolver(schemaName)),
dispatch(push(`${prefixUrl}/manage/${trimmedName}/details`)),
]);
}); });
dispatch(fetchResolver(remoteSchemaName));
}; };
const customOnError = error => { const customOnError = error => {
Promise.all([dispatch({ type: MODIFY_RESOLVER_FAIL, data: error })]); Promise.all([dispatch({ type: MODIFY_RESOLVER_FAIL, data: error })]);
@ -426,149 +422,6 @@ const modifyResolver = () => {
}; };
}; };
/*
const modifyResolver = () => {
return (dispatch, getState) => {
const currState = getState().customResolverData.addData;
// const url = Endpoints.getSchema;
let upQueryArgs = [];
let downQueryArgs = [];
const migrationName = 'update_add_schema_' + currState.name.trim();
const schemaName = currState.name.trim();
const deleteResolverUp = {
type: 'remove_remote_schema',
args: {
name: currState.editState.originalName,
},
};
upQueryArgs.push(deleteResolverUp);
// Delete the new one and create the old one
const resolveDownObj = {
name: currState.editState.originalName,
url: currState.editState.originalUrl,
url_from_env: currState.editState.originalEnvUrl,
headers: [],
};
resolveDownObj.headers = [...currState.editState.originalHeaders];
if (resolveDownObj.url) {
delete resolveDownObj.url_from_env;
} else {
delete resolveDownObj.url;
}
const createResolverDown = {
type: 'add_remote_schema',
args: {
...resolveDownObj,
},
};
downQueryArgs.push(createResolverDown);
let upQuery = {
type: 'bulk',
args: upQueryArgs,
};
let downQuery = {
type: 'bulk',
args: downQueryArgs,
};
const requestMsg = 'Modifying schema...';
const successMsg = 'Schema modified';
const errorMsg = 'Modify schema failed';
const customOnSuccess = () => {
// dispatch({ type: REQUEST_SUCCESS });
// Do the modify thing here
upQueryArgs = [];
downQueryArgs = [];
const resolveObj = {
name: currState.name.trim(),
url: currState.manualUrl,
url_from_env: currState.envName,
headers: [],
};
resolveObj.headers = [
...getReqHeader(getState().customResolverData.headerData.headers),
];
if (resolveObj.url) {
delete resolveObj.url_from_env;
} else {
delete resolveObj.url;
}
const createResolverUp = {
type: 'add_remote_schema',
args: {
...resolveObj,
},
};
upQueryArgs.push(createResolverUp);
const deleteResolverDown = {
type: 'remove_remote_schema',
args: {
name: currState.name,
},
};
downQueryArgs.push(deleteResolverDown);
upQuery = {
type: 'bulk',
args: upQueryArgs,
};
downQuery = {
type: 'bulk',
args: downQueryArgs,
};
const tOnSuccess = () => {
Promise.all([
dispatch({ type: RESET }),
dispatch(fetchResolvers()),
]).then(() => {
return dispatch(fetchResolver(schemaName));
});
};
const tOnError = error => {
Promise.all([dispatch({ type: MODIFY_RESOLVER_FAIL, data: error })]);
};
return dispatch(
makeRequest(
upQuery.args,
downQuery.args,
migrationName,
tOnSuccess,
tOnError,
requestMsg,
successMsg,
errorMsg
)
);
};
const customOnError = error => {
Promise.all([dispatch({ type: MODIFY_RESOLVER_FAIL, data: error })]);
};
dispatch({ type: MODIFYING_RESOLVER });
return dispatch(
makeRequest(
upQuery.args,
downQuery.args,
migrationName,
customOnSuccess,
customOnError,
requestMsg
)
);
};
};
*/
const addResolverReducer = (state = addState, action) => { const addResolverReducer = (state = addState, action) => {
switch (action.type) { switch (action.type) {
case MANUAL_URL_CHANGED: case MANUAL_URL_CHANGED:

View File

@ -17,6 +17,8 @@ import Button from '../../../Common/Button/Button';
import { appPrefix, pageTitle } from '../constants'; import { appPrefix, pageTitle } from '../constants';
import { NotFoundError } from '../../../Error/PageNotFound';
import globals from '../../../../Globals'; import globals from '../../../../Globals';
const prefixUrl = globals.urlPrefix + appPrefix; const prefixUrl = globals.urlPrefix + appPrefix;
@ -102,6 +104,15 @@ class Edit extends React.Component {
} }
render() { render() {
const currentResolver = this.props.allResolvers.find(
r => r.name === this.props.params.resolverName
);
if (!currentResolver) {
// throw a 404 exception
throw new NotFoundError();
}
const styles = require('../CustomResolver.scss'); const styles = require('../CustomResolver.scss');
const { isFetching, isRequesting, editState } = this.props; const { isFetching, isRequesting, editState } = this.props;
@ -234,6 +245,7 @@ const mapStateToProps = state => {
return { return {
...state.customResolverData.addData, ...state.customResolverData.addData,
...state.customResolverData.headerData, ...state.customResolverData.headerData,
allResolvers: state.customResolverData.listData.resolvers,
dataHeaders: { ...state.tables.dataHeaders }, dataHeaders: { ...state.tables.dataHeaders },
}; };
}; };

View File

@ -13,6 +13,8 @@ import ReloadMetadata from '../../Metadata/MetadataOptions/ReloadMetadata';
import { appPrefix } from '../constants'; import { appPrefix } from '../constants';
import { NotFoundError } from '../../../Error/PageNotFound';
import globals from '../../../../Globals'; import globals from '../../../../Globals';
const prefixUrl = globals.urlPrefix + appPrefix; const prefixUrl = globals.urlPrefix + appPrefix;
@ -49,6 +51,15 @@ class ViewStitchedSchema extends React.Component {
} }
render() { render() {
const currentResolver = this.props.allResolvers.find(
r => r.name === this.props.params.resolverName
);
if (!currentResolver) {
// throw a 404 exception
throw new NotFoundError();
}
const styles = require('../CustomResolver.scss'); const styles = require('../CustomResolver.scss');
const { resolverName } = this.props.params; const { resolverName } = this.props.params;
@ -171,6 +182,7 @@ const mapStateToProps = state => {
return { return {
...state.customResolverData.addData, ...state.customResolverData.addData,
...state.customResolverData.headerData, ...state.customResolverData.headerData,
allResolvers: state.customResolverData.listData.resolvers,
dataHeaders: { ...state.tables.dataHeaders }, dataHeaders: { ...state.tables.dataHeaders },
}; };
}; };

View File

@ -395,8 +395,10 @@ const fetchFunctionInit = () => (dispatch, getState) => {
); );
}; };
const updateCurrentSchema = schemaName => dispatch => { const updateCurrentSchema = (schemaName, redirect = true) => dispatch => {
if (redirect) {
dispatch(push(`${globals.urlPrefix}/data/schema/${schemaName}`)); dispatch(push(`${globals.urlPrefix}/data/schema/${schemaName}`));
}
Promise.all([ Promise.all([
dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: schemaName }), dispatch({ type: UPDATE_CURRENT_SCHEMA, currentSchema: schemaName }),

View File

@ -7,6 +7,7 @@ import PageContainer from '../../Common/Layout/PageContainer/PageContainer';
import DataSubSidebar from './DataSubSidebar'; import DataSubSidebar from './DataSubSidebar';
import { updateCurrentSchema } from './DataActions'; import { updateCurrentSchema } from './DataActions';
import { NotFoundError } from '../../Error/PageNotFound';
const sectionPrefix = '/data'; const sectionPrefix = '/data';
@ -20,6 +21,13 @@ const DataPageContainer = ({
}) => { }) => {
const styles = require('../../Common/TableCommon/Table.scss'); const styles = require('../../Common/TableCommon/Table.scss');
if (!schemaList.map(s => s.schema_name).includes(currentSchema)) {
dispatch(updateCurrentSchema('public', false));
// throw a 404 exception
throw new NotFoundError();
}
const currentLocation = location.pathname; const currentLocation = location.pathname;
let migrationTab = null; let migrationTab = null;
@ -42,6 +50,14 @@ const DataPageContainer = ({
dispatch(updateCurrentSchema(e.target.value)); dispatch(updateCurrentSchema(e.target.value));
}; };
const getSchemaOptions = () => {
return schemaList.map(s => (
<option key={s.schema_name} value={s.schema_name}>
{s.schema_name}
</option>
));
};
const sidebarContent = ( const sidebarContent = (
<ul> <ul>
<li <li
@ -60,11 +76,7 @@ const DataPageContainer = ({
value={currentSchema} value={currentSchema}
className={styles.changeSchema + ' form-control'} className={styles.changeSchema + ' form-control'}
> >
{schemaList.map(s => ( {getSchemaOptions()}
<option key={s.schema_name} value={s.schema_name}>
{s.schema_name}
</option>
))}
</select> </select>
</div> </div>
</div> </div>

View File

@ -23,12 +23,16 @@ import {
} from '../customFunctionReducer'; } from '../customFunctionReducer';
import { SET_SQL } from '../../RawSQL/Actions'; import { SET_SQL } from '../../RawSQL/Actions';
import { NotFoundError } from '../../../../Error/PageNotFound';
class ModifyCustomFunction extends React.Component { class ModifyCustomFunction extends React.Component {
constructor() { constructor() {
super(); super();
this.state = {};
this.state.deleteConfirmationError = null; this.state = {
deleteConfirmationError: null,
funcFetchCompleted: false,
};
} }
componentDidMount() { componentDidMount() {
@ -37,7 +41,11 @@ class ModifyCustomFunction extends React.Component {
this.props.dispatch(push(prefixUrl)); this.props.dispatch(push(prefixUrl));
} }
Promise.all([ Promise.all([
this.props.dispatch(fetchCustomFunction(functionName, schema)), this.props
.dispatch(fetchCustomFunction(functionName, schema))
.then(() => {
this.setState({ funcFetchCompleted: true });
}),
]); ]);
} }
@ -48,12 +56,16 @@ class ModifyCustomFunction extends React.Component {
schema !== nextProps.params.schema schema !== nextProps.params.schema
) { ) {
Promise.all([ Promise.all([
this.props.dispatch( this.props
.dispatch(
fetchCustomFunction( fetchCustomFunction(
nextProps.params.functionName, nextProps.params.functionName,
nextProps.params.schema nextProps.params.schema
) )
), )
.then(() => {
this.setState({ funcFetchCompleted: true });
}),
]); ]);
} }
} }
@ -108,6 +120,11 @@ class ModifyCustomFunction extends React.Component {
isFetching, isFetching,
} = this.props.functions; } = this.props.functions;
if (this.state.funcFetchCompleted && !functionName) {
// throw a 404 exception
throw new NotFoundError();
}
const { migrationMode } = this.props; const { migrationMode } = this.props;
const baseUrl = `${appPrefix}/schema/${schema}/functions/${functionName}`; const baseUrl = `${appPrefix}/schema/${schema}/functions/${functionName}`;
@ -182,6 +199,7 @@ class ModifyCustomFunction extends React.Component {
url: '', url: '',
}); });
} }
return ( return (
<div className={'col-xs-8' + ' ' + styles.modifyWrapper}> <div className={'col-xs-8' + ' ' + styles.modifyWrapper}>
<Helmet <Helmet

View File

@ -10,8 +10,6 @@ import { pageTitle, appPrefix } from '../Modify/constants';
import tabInfo from '../Modify/tabInfo'; import tabInfo from '../Modify/tabInfo';
import globals from '../../../../../Globals'; import globals from '../../../../../Globals';
const prefixUrl = globals.urlPrefix + appPrefix;
import { fetchCustomFunction } from '../customFunctionReducer'; import { fetchCustomFunction } from '../customFunctionReducer';
import { import {
updateSchemaInfo, updateSchemaInfo,
@ -19,15 +17,32 @@ import {
fetchFunctionInit, fetchFunctionInit,
setTable, setTable,
} from '../../DataActions'; } from '../../DataActions';
import { NotFoundError } from '../../../../Error/PageNotFound';
const prefixUrl = globals.urlPrefix + appPrefix;
class Permission extends React.Component { class Permission extends React.Component {
constructor() {
super();
this.state = {
funcFetchCompleted: false,
};
}
componentDidMount() { componentDidMount() {
const { functionName, schema } = this.props.params; const { functionName, schema } = this.props.params;
if (!functionName) { if (!functionName) {
this.props.dispatch(push(prefixUrl)); this.props.dispatch(push(prefixUrl));
} }
Promise.all([ Promise.all([
this.props.dispatch(fetchCustomFunction(functionName, schema)), this.props
.dispatch(fetchCustomFunction(functionName, schema))
.then(() => {
this.setState({ funcFetchCompleted: true });
}),
]); ]);
} }
render() { render() {
@ -39,6 +54,11 @@ class Permission extends React.Component {
setOffTableSchema, setOffTableSchema,
} = this.props.functions; } = this.props.functions;
if (this.state.funcFetchCompleted && !functionName) {
// throw a 404 exception
throw new NotFoundError();
}
const { dispatch } = this.props; const { dispatch } = this.props;
const baseUrl = `${appPrefix}/schema/${schema}/functions/${functionName}`; const baseUrl = `${appPrefix}/schema/${schema}/functions/${functionName}`;

View File

@ -157,10 +157,9 @@ const fetchCustomFunction = (functionName, schema) => {
}); });
return Promise.resolve(); return Promise.resolve();
} }
return dispatch(_push('/'));
}, },
error => { error => {
console.error('Failed to fetch resolver' + JSON.stringify(error)); console.error('Failed to fetch function' + JSON.stringify(error));
return dispatch({ type: CUSTOM_FUNCTION_FETCH_FAIL, data: error }); return dispatch({ type: CUSTOM_FUNCTION_FETCH_FAIL, data: error });
} }
); );
@ -276,12 +275,9 @@ const unTrackCustomFunction = () => {
const errorMsg = 'Delete custom function failed'; const errorMsg = 'Delete custom function failed';
const customOnSuccess = () => { const customOnSuccess = () => {
// dispatch({ type: REQUEST_SUCCESS }); dispatch(_push(`/schema/${currentSchema}`));
Promise.all([ dispatch({ type: RESET });
dispatch({ type: RESET }), dispatch(fetchTrackedFunctions());
dispatch(_push('/')),
dispatch(fetchTrackedFunctions()),
]);
}; };
const customOnError = error => { const customOnError = error => {
Promise.all([ Promise.all([

View File

@ -43,10 +43,11 @@ export const createNewSchema = (schemaName, successCb, errorCb) => {
const errorMsg = 'Error creating schema'; const errorMsg = 'Error creating schema';
const customOnSuccess = () => { const customOnSuccess = () => {
dispatch(fetchSchemaList()); dispatch(fetchSchemaList()).then(() => {
if (successCb) { if (successCb) {
successCb(); successCb();
} }
});
}; };
const customOnError = () => { const customOnError = () => {
if (errorCb) { if (errorCb) {

View File

@ -133,9 +133,11 @@ class Schema extends Component {
}; };
const getCurrentSchemaSection = () => { const getCurrentSchemaSection = () => {
const schemaOptions = schemaList.map(s => { const getSchemaOptions = () => {
return <option key={s.schema_name}>{s.schema_name}</option>; return schemaList.map(s => (
}); <option key={s.schema_name}>{s.schema_name}</option>
));
};
const getCreateSchemaSection = () => { const getCreateSchemaSection = () => {
let createSchemaSection = null; let createSchemaSection = null;
@ -262,7 +264,7 @@ class Schema extends Component {
} }
value={currentSchema} value={currentSchema}
> >
{schemaOptions} {getSchemaOptions()}
</select> </select>
</div> </div>
<div className={styles.display_inline + ' ' + styles.add_mar_left}> <div className={styles.display_inline + ' ' + styles.add_mar_left}>

View File

@ -12,7 +12,8 @@ import { setTable } from '../DataActions';
import TableHeader from '../TableCommon/TableHeader'; import TableHeader from '../TableCommon/TableHeader';
import ViewHeader from './ViewHeader'; import ViewHeader from './ViewHeader';
import ViewRows from './ViewRows'; import ViewRows from './ViewRows';
import { replace } from 'react-router-redux';
import { NotFoundError } from '../../../Error/PageNotFound';
const genHeadings = headings => { const genHeadings = headings => {
if (headings.length === 0) { if (headings.length === 0) {
@ -146,7 +147,7 @@ class ViewTable extends Component {
query, query,
curFilter, curFilter,
rows, rows,
count, // eslint-disable-line no-unused-vars count,
activePath, activePath,
migrationMode, migrationMode,
ongoingRequest, ongoingRequest,
@ -159,16 +160,18 @@ class ViewTable extends Component {
manualTriggers = [], manualTriggers = [],
triggeredRow, triggeredRow,
triggeredFunction, triggeredFunction,
} = this.props; // eslint-disable-line no-unused-vars } = this.props;
// check if table exists // check if table exists
const currentTable = schemas.find( const currentTable = schemas.find(
s => s.table_name === tableName && s.table_schema === currentSchema s => s.table_name === tableName && s.table_schema === currentSchema
); );
if (!currentTable) { if (!currentTable) {
// dispatch a 404 route // throw a 404 exception
dispatch(replace('/404')); throw new NotFoundError();
} }
// Is this a view // Is this a view
const isView = currentTable.table_type !== 'BASE TABLE'; const isView = currentTable.table_type !== 'BASE TABLE';

View File

@ -10,6 +10,8 @@ import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE } from '../utils';
import { getParentNodeByClass } from '../../../../utils/domFunctions'; import { getParentNodeByClass } from '../../../../utils/domFunctions';
import { NotFoundError } from '../../../Error/PageNotFound';
class InsertItem extends Component { class InsertItem extends Component {
constructor() { constructor() {
super(); super();
@ -48,6 +50,15 @@ class InsertItem extends Component {
} = this.props; } = this.props;
const styles = require('../../../Common/TableCommon/Table.scss'); const styles = require('../../../Common/TableCommon/Table.scss');
// check if table exists
const currentTable = schemas.find(
s => s.table_name === tableName && s.table_schema === currentSchema
);
if (!currentTable) {
// throw a 404 exception
throw new NotFoundError();
}
const _columns = schemas.find( const _columns = schemas.find(
x => x.table_name === tableName && x.table_schema === currentSchema x => x.table_name === tableName && x.table_schema === currentSchema
).columns; ).columns;

View File

@ -319,7 +319,7 @@ const saveForeignKeys = (index, tableSchema, columns) => {
.join(', ')}) .join(', ')})
references "${oldConstraint.ref_table_table_schema}"."${ references "${oldConstraint.ref_table_table_schema}"."${
oldConstraint.ref_table oldConstraint.ref_table
}" }"
(${Object.values(oldConstraint.column_mapping) (${Object.values(oldConstraint.column_mapping)
.map(rc => `"${rc}"`) .map(rc => `"${rc}"`)
.join(', ')}) .join(', ')})
@ -571,10 +571,11 @@ const deleteTableSql = tableName => {
const errorMsg = 'Deleting table failed'; const errorMsg = 'Deleting table failed';
const customOnSuccess = () => { const customOnSuccess = () => {
dispatch(updateSchemaInfo()).then(() => { dispatch(updateSchemaInfo());
dispatch(_push('/')); dispatch(_push('/'));
});
}; };
const customOnError = err => { const customOnError = err => {
dispatch({ type: UPDATE_MIGRATION_STATUS_ERROR, data: err }); dispatch({ type: UPDATE_MIGRATION_STATUS_ERROR, data: err });
}; };

View File

@ -24,7 +24,7 @@ import TableCommentEditor from './TableCommentEditor';
import ForeignKeyEditor from './ForeignKeyEditor'; import ForeignKeyEditor from './ForeignKeyEditor';
import UniqueKeyEditor from './UniqueKeyEditor'; import UniqueKeyEditor from './UniqueKeyEditor';
import styles from './ModifyTable.scss'; import styles from './ModifyTable.scss';
import { replace } from 'react-router-redux'; import { NotFoundError } from '../../../Error/PageNotFound';
class ModifyTable extends React.Component { class ModifyTable extends React.Component {
componentDidMount() { componentDidMount() {
@ -62,8 +62,8 @@ class ModifyTable extends React.Component {
t => t.table_name === tableName && t.table_schema === currentSchema t => t.table_name === tableName && t.table_schema === currentSchema
); );
if (!tableSchema) { if (!tableSchema) {
dispatch(replace('/404')); // throw a 404 exception
return null; throw new NotFoundError();
} }
const tableComment = tableSchema.comment; const tableComment = tableSchema.comment;

View File

@ -12,6 +12,7 @@ import TableCommentEditor from './TableCommentEditor';
import { ordinalColSort } from '../utils'; import { ordinalColSort } from '../utils';
import { setTable } from '../DataActions'; import { setTable } from '../DataActions';
import Button from '../../../Common/Button/Button'; import Button from '../../../Common/Button/Button';
import { NotFoundError } from '../../../Error/PageNotFound';
class ModifyView extends Component { class ModifyView extends Component {
componentDidMount() { componentDidMount() {
@ -45,7 +46,13 @@ class ModifyView extends Component {
const tableSchema = allSchemas.find( const tableSchema = allSchemas.find(
t => t.table_name === tableName && t.table_schema === currentSchema t => t.table_name === tableName && t.table_schema === currentSchema
); // eslint-disable-line no-unused-vars );
if (!tableSchema) {
// throw a 404 exception
throw new NotFoundError();
}
const tableComment = tableSchema.comment; const tableComment = tableSchema.comment;
let alert = null; let alert = null;

View File

@ -48,6 +48,8 @@ import { allOperators, getLegacyOperator } from './PermissionBuilder/utils';
import Button from '../../../Common/Button/Button'; import Button from '../../../Common/Button/Button';
import { defaultPresetsState } from '../DataState'; import { defaultPresetsState } from '../DataState';
import { NotFoundError } from '../../../Error/PageNotFound';
class Permissions extends Component { class Permissions extends Component {
constructor() { constructor() {
super(); super();
@ -66,16 +68,6 @@ class Permissions extends Component {
componentDidMount() { componentDidMount() {
this.props.dispatch({ type: RESET }); this.props.dispatch({ type: RESET });
const currentTableSchema = this.props.allSchemas.find(
t =>
t.table_name === this.props.tableName &&
t.table_schema === this.props.currentSchema
);
if (!currentTableSchema) {
return;
}
this.props.dispatch(setTable(this.props.tableName)); this.props.dispatch(setTable(this.props.tableName));
} }
@ -94,6 +86,17 @@ class Permissions extends Component {
currentSchema, currentSchema,
} = this.props; } = this.props;
const currentTableSchema = this.props.allSchemas.find(
t =>
t.table_name === this.props.tableName &&
t.table_schema === this.props.currentSchema
);
if (!currentTableSchema) {
// throw a 404 exception
throw new NotFoundError();
}
const styles = require('../TableModify/ModifyTable.scss'); const styles = require('../TableModify/ModifyTable.scss');
const getAllRoles = allTableSchemas => { const getAllRoles = allTableSchemas => {

View File

@ -21,6 +21,7 @@ import Button from '../../../Common/Button/Button';
import AddManualRelationship from './AddManualRelationship'; import AddManualRelationship from './AddManualRelationship';
import suggestedRelationshipsRaw from './autoRelations'; import suggestedRelationshipsRaw from './autoRelations';
import RelationshipEditor from './RelationshipEditor'; import RelationshipEditor from './RelationshipEditor';
import { NotFoundError } from '../../../Error/PageNotFound';
const addRelationshipCellView = ( const addRelationshipCellView = (
dispatch, dispatch,
@ -328,6 +329,12 @@ class Relationships extends Component {
const tableSchema = allSchemas.find( const tableSchema = allSchemas.find(
t => t.table_name === tableName && t.table_schema === currentSchema t => t.table_name === tableName && t.table_schema === currentSchema
); );
if (!tableSchema) {
// throw a 404 exception
throw new NotFoundError();
}
let alert = null; let alert = null;
if (ongoingRequest) { if (ongoingRequest) {
alert = ( alert = (

View File

@ -7,6 +7,7 @@ import { getObjArrRelList } from './utils';
import { setTable, UPDATE_REMOTE_SCHEMA_MANUAL_REL } from '../DataActions'; import { setTable, UPDATE_REMOTE_SCHEMA_MANUAL_REL } from '../DataActions';
import AddManualRelationship from './AddManualRelationship'; import AddManualRelationship from './AddManualRelationship';
import RelationshipEditor from './RelationshipEditor'; import RelationshipEditor from './RelationshipEditor';
import { NotFoundError } from '../../../Error/PageNotFound';
class RelationshipsView extends Component { class RelationshipsView extends Component {
componentDidMount() { componentDidMount() {
@ -40,6 +41,12 @@ class RelationshipsView extends Component {
const tableSchema = allSchemas.find( const tableSchema = allSchemas.find(
t => t.table_name === tableName && t.table_schema === currentSchema t => t.table_name === tableName && t.table_schema === currentSchema
); );
if (!tableSchema) {
// throw a 404 exception
throw new NotFoundError();
}
let alert = null; let alert = null;
if (ongoingRequest) { if (ongoingRequest) {
alert = ( alert = (

View File

@ -469,6 +469,7 @@ const deleteTrigger = triggerName => {
// dispatch({ type: REQUEST_SUCCESS }); // dispatch({ type: REQUEST_SUCCESS });
dispatch({ type: REQUEST_COMPLETE }); // modify trigger action dispatch({ type: REQUEST_COMPLETE }); // modify trigger action
dispatch(showSuccessNotification('Trigger Deleted')); dispatch(showSuccessNotification('Trigger Deleted'));
dispatch(push('/manage/triggers'));
// remove this trigger from state // remove this trigger from state
const existingTriggers = getState().triggers.triggerList.filter( const existingTriggers = getState().triggers.triggerList.filter(
trigger => trigger.name !== triggerName trigger => trigger.name !== triggerName
@ -477,7 +478,6 @@ const deleteTrigger = triggerName => {
type: LOAD_TRIGGER_LIST, type: LOAD_TRIGGER_LIST,
triggerList: existingTriggers, triggerList: existingTriggers,
}); });
dispatch(push('/manage/triggers'));
return; return;
}; };
const customOnError = () => { const customOnError = () => {

View File

@ -3,7 +3,6 @@ import TableHeader from '../TableCommon/TableHeader';
import styles from './ModifyEvent.scss'; import styles from './ModifyEvent.scss';
import { getTableColumns } from '../utils'; import { getTableColumns } from '../utils';
import _push from '../push';
import Info from './Info'; import Info from './Info';
import WebhookEditor from './WebhookEditor'; import WebhookEditor from './WebhookEditor';
@ -14,6 +13,8 @@ import ActionButtons from './ActionButtons';
import { save, setDefaults, RESET_MODIFY_STATE } from './Actions'; import { save, setDefaults, RESET_MODIFY_STATE } from './Actions';
import { NotFoundError } from '../../../Error/PageNotFound';
class Modify extends React.Component { class Modify extends React.Component {
componentDidMount() { componentDidMount() {
const { dispatch } = this.props; const { dispatch } = this.props;
@ -40,8 +41,8 @@ class Modify extends React.Component {
); );
if (!currentTrigger) { if (!currentTrigger) {
dispatch(_push('/events/manage')); // throw a 404 exception
return null; throw new NotFoundError();
} }
const { const {

View File

@ -34,9 +34,6 @@ const vMakeRequest = () => {
const state = getState(); const state = getState();
const url = Endpoints.query; const url = Endpoints.query;
const originalTrigger = getState().triggers.currentTrigger; const originalTrigger = getState().triggers.currentTrigger;
const triggerList = getState().triggers.triggerList;
const triggerSchema = triggerList.filter(t => t.name === originalTrigger);
const triggerName = triggerSchema[0].name;
const currentQuery = JSON.parse(JSON.stringify(state.triggers.view.query)); const currentQuery = JSON.parse(JSON.stringify(state.triggers.view.query));
// count query // count query
const countQuery = JSON.parse(JSON.stringify(state.triggers.view.query)); const countQuery = JSON.parse(JSON.stringify(state.triggers.view.query));
@ -52,7 +49,7 @@ const vMakeRequest = () => {
finalAndClause.push({ error: false }); finalAndClause.push({ error: false });
currentQuery.columns[1].where = { $and: finalAndClause }; currentQuery.columns[1].where = { $and: finalAndClause };
currentQuery.where = { name: state.triggers.currentTrigger }; currentQuery.where = { name: state.triggers.currentTrigger };
countQuery.where.$and.push({ trigger_name: triggerName }); countQuery.where.$and.push({ trigger_name: originalTrigger });
} else { } else {
// reset where for events // reset where for events
if (currentQuery.columns[1]) { if (currentQuery.columns[1]) {

View File

@ -4,7 +4,7 @@ import { vSetDefaults, vMakeRequest, vExpandHeading } from './ViewActions'; // e
import { setTrigger } from '../EventActions'; import { setTrigger } from '../EventActions';
import TableHeader from '../TableCommon/TableHeader'; import TableHeader from '../TableCommon/TableHeader';
import ViewRows from './ViewRows'; import ViewRows from './ViewRows';
import { replace } from 'react-router-redux'; import { NotFoundError } from '../../../Error/PageNotFound';
const genHeadings = headings => { const genHeadings = headings => {
if (headings.length === 0) { if (headings.length === 0) {
@ -129,12 +129,13 @@ class ViewTable extends Component {
expandedRow, expandedRow,
} = this.props; // eslint-disable-line no-unused-vars } = this.props; // eslint-disable-line no-unused-vars
// check if table exists // check if trigger exists
const currentTrigger = triggerList.find(s => s.name === triggerName); const currentTrigger = triggerList.find(s => s.name === triggerName);
if (!currentTrigger) { if (!currentTrigger) {
// dispatch a 404 route // throw a 404 exception
dispatch(replace('/404')); throw new NotFoundError();
} }
// Is this a view // Is this a view
const isView = false; const isView = false;

View File

@ -44,9 +44,6 @@ const vMakeRequest = () => {
const state = getState(); const state = getState();
const url = Endpoints.query; const url = Endpoints.query;
const originalTrigger = getState().triggers.currentTrigger; const originalTrigger = getState().triggers.currentTrigger;
const triggerList = getState().triggers.triggerList;
const triggerSchema = triggerList.filter(t => t.name === originalTrigger);
const triggerName = triggerSchema[0].name;
const currentQuery = JSON.parse(JSON.stringify(state.triggers.view.query)); const currentQuery = JSON.parse(JSON.stringify(state.triggers.view.query));
// count query // count query
const countQuery = JSON.parse(JSON.stringify(state.triggers.view.query)); const countQuery = JSON.parse(JSON.stringify(state.triggers.view.query));
@ -64,7 +61,7 @@ const vMakeRequest = () => {
currentQuery.columns[1].where = { $and: finalAndClause }; currentQuery.columns[1].where = { $and: finalAndClause };
currentQuery.where = { name: state.triggers.currentTrigger }; currentQuery.where = { name: state.triggers.currentTrigger };
countQuery.where.$and.push({ countQuery.where.$and.push({
trigger_name: state.triggers.currentTrigger, trigger_name: originalTrigger,
}); });
} else { } else {
// reset where for events // reset where for events
@ -76,7 +73,7 @@ const vMakeRequest = () => {
currentQuery.where = { name: state.triggers.currentTrigger }; currentQuery.where = { name: state.triggers.currentTrigger };
countQuery.where = { countQuery.where = {
$and: [ $and: [
{ trigger_name: triggerName }, { trigger_name: state.triggers.currentTrigger },
{ $or: [{ delivered: { $eq: true } }, { error: { $eq: true } }] }, { $or: [{ delivered: { $eq: true } }, { error: { $eq: true } }] },
], ],
}; };

View File

@ -4,7 +4,7 @@ import { vSetDefaults, vMakeRequest, vExpandHeading } from './ViewActions'; // e
import { setTrigger } from '../EventActions'; import { setTrigger } from '../EventActions';
import TableHeader from '../TableCommon/TableHeader'; import TableHeader from '../TableCommon/TableHeader';
import ViewRows from './ViewRows'; import ViewRows from './ViewRows';
import { replace } from 'react-router-redux'; import { NotFoundError } from '../../../Error/PageNotFound';
const genHeadings = headings => { const genHeadings = headings => {
if (headings.length === 0) { if (headings.length === 0) {
@ -143,8 +143,8 @@ class ViewTable extends Component {
// check if table exists // check if table exists
const currentTrigger = triggerList.find(s => s.name === triggerName); const currentTrigger = triggerList.find(s => s.name === triggerName);
if (!currentTrigger) { if (!currentTrigger) {
// dispatch a 404 route // throw a 404 exception
dispatch(replace('/404')); throw new NotFoundError();
} }
// Is this a view // Is this a view
const isView = false; const isView = false;

View File

@ -4,7 +4,7 @@ import { vSetDefaults, vMakeRequest, vExpandHeading } from './ViewActions'; // e
import { setTrigger } from '../EventActions'; import { setTrigger } from '../EventActions';
import TableHeader from '../TableCommon/TableHeader'; import TableHeader from '../TableCommon/TableHeader';
import ViewRows from './ViewRows'; import ViewRows from './ViewRows';
import { replace } from 'react-router-redux'; import { NotFoundError } from '../../../Error/PageNotFound';
const genHeadings = headings => { const genHeadings = headings => {
if (headings.length === 0) { if (headings.length === 0) {
@ -133,8 +133,8 @@ class ViewTable extends Component {
// check if table exists // check if table exists
const currentTrigger = triggerList.find(s => s.name === triggerName); const currentTrigger = triggerList.find(s => s.name === triggerName);
if (!currentTrigger) { if (!currentTrigger) {
// dispatch a 404 route // throw a 404 exception
dispatch(replace('/404')); throw new NotFoundError();
} }
// Is this a view // Is this a view
const isView = false; const isView = false;

View File

@ -28,6 +28,7 @@ import * as tooltip from '../Common/Tooltips';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import { convertDateTimeToLocale } from '../utils'; import { convertDateTimeToLocale } from '../utils';
import Button from '../../../Common/Button/Button'; import Button from '../../../Common/Button/Button';
import { NotFoundError } from '../../../Error/PageNotFound';
class StreamingLogs extends Component { class StreamingLogs extends Component {
constructor(props) { constructor(props) {
@ -106,17 +107,16 @@ class StreamingLogs extends Component {
} }
render() { render() {
const { const { triggerName, log, count, dispatch, triggerList } = this.props;
triggerName,
log,
count,
dispatch,
triggerList,
} = this.props;
const styles = require('../TableCommon/EventTable.scss'); const styles = require('../TableCommon/EventTable.scss');
// check if trigger exists
const currentTrigger = triggerList.find(s => s.name === triggerName); const currentTrigger = triggerList.find(s => s.name === triggerName);
if (!currentTrigger) {
// throw a 404 exception
throw new NotFoundError();
}
const invocationColumns = [ const invocationColumns = [
'redeliver', 'redeliver',