separate server and cli env variables in console local dev (#2937)

This commit is contained in:
Rishichandra Wawhal 2019-10-08 15:53:01 +05:30 committed by Rikin Kachhia
parent 453a544d83
commit 5ced530ccd
8 changed files with 139 additions and 101 deletions

View File

@ -28,7 +28,7 @@ Feel free to open pull requests to address these issues or to add/fix console f
- [Hasura GraphQL Engine](https://docs.hasura.io/1.0/graphql/manual/getting-started/index.html)
- [Hasura CLI](https://docs.hasura.io/1.0/graphql/manual/hasura-cli/install-hasura-cli.html) (for working with migrations)
### Setup and Install Dependencies
### Set up and install dependencies
- Fork the repo on GitHub.
- Clone your forked repo: `git clone https://github.com/<your-username>/graphql-engine`
@ -40,88 +40,114 @@ cd console
npm install
```
Hasura console can be developed in two modes (`server` or `cli` mode). Both modes require a running instance of GraphQL Engine. The easiest way to get Hasura GraphQL engine instance is by Heroku. You can get it by following the steps given in [this](https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html) link. Other methods to install Hasura GraphQL engine are documented [here](https://docs.hasura.io/1.0/graphql/manual/getting-started/index.html).
### Run console development server
### Development with Hasura GraphQL Engine (`server` mode)
Hasura console can be developed in two modes, `server` or `cli` mode. If you are looking to add/tweak functionality related to migrations, check out [Development with Hasura CLI](#development-with-hasura-cli-cli-mode), otherwise check out [Development with Hasura GraphQL engine](#development-with-hasura-graphql-engine-server-mode).
Hasura GraphQL engine should be running to develop console in this mode. If you have set it up on Heroku, your url will look like `<app-name>.herokuapp.com`, if it's on your local machine, it's probably `http://localhost:8080`.
Both modes require a running instance of GraphQL Engine. The easiest way to get Hasura GraphQL engine instance is by Heroku. You can get it by following the steps given in [this](https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html) link. Other methods to install Hasura GraphQL engine are documented [here](https://docs.hasura.io/1.0/graphql/manual/getting-started/index.html).
[Dotenv](https://github.com/motdotla/dotenv) is used for setting environment variables for development. Create a `.env` file in the root directory for console (wherever package.json is). Here's a `.env` file with some environment variable examples :
[Dotenv](https://github.com/motdotla/dotenv) is used for setting environment variables for development. In production, these environment variables are templated by the server or CLI.
```bash
PORT=3000
NODE_ENV=development
DATA_API_URL=http://localhost:8080
ADMIN_SECRET=xyz
IS_ADMIN_SECRET_SET=true
CONSOLE_MODE=server
URL_PREFIX=/
ASSETS_PATH=https://graphql-engine-cdn.hasura.io/console/assets
ASSETS_VERSION=channel/beta/v1.0
CDN_ASSETS=true
```
#### Develop with Hasura GraphQL engine (`server` mode)
Note that `CONSOLE_MODE` is set to `server`. In this mode, **migrations** will be disabled and the corresponding functionality on the console will be hidden. If you are looking to add/tweak functionality related to migrations, check out [Development with Hasura CLI](#development-with-hasura-cli-cli-mode).
In server mode, **migrations** will be disabled and the corresponding functionality on the console will be hidden.
##### Set up `.env` file
Environment variables accepted in `server` mode:
1. `PORT`: Configure the port where Hasura console will run locally.
2. `NODE_ENV`: `development`
3. `DATA_API_URL`: Configure it with the Hasura GraphQL Engine url. If you are running it on Heroku, your url will look like `<app-name>.herokuapp.com`
4. `ADMIN_SECRET`: Set admin secret if Hasura GraphQL engine is configured to run with ADMIN_SECRET.
5. `CONSOLE_MODE`: `server`
6. `URL_PREFIX`: `/` (forward slash)
- `NODE_ENV`: Console build environment (`development`/`production`)
- `PORT`: The port where Hasura console will run locally
- `CDN_ASSETS`: Should assets be loaded from CDN (`true`/`false`)
- `ASSETS_PATH`: Path to console assets
- `ASSETS_VERSION`: Version of console assets being served
- `ENABLE_TELEMETRY`: Whether to enable telemetry (`true`/`false`)
- `URL_PREFIX`: Path at which the console is running
- `DATA_API_URL`: The Hasura GraphQL engine url. (If you are running it on Heroku, it will look like <app-name>.herokuapp.com, if you are running locally, it will look like http://localhost:<port>)
- `SERVER_VERSION`: Hasura GraphQL Engine server version
- `CONSOLE_MODE`: In server mode, it should be `server`
- `IS_ADMIN_SECRET_SET`: Is GraphQl engine configured with an admin secret (`true`/`false`)
> The server also templates `consolePath` in `window.__env` which is the relative path of the current page (something like `/console/data/schema/public`). Using this path, the console determines the DATA_API_URL. You do not need to worry about this in development since you are hardcoding the value of DATA_API_URL in `.env`.
Here's an example `.env` file for `server` mode:
#### Run Development Server:
```bash
NODE_ENV=development
PORT=3000
CDN_ASSETS=true
ASSETS_PATH=https://graphql-engine-cdn.hasura.io/console/assets
ASSETS_VERSION=channel/beta/v1.0
ENABLE_TELEMETRY=true
URL_PREFIX=/
DATA_API_URL=http://localhost:8080
SERVER_VERSION=v1.0.0-beta.6
CONSOLE_MODE=server
IS_ADMIN_SECRET_SET=true
```
> The server also templates `consolePath` in `window.__env` which is the relative path of the current page (something like `/console/data/schema/public`). Using this path, the console determines the DATA_API_URL in production. You do not need to worry about this in development since you are hardcoding the value of DATA_API_URL in `.env`.
##### Run console development server:
```bash
npm run dev
```
### Development with Hasura CLI (`cli` mode)
#### Develop with Hasura CLI (`cli` mode)
Configure .env file with appropriate values for the required environment variables, such as the examples below:
##### Set up `.env` file
```bash
PORT=3000
NODE_ENV=development
DATA_API_URL=http://localhost:8080
API_HOST=http://localhost
API_PORT=9693
ADMIN_SECRET=xyz
CONSOLE_MODE=cli
URL_PREFIX=/
```
Environment variables accepted in `cli` mode:
1. `PORT`: Configure the port where Hasura console will run locally.
2. `NODE_ENV`: `development`
3. `DATA_API_URL`: Configure it with the Hasura GraphQL Engine url. If you are running it on Heroku. Your url will look like <app-name>.herokuapp.com
4. `API_HOST`: Hasura CLI host. Hasura CLI runs on `http://localhost` by default.
5. `API_PORT`: Hasura CLI port. Hasura CLI exposes the API at `9693` by default
6. `ADMIN_SECRET`: Set admin secret if Hasura GraphQL engine is configured to run with ADMIN_SECRET
7. `CONSOLE_MODE`: `cli`
8. `URL_PREFIX`: / (forward slash)
- `NODE_ENV`: Console build environment (`development`/`production`)
- `PORT`: The port where Hasura console will run locally
- `API_HOST`: Hasura CLI host. Hasura CLI runs on `http://localhost` by default.
- `API_PORT`: Hasura CLI port. Hasura CLI exposes the API at `9693` by default
- `CDN_ASSETS`: Should assets be loaded from CDN (`true`/`false`)
- `ASSETS_PATH`: Path to console assets
- `ASSETS_VERSION`: Version of console assets being served
- `ENABLE_TELEMETRY`: Whether to enable telemetry (`true`/`false`)
- `URL_PREFIX`: Path at which the console is running
- `DATA_API_URL`: The Hasura GraphQL engine url. (If you are running it on Heroku, it will look like <app-name>.herokuapp.com, if you are running locally, it will look like http://localhost:<port>)
- `SERVER_VERSION`: Hasura GraphQL Engine server version
- `CONSOLE_MODE`: In cli mode, it should be `cli`
- `ADMIN_SECRET`: the admin secret passed via the CLI
#### Run Development Server:
This setup requires hasura cli to be running in a different window. Start hasura cli with the same Hasura GraphQL engine url as configured for `DATA_API_URL`.
##### Start Hasura CLI server
Here's an example `.env` file for `cli` mode:
```bash
hasura console
NODE_ENV=development
PORT=3000
API_HOST=http://localhost
API_PORT=9693
CDN_ASSETS=true
ASSETS_PATH=https://graphql-engine-cdn.hasura.io/console/assets
ASSETS_VERSION=channel/beta/v1.0
ENABLE_TELEMETRY=true
URL_PREFIX=/
DATA_API_URL=http://localhost:8080
SERVER_VERSION=v1.0.0-beta.6
CONSOLE_MODE=cli
ADMIN_SECRET=my-admin-secret
```
##### Start development server
##### Run console development server:
This setup requires a Hasura CLI console server to be running.
###### Start Hasura CLI console server
Start Hasura CLI console with the same Hasura GraphQL engine url as configured for `DATA_API_URL`.
```bash
hasura console --endpoint <DATA_API_URL> --admin-secret <your-admin-secret> (optional)
```
###### Start development console server
```bash
npm run dev
```
### Checkout the console
### Check out the console
Visit [http://localhost:3000](http://localhost:3000) to confirm the setup.
@ -140,7 +166,7 @@ It should automatically connect to the Redux store when started in development m
By default [redux-logger](https://www.npmjs.com/package/redux-logger) is enabled to assist in development.
You can disable it if you wish by commenting out the `createLogger` line in `src/client.js`
### Run Tests
### Run tests
- Run tests: `npm run cypress`
- Write your tests in the `cypress` directory, integration.

View File

@ -2,6 +2,7 @@ import { SERVER_CONSOLE_MODE } from './constants';
import { getFeaturesCompatibility } from './helpers/versionUtils';
import { stripTrailingSlash } from './components/Common/utils/urlUtils';
// TODO: move this section to a more appropriate location
/* set helper tools into window */
import sqlFormatter from './helpers/sql-formatter.min';
@ -19,19 +20,19 @@ if (
/* initialize globals */
const isProduction = window.__env.nodeEnv === 'production';
const globals = {
apiHost: window.__env.apiHost,
apiPort: window.__env.apiPort,
dataApiUrl: stripTrailingSlash(window.__env.dataApiUrl),
devDataApiUrl: window.__env.devDataApiUrl,
nodeEnv: window.__env.nodeEnv,
adminSecret: window.__env.adminSecret || null, // will be updated after login/logout
isAdminSecretSet: window.__env.isAdminSecretSet || false,
dataApiUrl: stripTrailingSlash(window.__env.dataApiUrl), // overridden below if server mode
urlPrefix: stripTrailingSlash(window.__env.urlPrefix || '/'), // overridden below if server mode in production
adminSecret: window.__env.adminSecret || null, // gets updated after login/logout in server mode
isAdminSecretSet:
window.__env.isAdminSecretSet || window.__env.adminSecret || false,
consoleMode: window.__env.consoleMode || SERVER_CONSOLE_MODE,
urlPrefix: stripTrailingSlash(window.__env.urlPrefix) || '',
enableTelemetry: window.__env.enableTelemetry,
telemetryTopic:
window.__env.nodeEnv !== 'development' ? 'console' : 'console_test',
telemetryTopic: isProduction ? 'console' : 'console_test',
assetsPath: window.__env.assetsPath,
serverVersion: window.__env.serverVersion,
consoleAssetVersion: CONSOLE_ASSET_VERSION, // set during console build
@ -41,22 +42,24 @@ const globals = {
};
if (globals.consoleMode === SERVER_CONSOLE_MODE) {
if (globals.nodeEnv !== 'development') {
if (isProduction) {
const consolePath = window.__env.consolePath;
if (consolePath) {
const currentUrl = stripTrailingSlash(window.location.href);
const currentPath = stripTrailingSlash(window.location.pathname);
globals.dataApiUrl = currentUrl.slice(
0,
currentUrl.lastIndexOf(consolePath)
);
const currentPath = stripTrailingSlash(window.location.pathname);
globals.urlPrefix =
currentPath.slice(0, currentPath.lastIndexOf(consolePath)) + '/console';
} else {
const windowUrl = window.location.protocol + '//' + window.location.host;
const windowHostUrl =
window.location.protocol + '//' + window.location.host;
globals.dataApiUrl = windowUrl;
globals.dataApiUrl = windowHostUrl;
}
}
}

View File

@ -53,7 +53,10 @@ class App extends Component {
);
}
if (telemetry.console_opts && !telemetry.console_opts.telemetryNotificationShown) {
if (
telemetry.console_opts &&
!telemetry.console_opts.telemetryNotificationShown
) {
dispatch(showTelemetryNotification());
dispatch(telemetryNotificationShown());
}

View File

@ -226,7 +226,7 @@ class Main extends React.Component {
const getAdminSecretSection = () => {
let adminSecretHtml = null;
if (!(globals.isAdminSecretSet || globals.adminSecret)) {
if (!globals.isAdminSecretSet) {
adminSecretHtml = (
<div className={styles.secureSection}>
<a

View File

@ -222,7 +222,7 @@ export const dropInconsistentObjects = () => {
};
export const isMetadataStatusPage = () => {
return window.location.pathname.includes('/setting/metadata-status');
return window.location.pathname.includes('/settings/metadata-status');
};
export const redirectToMetadataStatus = () => {
@ -535,7 +535,7 @@ export const metadataReducer = (state = defaultState, action) => {
...state,
allowedQueries: [
...state.allowedQueries.map(q =>
(q.name === action.data.queryName ? action.data.newQuery : q)
q.name === action.data.queryName ? action.data.newQuery : q
),
],
};

View File

@ -1,31 +1,36 @@
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},`;
import { CLI_CONSOLE_MODE } from '../constants';
if (process.env.ADMIN_SECRET !== undefined) {
envObj += `
adminSecret: '${process.env.ADMIN_SECRET}',`;
} else {
// ADMIN_SECRET is undefined
if (process.env.IS_ADMIN_SECRET_SET !== undefined) {
envObj += `
isAdminSecretSet: ${process.env.IS_ADMIN_SECRET_SET},`;
}
}
const env = `
window.__env={
${envObj}
};
const serverEnvVars = `
dataApiUrl: '${process.env.DATA_API_URL}',
isAdminSecretSet: '${process.env.IS_ADMIN_SECRET_SET}',
consoleMode: '${process.env.CONSOLE_MODE}',
nodeEnv: '${process.env.NODE_ENV}',
serverVersion: '${process.env.SERVER_VERSION}',
urlPrefix: '${process.env.URL_PREFIX}',
consolePath: '${process.env.CONSOLE_PATH}',
enableTelemetry: ${process.env.ENABLE_TELEMETRY},
assetsPath: '${process.env.ASSETS_PATH}',
assetsVersion: '${process.env.ASSETS_VERSION}',
cdnAssets: ${process.env.CDN_ASSETS}
`;
export { env };
const cliEnvVars = `
apiPort: '${process.env.API_PORT}',
apiHost: '${process.env.API_HOST}',
dataApiUrl: '${process.env.DATA_API_URL}',
adminSecret: '${process.env.ADMIN_SECRET}',
consoleMode: '${process.env.CONSOLE_MODE}',
nodeEnv: '${process.env.NODE_ENV}',
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},
`;
const envVars =
process.env.CONSOLE_MODE === CLI_CONSOLE_MODE ? cliEnvVars : serverEnvVars;
export const env = `
window.__env = {${envVars}};
`;

View File

@ -2,6 +2,7 @@ import Endpoints, { globalCookiePolicy } from '../Endpoints';
import requestAction from '../utils/requestAction';
import dataHeaders from '../components/Services/Data/Common/Headers';
import defaultTelemetryState from './State';
import globals from '../Globals';
const SET_CONSOLE_OPTS = 'Telemetry/SET_CONSOLE_OPTS';
const SET_NOTIFICATION_SHOWN = 'Telemetry/SET_NOTIFICATION_SHOWN';
@ -43,7 +44,7 @@ const setNotificationShownInDB = () => (dispatch, getState) => {
const loadConsoleTelemetryOpts = () => {
return (dispatch, getState) => {
if (window.__env.enableTelemetry === undefined) {
if (globals.enableTelemetry === undefined) {
return dispatch({ type: SET_TELEMETRY_DISABLED });
}

View File

@ -9,7 +9,7 @@ import { CLI_CONSOLE_MODE } from '../constants';
const validateLogin = ({ dispatch }) => {
return (nextState, replaceState, cb) => {
// care about admin secret only if it is set
if (globals.isAdminSecretSet || globals.adminSecret) {
if (globals.isAdminSecretSet) {
const validationSuccessCallback = () => {
if (nextState.location.pathname === '/login') {
replaceState('/');