Permanently clear GraphQL Engine's metadata and configure it from
scratch (tracking relevant tables and relationships). This process
@@ -62,36 +59,6 @@ const MetadataOptions = props => {
);
};
- const getClearSecretSection = () => {
- let clearSecretSection = null;
-
- if (window.localStorage[CONSOLE_ADMIN_SECRET]) {
- clearSecretSection = (
-
-
-
Clear {globals.adminSecretLabel} (logout)
-
-
- The console caches the {globals.adminSecretLabel} (
- {globals.adminSecretLabel === 'access-key'
- ? 'HASURA_GRAPHQL_ACCESS_KEY'
- : 'HASURA_GRAPHQL_ADMIN_SECRET'}
- ) in the browser. You can clear this cache to force a prompt for
- the {globals.adminSecretLabel} when the console is accessed next
- using this browser.
-
-
-
-
-
-
-
- );
- }
-
- return clearSecretSection;
- };
-
return (
{
{getMetadataImportExportSection()}
{getMetadataUpdateSection()}
-
- {getClearSecretSection()}
);
};
diff --git a/console/src/components/Services/Metadata/MetadataOptions/ReloadMetadata.js b/console/src/components/Services/Settings/MetadataOptions/ReloadMetadata.js
similarity index 96%
rename from console/src/components/Services/Metadata/MetadataOptions/ReloadMetadata.js
rename to console/src/components/Services/Settings/MetadataOptions/ReloadMetadata.js
index bd465715f39..ab4567d6ea5 100644
--- a/console/src/components/Services/Metadata/MetadataOptions/ReloadMetadata.js
+++ b/console/src/components/Services/Settings/MetadataOptions/ReloadMetadata.js
@@ -21,7 +21,7 @@ class ReloadMetadata extends Component {
const { dispatch } = this.props;
const { isReloading } = this.state;
- const metaDataStyles = require('../Metadata.scss');
+ const metaDataStyles = require('../Settings.scss');
const reloadMetadataAndLoadInconsistentMetadata = e => {
e.preventDefault();
diff --git a/console/src/components/Services/Metadata/MetadataOptions/ReloadRemoteSchema.js b/console/src/components/Services/Settings/MetadataOptions/ReloadRemoteSchema.js
similarity index 96%
rename from console/src/components/Services/Metadata/MetadataOptions/ReloadRemoteSchema.js
rename to console/src/components/Services/Settings/MetadataOptions/ReloadRemoteSchema.js
index a227acaa94b..7d2b621ad64 100644
--- a/console/src/components/Services/Metadata/MetadataOptions/ReloadRemoteSchema.js
+++ b/console/src/components/Services/Settings/MetadataOptions/ReloadRemoteSchema.js
@@ -17,7 +17,7 @@ class ReloadRemoteSchema extends Component {
render() {
const { dispatch, remoteSchemaName } = this.props;
const { isReloading } = this.state;
- const metaDataStyles = require('../Metadata.scss');
+ const metaDataStyles = require('../Settings.scss');
const reloadRemoteMetadataHandler = () => {
this.setState({ isReloading: true });
dispatch(
diff --git a/console/src/components/Services/Metadata/MetadataOptions/ResetMetadata.js b/console/src/components/Services/Settings/MetadataOptions/ResetMetadata.js
similarity index 100%
rename from console/src/components/Services/Metadata/MetadataOptions/ResetMetadata.js
rename to console/src/components/Services/Settings/MetadataOptions/ResetMetadata.js
diff --git a/console/src/components/Services/Metadata/MetadataStatus/MetadataStatus.js b/console/src/components/Services/Settings/MetadataStatus/MetadataStatus.js
similarity index 99%
rename from console/src/components/Services/Metadata/MetadataStatus/MetadataStatus.js
rename to console/src/components/Services/Settings/MetadataStatus/MetadataStatus.js
index 11511c2bfcf..4767221015c 100644
--- a/console/src/components/Services/Metadata/MetadataStatus/MetadataStatus.js
+++ b/console/src/components/Services/Settings/MetadataStatus/MetadataStatus.js
@@ -6,7 +6,7 @@ import {
showSuccessNotification,
showErrorNotification,
} from '../../Common/Notification';
-import metaDataStyles from '../Metadata.scss';
+import metaDataStyles from '../Settings.scss';
import styles from '../../../Common/TableCommon/Table.scss';
import CheckIcon from '../../../Common/Icons/Check';
import CrossIcon from '../../../Common/Icons/Cross';
diff --git a/console/src/components/Services/Metadata/Metadata.scss b/console/src/components/Services/Settings/Settings.scss
similarity index 100%
rename from console/src/components/Services/Metadata/Metadata.scss
rename to console/src/components/Services/Settings/Settings.scss
diff --git a/console/src/components/Services/Metadata/Sidebar.js b/console/src/components/Services/Settings/Sidebar.js
similarity index 73%
rename from console/src/components/Services/Metadata/Sidebar.js
rename to console/src/components/Services/Settings/Sidebar.js
index 58eb8a630a4..8638e67ae1c 100644
--- a/console/src/components/Services/Metadata/Sidebar.js
+++ b/console/src/components/Services/Settings/Sidebar.js
@@ -1,16 +1,20 @@
import React from 'react';
import LeftContainer from '../../Common/Layout/LeftContainer/LeftContainer';
import { Link } from 'react-router';
-import styles from '../../Common/TableCommon/Table.scss';
import CheckIcon from '../../Common/Icons/Check';
import CrossIcon from '../../Common/Icons/Cross';
+import globals from '../../../Globals';
+import { CLI_CONSOLE_MODE } from '../../../constants';
+import { getAdminSecret } from '../ApiExplorer/ApiRequest/utils';
+
+import styles from '../../Common/TableCommon/Table.scss';
const Sidebar = ({ location, metadata }) => {
const sectionsData = [];
sectionsData.push({
key: 'actions',
- link: '/metadata/actions',
+ link: '/settings/metadata-actions',
dataTestVal: 'metadata-actions-link',
title: 'Metadata Actions',
});
@@ -20,7 +24,7 @@ const Sidebar = ({ location, metadata }) => {
sectionsData.push({
key: 'status',
- link: '/metadata/status',
+ link: '/settings/metadata-status',
dataTestVal: 'metadata-status-link',
title: (
@@ -32,11 +36,23 @@ const Sidebar = ({ location, metadata }) => {
sectionsData.push({
key: 'allowed-queries',
- link: '/metadata/allowed-queries',
+ link: '/settings/allowed-queries',
dataTestVal: 'allowed-queries-link',
title: 'Allowed Queries',
});
+
+ const adminSecret = getAdminSecret();
+
+ if (adminSecret && globals.consoleMode !== CLI_CONSOLE_MODE) {
+ sectionsData.push({
+ key: 'logout',
+ link: '/settings/logout',
+ dataTestVal: 'logout-page-link',
+ title: 'Logout (clear admin-secret)',
+ });
+ }
+
const currentLocation = location.pathname;
const sections = [];
diff --git a/console/src/components/Services/Metadata/State.js b/console/src/components/Services/Settings/State.js
similarity index 100%
rename from console/src/components/Services/Metadata/State.js
rename to console/src/components/Services/Settings/State.js
diff --git a/console/src/components/Services/Metadata/utils.js b/console/src/components/Services/Settings/utils.js
similarity index 100%
rename from console/src/components/Services/Metadata/utils.js
rename to console/src/components/Services/Settings/utils.js
diff --git a/console/src/constants.js b/console/src/constants.js
index 074be27cc9a..7c3a6a184f4 100644
--- a/console/src/constants.js
+++ b/console/src/constants.js
@@ -1 +1,4 @@
export const SERVER_CONSOLE_MODE = 'server';
+export const CLI_CONSOLE_MODE = 'cli';
+
+export const ADMIN_SECRET_HEADER_KEY = 'x-hasura-admin-secret';
diff --git a/console/src/helpers/localDev.js b/console/src/helpers/localDev.js
index 18b3fa73d6c..beb98de1fc3 100644
--- a/console/src/helpers/localDev.js
+++ b/console/src/helpers/localDev.js
@@ -1,38 +1,30 @@
-const envObj = `apiHost: '${process.env.API_HOST}',
- apiPort: '${process.env.API_PORT}',
- dataApiUrl: '${process.env.DATA_API_URL}',
- adminSecret: '${process.env.ADMIN_SECRET}',
- consoleMode: '${process.env.CONSOLE_MODE}',
- nodeEnv: '${process.env.NODE_ENV}',
- urlPrefix: '${process.env.URL_PREFIX}',
- enableTelemetry: ${process.env.ENABLE_TELEMETRY},
- assetsPath: '${process.env.ASSETS_PATH}',
- assetsVersion: '${process.env.ASSETS_VERSION}',
- serverVersion: '${process.env.SERVER_VERSION}',
- cdnAssets: ${process.env.CDN_ASSETS},
-`;
-
-let appendObj;
+let envObj = `
+ apiHost: '${process.env.API_HOST}',
+ apiPort: '${process.env.API_PORT}',
+ dataApiUrl: '${process.env.DATA_API_URL}',
+ consoleMode: '${process.env.CONSOLE_MODE}',
+ nodeEnv: '${process.env.NODE_ENV}',
+ urlPrefix: '${process.env.URL_PREFIX}',
+ enableTelemetry: ${process.env.ENABLE_TELEMETRY},
+ assetsPath: '${process.env.ASSETS_PATH}',
+ assetsVersion: '${process.env.ASSETS_VERSION}',
+ serverVersion: '${process.env.SERVER_VERSION}',
+ cdnAssets: ${process.env.CDN_ASSETS},`;
if (process.env.ADMIN_SECRET !== undefined) {
- appendObj = `
- adminSecret: '${process.env.ADMIN_SECRET}'`;
+ envObj += `
+ adminSecret: '${process.env.ADMIN_SECRET}',`;
} else {
// ADMIN_SECRET is undefined
if (process.env.IS_ADMIN_SECRET_SET !== undefined) {
- appendObj = `isAdminSecretSet: ${process.env.IS_ADMIN_SECRET_SET}`;
- } else {
- // Both ADMIN_SECRET and IS_ADMIN_SECRET_SET is undefined
- if (process.env.ACCESS_KEY !== undefined) {
- appendObj = `accessKey: ${process.env.ACCESS_KEY}`;
- } else {
- appendObj = `isAccessKeySet: ${process.env.IS_ACCESS_KEY_SET}`;
- }
+ envObj += `
+ isAdminSecretSet: ${process.env.IS_ADMIN_SECRET_SET},`;
}
}
const env = `
- window.__env={\n\t\t${envObj}\t\t${appendObj}
+ window.__env={
+ ${envObj}
};
`;
diff --git a/console/src/reducer.js b/console/src/reducer.js
index 01e20cc3251..b5151c065c8 100644
--- a/console/src/reducer.js
+++ b/console/src/reducer.js
@@ -7,7 +7,7 @@ import mainReducer from './components/Main/Actions';
import apiExplorerReducer from 'components/Services/ApiExplorer/Actions';
import progressBarReducer from 'components/App/Actions';
import telemetryReducer from './telemetry/Actions';
-import { metadataReducer } from './components/Services/Metadata/Actions';
+import { metadataReducer } from './components/Services/Settings/Actions';
import { reducer as notifications } from 'react-notification-system-redux';
diff --git a/console/src/routes.js b/console/src/routes.js
index 9dc4683a062..1d83178d843 100644
--- a/console/src/routes.js
+++ b/console/src/routes.js
@@ -19,7 +19,7 @@ import { eventRouterUtils } from './components/Services/EventTrigger';
import { getRemoteSchemaRouter } from './components/Services/RemoteSchema';
-import generatedApiExplorer from './components/Services/ApiExplorer/ApiExplorerGenerator';
+import generatedApiExplorer from './components/Services/ApiExplorer/ApiExplorer';
import generatedVoyagerConnector from './components/Services/VoyagerView/VoyagerView';
@@ -27,34 +27,35 @@ import about from './components/Services/About/About';
import generatedLoginConnector from './components/Login/Login';
-import metadataContainer from './components/Services/Metadata/Container';
-import metadataOptionsContainer from './components/Services/Metadata/MetadataOptions/MetadataOptions';
-import metadataStatusContainer from './components/Services/Metadata/MetadataStatus/MetadataStatus';
-import allowedQueriesContainer from './components/Services/Metadata/AllowedQueries/AllowedQueries';
+import settingsContainer from './components/Services/Settings/Container';
+import metadataOptionsContainer from './components/Services/Settings/MetadataOptions/MetadataOptions';
+import metadataStatusContainer from './components/Services/Settings/MetadataStatus/MetadataStatus';
+import allowedQueriesContainer from './components/Services/Settings/AllowedQueries/AllowedQueries';
+import logoutContainer from './components/Services/Settings/Logout/Logout';
+
+import { showErrorNotification } from './components/Services/Common/Notification';
+import { CLI_CONSOLE_MODE } from './constants';
const routes = store => {
// load hasuractl migration status
const requireMigrationStatus = (nextState, replaceState, cb) => {
- if (globals.consoleMode === 'cli') {
- store.dispatch(loadMigrationStatus()).then(
+ const { dispatch } = store;
+
+ if (globals.consoleMode === CLI_CONSOLE_MODE) {
+ dispatch(loadMigrationStatus()).then(
() => {
cb();
},
r => {
if (r.code === 'data_api_error') {
- if (globals.adminSecret) {
- alert('Hasura CLI: ' + r.message);
- } else {
- alert(
- `Looks like CLI is not configured with the ${
- globals.adminSecretLabel
- }. Please configure and try again`
- );
- }
+ dispatch(showErrorNotification('Error', null, r));
} else {
- alert(
- 'Hasura console is not able to reach your Hasura GraphQL engine instance. Please ensure that your ' +
- 'instance is running and the endpoint is configured correctly.'
+ dispatch(
+ showErrorNotification(
+ 'Connection error',
+ 'Hasura console is not able to reach your Hasura GraphQL engine instance. Please ensure that your ' +
+ 'instance is running and the endpoint is configured correctly.'
+ )
);
}
}
@@ -102,17 +103,21 @@ const routes = store => {
component={generatedVoyagerConnector(connect)}
/>
-
-
-
+
+
+
+
{dataRouter}
{eventRouter}
diff --git a/console/src/utils/requestAction.js b/console/src/utils/requestAction.js
index e0d4790bb47..0f84ed023c5 100644
--- a/console/src/utils/requestAction.js
+++ b/console/src/utils/requestAction.js
@@ -1,18 +1,14 @@
import fetch from 'isomorphic-fetch';
import { push } from 'react-router-redux';
import globals from 'Globals';
-import { UPDATE_DATA_HEADERS } from 'components/Services/Data/DataActions';
import {
LOAD_REQUEST,
DONE_REQUEST,
FAILED_REQUEST,
ERROR_REQUEST,
- CONNECTION_FAILED,
} from 'components/App/Actions';
-import { LOGIN_IN_PROGRESS, LOGIN_ERROR } from 'components/Main/Actions';
-
const requestAction = (
url,
options,
@@ -25,7 +21,7 @@ const requestAction = (
}
return dispatch => {
- const p1 = new Promise((resolve, reject) => {
+ return new Promise((resolve, reject) => {
dispatch({ type: LOAD_REQUEST });
fetch(url, options).then(
response => {
@@ -59,18 +55,9 @@ const requestAction = (
});
}
if (msg.code && msg.code === 'access-denied') {
- dispatch({
- type: UPDATE_DATA_HEADERS,
- data: {
- 'content-type': 'application/json',
- [`x-hasura-${
- globals.adminSecretLabel
- }`]: globals.adminSecret,
- },
- });
- dispatch({ type: LOGIN_IN_PROGRESS, data: false });
- dispatch({ type: LOGIN_ERROR, data: false });
- dispatch(push(globals.urlPrefix + '/login'));
+ if (window.location.pathname !== globals.urlPrefix + '/login') {
+ dispatch(push(globals.urlPrefix + '/login'));
+ }
}
reject(msg);
});
@@ -84,13 +71,11 @@ const requestAction = (
});
},
error => {
- console.error(error);
+ console.error('Request error: ', error);
dispatch({ type: FAILED_REQUEST });
- dispatch({ type: CONNECTION_FAILED });
if (ERROR) {
dispatch({
type: ERROR,
- code: 'server-connection-failed',
message: error.message,
data: error.message,
});
@@ -99,7 +84,6 @@ const requestAction = (
}
);
});
- return p1;
};
};
diff --git a/console/src/utils/validateLogin.js b/console/src/utils/validateLogin.js
index 815776ff117..60a04b543a5 100644
--- a/console/src/utils/validateLogin.js
+++ b/console/src/utils/validateLogin.js
@@ -1,96 +1,43 @@
-import {
- loadAdminSecretState,
- clearAdminSecretState,
- CONSOLE_ADMIN_SECRET,
-} from '../components/AppState';
+import { clearAdminSecretState } from '../components/AppState';
import globals from '../Globals';
-import Endpoints, { globalCookiePolicy } from '../Endpoints';
-import requestAction from './requestActionPlain';
+import { verifyLogin } from '../components/Login/Actions';
-import { UPDATE_DATA_HEADERS } from '../components/Services/Data/DataActions';
-import { changeRequestHeader } from '../components/Services/ApiExplorer/Actions';
-
-import { SERVER_CONSOLE_MODE } from '../constants';
-
-const checkValidity = adminSecret => {
- return dispatch => {
- const url = Endpoints.getSchema;
- const currentSchema = 'public';
- const headers = {
- 'content-type': 'application/json',
- [`x-hasura-${globals.adminSecretLabel}`]: adminSecret,
- };
- const options = {
- credentials: globalCookiePolicy,
- method: 'POST',
- headers: headers,
- body: JSON.stringify({
- type: 'select',
- args: {
- table: {
- name: 'hdb_table',
- schema: 'hdb_catalog',
- },
- columns: ['table_schema'],
- where: { table_schema: currentSchema },
- limit: 1,
- },
- }),
- };
- return dispatch(requestAction(url, options));
- };
-};
+import { getAdminSecret } from '../components/Services/ApiExplorer/ApiRequest/utils';
+import { CLI_CONSOLE_MODE } from '../constants';
const validateLogin = ({ dispatch }) => {
return (nextState, replaceState, cb) => {
- // Validate isAdminSecretSet env is set by server or adminSecret env is set by cli
+ // care about admin secret only if it is set
if (globals.isAdminSecretSet || globals.adminSecret) {
- let adminSecret = '';
- // Check the console mode and retrieve adminSecret accordingly.
- if (globals.consoleMode === SERVER_CONSOLE_MODE) {
- adminSecret = loadAdminSecretState(CONSOLE_ADMIN_SECRET);
- } else {
- adminSecret = globals.adminSecret;
- }
- dispatch(checkValidity(adminSecret))
- .then(() => {
- return Promise.all([
- dispatch({
- type: UPDATE_DATA_HEADERS,
- data: {
- 'content-type': 'application/json',
- [`x-hasura-${globals.adminSecretLabel}`]: adminSecret,
- },
- }),
- dispatch(
- changeRequestHeader(
- 1,
- 'key',
- `x-hasura-${globals.adminSecretLabel}`,
- true
- )
- ),
- dispatch(changeRequestHeader(1, 'value', adminSecret, true)),
- ]);
- })
- .then(() => {
- if (nextState.location.pathname === '/login') {
- replaceState('/');
- }
- cb();
- })
- .catch(() => {
- // Clear state from the localStorage if there exists one
+ const validationSuccessCallback = () => {
+ if (nextState.location.pathname === '/login') {
+ replaceState('/');
+ }
+ cb();
+ };
+
+ const validationFailureCallback = () => {
+ if (globals.consoleMode !== CLI_CONSOLE_MODE) {
clearAdminSecretState();
- if (nextState.location.pathname !== '/login') {
- replaceState('/login');
- }
- cb();
- });
+ }
+
+ if (nextState.location.pathname !== '/login') {
+ replaceState('/login');
+ }
+ cb();
+ };
+
+ const adminSecret = getAdminSecret();
+
+ verifyLogin({
+ adminSecret,
+ successCallback: validationSuccessCallback,
+ errorCallback: validationFailureCallback,
+ dispatch,
+ });
} else {
cb();
- return;
}
};
};