diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d51eebb6aea55..ef343062bf5d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ consisting of 3 components. Each have their own contributing guides: 1. [Server (Haskell)](server/CONTRIBUTING.md) 2. [CLI (Go)](cli/CONTRIBUTING.md) -3. [Console (JavaScript)](console/CONTRIBUTING.md) +3. [Console (JavaScript)](console/README.md#contributing-to-hasura-console) All of the three components have a single version, denoted by either the git tag, or a combination of branch name and git commit SHA. diff --git a/assets/console-readme-assets/start-dev-server.jpg b/assets/console-readme-assets/start-dev-server.jpg new file mode 100644 index 0000000000000..af9f2d216c43d Binary files /dev/null and b/assets/console-readme-assets/start-dev-server.jpg differ diff --git a/assets/console-readme-assets/test-dev-setup.jpg b/assets/console-readme-assets/test-dev-setup.jpg new file mode 100644 index 0000000000000..b387a5693f600 Binary files /dev/null and b/assets/console-readme-assets/test-dev-setup.jpg differ diff --git a/console/CONTRIBUTING.md b/console/CONTRIBUTING.md deleted file mode 100644 index af5cfda615db9..0000000000000 --- a/console/CONTRIBUTING.md +++ /dev/null @@ -1,39 +0,0 @@ -## Contributing - -This guide is for setting-up the console for development on your own machine, and how to contribute. - -### Pre-requisites - -- Node.js (v8.9+) -- Hasura CLI (for working with migrations) -- Hasura GraphQL Engine Server - -## Development Workflow - -### Fork and clone - -- Fork the repo on GitHub -- Clone your forked repo: `git clone https://github.com//graphql-engine` - -### Setup - -- Run `npm install` to install the modules. -- Make sure the graphql-engine server is running. It can be either local or pointing to a cloud url. -- Run `npm run build` to build the console. - -### Develop - -- Configure .env file according to [README.md](./README.md), where you specify environment variables for the development setup. -- Run `npm run dev` to start console in development mode. -- Run `hasura console` in case the `CONSOLE_MODE` is `cli`. - -### Test - -- Run tests: `npm run test` -- Write your tests in the `cypress` directory, integration. - -### Create Pull Request - -- Make sure your commit messages meet the [guidelines](../CONTRIBUTING.md). -- Create a pull request from your forked repo to the main repo. -- Every pull request will automatically build and run the tests. diff --git a/console/README.md b/console/README.md index dfee52e91d8fe..1c702d2012b53 100644 --- a/console/README.md +++ b/console/README.md @@ -1,29 +1,143 @@ -## Usage of Environment Variables + -This app uses a few environment variables which are required for development. The production build uses values directly injected by the server serving this app. +# Hasura Console -We use [dotenv](https://github.com/motdotla/dotenv) for setting environment variables for development. Create a `.env' file in the root directory (wherever package.json is) and set the following values. Replace accordingly for testing. +The Hasura console is an admin dashboard to manage the connected database and to try out GraphQL APIs. It is a React application bundled with webpack and the state is managed using Redux. +Served by + +1. Hasura GraphQL Engine: + The console is served by GraphQL Engine at `/console` endpoint (when `--enable-console` flag is used). Typically runs in **No Migration Mode** which means that actions on the console are not spitting out migration “yaml” files automatically. Most users will be using the Hasura console in this mode. + +2. Hasura CLI: + Served by the Hasura CLI using `hasura console` command, typically runs with migration mode **enabled**. All the changes to schema/hasura metadata will be tracked and spit out on the filesystem as migration yaml files and a metadata yaml file. This allows for easy version controlling of the schema/hasura metadata. + +## Contributing to Hasura console + +This guide is for setting-up the console for development on your own machine, and how to contribute. + +### Prerequisites + +- Node.js (v8.9+) +- [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 + +- Fork the repo on GitHub. +- Clone your forked repo: `git clone https://github.com//graphql-engine` + +```bash +git clone https://github.com//graphql-engine +cd graphql-engine +cd console +npm install ``` + +Hasura console can be developed in two modes (`server` or `cli` mode). Both modes requires a running instance of GraphQL Enigne. 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 is documented [here](https://docs.hasura.io/1.0/graphql/manual/getting-started/index.html). + +### 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 `.herokuapp.com`, if it's on you local machine, it's probably `http://localhost:8080`. + +[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). Sample `.env` file will look like below + +Sample environment variables: + +```bash PORT=3000 NODE_ENV=development -DATA_API_URL=http://localhost:9000 -DEV_DATA_API_URL=http://localhost:9000 +DATA_API_URL=http://localhost:8080 +ACCESS_KEY=xyz +CONSOLE_MODE=server +URL_PREFIX=/ +``` + +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). + +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 .herokuapp.com. +4. `ACCESS_KEY`: Set access key if Hasura GraphQL engine is configured to run with ACCESS_KEY. +5. `CONSOLE_MODE`: `server` +6. `URL_PREFIX`: ‘/’ (forward slash) + +#### Run Development Server: + +```bash + npm run dev +``` + +### Development with Hasura CLI (`cli` mode) + +Configure .env file with appropriate values for the required environment variables. + +Sample environment variables: + +```bash +PORT=3000 +NODE_ENV=development +DATA_API_URL=http://localhost:8080 API_HOST=http://localhost API_PORT=9693 -ACCESS_KEY=abcd -IS_ACCESS_KEY_SET=false +ACCESS_KEY=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 .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. `ACCESS_KEY`: Set access key if Hasura GraphQL engine is configured to run with ACCESS_KEY +7. `CONSOLE_MODE`: `cli` +8. `URL_PREFIX`: ‘/’ (forward slash) + +#### 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 + +```bash +hasura console +``` + +##### Start development server + +```bash +npm run dev +``` + +### Checkout the console + +Visit [http://localhost:3000](http://localhost:3000) to confirm the setup. + +![Testing Development Server](../assets/console-readme-assets/test-dev-setup.jpg) + +### Make changes to code + +Make changes to the code and the console will reload automatically to reflect the new changes. Keep iterating. +When adding a new feature, it is recommended to add corresponding tests too. + +Tests are written using [Cypress](https://www.cypress.io/). + +### Run Tests + +- Run tests: `npm run cypress` +- Write your tests in the `cypress` directory, integration. + +### Submitting a pull request -**Note** +- All the development work happens in your own fork of the graphql-engine. +- Make sure your commit messages meet the [guidelines](../CONTRIBUTING.md#commit-messages). +- Once the changes are done, create a pull request. +- CI configured for PR will run the test suite. +- Once everything goes well, it will generate a preview heroku app. +- The source code and the preview app will be reviewed by maintainers. -- The .env file should not be in version control. -- CONSOLE_MODE can be either 'cli' or 'hasuradb'. -- API_HOST and API_PORT are for contacting hasura cli console server. -- ACCESS_KEY will be set by hasura cli. -- IS_ACCESS_KEY_SET will be set by graphql-engine server. -- DEV_DATA_API_URL is used to simulate cli console, where server can be hosted anywhere. -- URL_PREFIX can be changed to host console on a different base URL path. -- + diff --git a/console/src/Globals.js b/console/src/Globals.js index faa50c189f79f..883813e91bff7 100644 --- a/console/src/Globals.js +++ b/console/src/Globals.js @@ -1,3 +1,5 @@ +import { SERVER_CONSOLE_MODE } from './constants'; + const checkExtraSlashes = url => { if (!url) { return url; @@ -16,7 +18,10 @@ const globals = { nodeEnv: window.__env.nodeEnv, accessKey: window.__env.accessKey, isAccessKeySet: window.__env.isAccessKeySet, - consoleMode: window.__env.consoleMode, + consoleMode: + window.__env.consoleMode === 'hasuradb' + ? 'server' + : window.__env.consoleMode, urlPrefix: checkExtraSlashes(window.__env.urlPrefix), }; @@ -26,7 +31,7 @@ if (!window.__env.urlPrefix) { } if (!window.__env.consoleMode) { - globals.consoleMode = 'hasuradb'; + globals.consoleMode = SERVER_CONSOLE_MODE; } if (!window.__env.accessKey) { @@ -37,7 +42,7 @@ if (!window.__env.isAccessKeySet) { globals.isAccessKeySet = false; } -if (globals.consoleMode === 'hasuradb') { +if (globals.consoleMode === SERVER_CONSOLE_MODE) { if (globals.nodeEnv !== 'development') { const windowUrl = window.location.protocol + '//' + window.location.host; globals.dataApiUrl = windowUrl; diff --git a/console/src/components/Common/validateLogin.js b/console/src/components/Common/validateLogin.js index 0bbc8111f4615..40aec719cc17a 100644 --- a/console/src/components/Common/validateLogin.js +++ b/console/src/components/Common/validateLogin.js @@ -7,6 +7,8 @@ import requestAction from '../../utils/requestActionPlain'; import { UPDATE_DATA_HEADERS } from '../Services/Data/DataActions'; import { changeRequestHeader } from '../ApiExplorer/Actions'; +import { SERVER_CONSOLE_MODE } from '../../constants'; + const checkValidity = accessKey => { return dispatch => { const url = Endpoints.getSchema; @@ -38,11 +40,11 @@ const checkValidity = accessKey => { const validateLogin = ({ dispatch }) => { return (nextState, replaceState, cb) => { - // Validate isAccessKeySet env is set by hasuradb or accessKey env is set by cli + // Validate isAccessKeySet env is set by server or accessKey env is set by cli if (globals.isAccessKeySet || globals.accessKey) { let accessKey = ''; // Check the console mode and retrieve accessKey accordingly. - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { accessKey = loadAccessKeyState('CONSOLE_ACCESS_KEY'); } else { accessKey = globals.accessKey; diff --git a/console/src/components/Services/Data/Common/getMigrateUrl.js b/console/src/components/Services/Data/Common/getMigrateUrl.js index d74dac8a533b6..55e2e3621a54b 100644 --- a/console/src/components/Services/Data/Common/getMigrateUrl.js +++ b/console/src/components/Services/Data/Common/getMigrateUrl.js @@ -1,10 +1,12 @@ import Endpoints from '../../../../Endpoints'; import globals from '../../../../Globals'; +import { SERVER_CONSOLE_MODE } from '../../../../constants'; + const returnMigrateUrl = mode => { if (globals.consoleMode === 'cli') { return mode ? Endpoints.hasuractlMigrate : Endpoints.hasuractlMetadata; - } else if (globals.consoleMode === 'hasuradb') { + } else if (globals.consoleMode === SERVER_CONSOLE_MODE) { return Endpoints.query; } }; diff --git a/console/src/components/Services/Data/DataActions.js b/console/src/components/Services/Data/DataActions.js index 68dece2ffdd2e..db3289f5c77f4 100644 --- a/console/src/components/Services/Data/DataActions.js +++ b/console/src/components/Services/Data/DataActions.js @@ -12,6 +12,8 @@ import { loadMigrationStatus } from '../../Main/Actions'; import returnMigrateUrl from './Common/getMigrateUrl'; import globals from '../../../Globals'; +import { SERVER_CONSOLE_MODE } from '../../../constants'; + const SET_TABLE = 'Data/SET_TABLE'; const LOAD_SCHEMA = 'Data/LOAD_SCHEMA'; const LOAD_UNTRACKED_SCHEMA = 'Data/LOAD_UNTRACKED_SCHEMA'; @@ -202,7 +204,7 @@ const setTable = tableName => ({ type: SET_TABLE, tableName }); const handleMigrationErrors = (title, errorMsg) => dispatch => { const requestMsg = title; - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { // handle errors for run_sql based workflow dispatch(showErrorNotification(title, errorMsg.code, requestMsg, errorMsg)); } else if (errorMsg.code === 'migration_failed') { @@ -264,7 +266,7 @@ const makeMigrationCall = ( const migrateUrl = returnMigrateUrl(currMigrationMode); let finalReqBody; - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { finalReqBody = upQuery; } else if (globals.consoleMode === 'cli') { finalReqBody = migrationBody; @@ -279,7 +281,7 @@ const makeMigrationCall = ( const onSuccess = () => { if (globals.consoleMode === 'cli') { - dispatch(loadMigrationStatus()); // don't call for hasuradb mode + dispatch(loadMigrationStatus()); // don't call for server mode } dispatch(loadSchema()); customOnSuccess(); diff --git a/console/src/components/Services/Data/DataRouter.js b/console/src/components/Services/Data/DataRouter.js index c3f17d4e5cfbb..6f3567dbff7eb 100644 --- a/console/src/components/Services/Data/DataRouter.js +++ b/console/src/components/Services/Data/DataRouter.js @@ -3,6 +3,7 @@ import React from 'react'; import { Route, IndexRedirect } from 'react-router'; import globals from '../../../Globals'; // import { loadAccessKeyState } from '../../AppState'; +import { SERVER_CONSOLE_MODE } from '../../../constants'; import { schemaConnector, @@ -168,7 +169,7 @@ const dataRouter = (connect, store, composeOnEnterHooks) => { cb(); }; const consoleModeRedirects = (nextState, replaceState, cb) => { - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { replaceState('/data/schema'); cb(); } diff --git a/console/src/components/Services/EventTrigger/Common/getMigrateUrl.js b/console/src/components/Services/EventTrigger/Common/getMigrateUrl.js index d74dac8a533b6..55e2e3621a54b 100644 --- a/console/src/components/Services/EventTrigger/Common/getMigrateUrl.js +++ b/console/src/components/Services/EventTrigger/Common/getMigrateUrl.js @@ -1,10 +1,12 @@ import Endpoints from '../../../../Endpoints'; import globals from '../../../../Globals'; +import { SERVER_CONSOLE_MODE } from '../../../../constants'; + const returnMigrateUrl = mode => { if (globals.consoleMode === 'cli') { return mode ? Endpoints.hasuractlMigrate : Endpoints.hasuractlMetadata; - } else if (globals.consoleMode === 'hasuradb') { + } else if (globals.consoleMode === SERVER_CONSOLE_MODE) { return Endpoints.query; } }; diff --git a/console/src/components/Services/EventTrigger/EventActions.js b/console/src/components/Services/EventTrigger/EventActions.js index 8540c235ce71c..a1d3aabebfe18 100644 --- a/console/src/components/Services/EventTrigger/EventActions.js +++ b/console/src/components/Services/EventTrigger/EventActions.js @@ -12,6 +12,8 @@ import returnMigrateUrl from './Common/getMigrateUrl'; import globals from '../../../Globals'; import { push } from 'react-router-redux'; +import { SERVER_CONSOLE_MODE } from '../../../constants'; + const SET_TRIGGER = 'Event/SET_TRIGGER'; const LOAD_TRIGGER_LIST = 'Event/LOAD_TRIGGER_LIST'; const LOAD_PROCESSED_EVENTS = 'Event/LOAD_PROCESSED_EVENTS'; @@ -291,7 +293,7 @@ const setRedeliverEvent = eventId => dispatch => { const handleMigrationErrors = (title, errorMsg) => dispatch => { const requestMsg = title; - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { // handle errors for run_sql based workflow dispatch(showErrorNotification(title, errorMsg.code, requestMsg, errorMsg)); } else if (errorMsg.code === 'migration_failed') { @@ -353,7 +355,7 @@ const makeMigrationCall = ( const migrateUrl = returnMigrateUrl(currMigrationMode); let finalReqBody; - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { finalReqBody = upQuery; } else if (globals.consoleMode === 'cli') { finalReqBody = migrationBody; @@ -368,7 +370,7 @@ const makeMigrationCall = ( const onSuccess = () => { if (globals.consoleMode === 'cli') { - dispatch(loadMigrationStatus()); // don't call for hasuradb mode + dispatch(loadMigrationStatus()); // don't call for server mode } dispatch(loadTriggers()); customOnSuccess(); diff --git a/console/src/components/Services/EventTrigger/EventRouter.js b/console/src/components/Services/EventTrigger/EventRouter.js index be3a1ad435e14..954433139534c 100644 --- a/console/src/components/Services/EventTrigger/EventRouter.js +++ b/console/src/components/Services/EventTrigger/EventRouter.js @@ -22,6 +22,8 @@ import { loadRunningEvents, } from '../EventTrigger/EventActions'; +import { SERVER_CONSOLE_MODE } from '../../../constants'; + const makeEventRouter = ( connect, store, @@ -166,7 +168,7 @@ const eventRouter = (connect, store, composeOnEnterHooks) => { cb(); }; const consoleModeRedirects = (nextState, replaceState, cb) => { - if (globals.consoleMode === 'hasuradb') { + if (globals.consoleMode === SERVER_CONSOLE_MODE) { replaceState(globals.urlPrefix + '/events/manage'); cb(); } diff --git a/console/src/constants.js b/console/src/constants.js new file mode 100644 index 0000000000000..b0614bc7a4c52 --- /dev/null +++ b/console/src/constants.js @@ -0,0 +1,3 @@ +const SERVER_CONSOLE_MODE = 'server'; + +export { SERVER_CONSOLE_MODE }; diff --git a/server/src-rsr/console.html b/server/src-rsr/console.html index 782a3d0626ee9..77aff5a79aecc 100644 --- a/server/src-rsr/console.html +++ b/server/src-rsr/console.html @@ -3,7 +3,7 @@