Repository: jhipster/generator-jhipster
Pull request #7386 (2018-03-31 23:11:44)

React fixes and general polish for v5
TODO:

- [x] Authorization in React

- Please make sure the below checklist is followed for Pull Requests.

- [ ] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [ ] Tests are added where necessary
- [ ] Documentation is added/updated where necessary
- [ ] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed



Patch:
diff --git a/generators/app/index.js b/generators/app/index.js
index 8f4a0b9463..e621e3e541 100644
--- a/generators/app/index.js
+++ b/generators/app/index.js
@@ -49,6 +49,13 @@ module.exports = class extends BaseGenerator {
             defaults: false
         });
 
+        // This adds support for a `--skip-commit-hook` flag
+        this.option('skip-commit-hook', {
+            desc: 'Skip adding husky commit hooks',
+            type: Boolean,
+            defaults: false
+        });
+
         // This adds support for a `--skip-user-management` flag
         this.option('skip-user-management', {
             desc: 'Skip the user management module during app generation',
@@ -274,6 +281,7 @@ module.exports = class extends BaseGenerator {
 
                 this.composeWith(require.resolve('../client'), {
                     'skip-install': this.options['skip-install'],
+                    'skip-commit-hook': this.options['skip-commit-hook'],
                     configOptions: this.configOptions,
                     force: this.options.force,
                     debug: this.isDebugEnabled
@@ -337,7 +345,7 @@ module.exports = class extends BaseGenerator {
     get writing() {
         return {
             cleanup() {
-                cleanup.cleanupOldFiles(this);
+                cleanup.cleanupOldFiles(this, this.javaDir, this.testDir);
             },
 
             regenerateEntities() {
diff --git a/generators/cleanup.js b/generators/cleanup.js
index 2243a7e919..c9c845f737 100644
--- a/generators/cleanup.js
+++ b/generators/cleanup.js
@@ -21,7 +21,6 @@ const constants = require('./generator-constants');
 
 const ANGULAR_DIR = constants.ANGULAR_DIR;
 const CLIENT_MAIN_SRC_DIR = constants.CLIENT_MAIN_SRC_DIR;
-const CLIENT_TEST_SRC_DIR = constants.CLIENT_TEST_SRC_DIR;
 
 module.exports = {
     cleanupOldFiles,
@@ -29,46 +28,22 @@ module.exports = {
 };
 
 /**
- * Removes files that where generated in previous JHipster versions and therefore
- * need to be removed.
- *
- * WARNING this only removes files created by the main generator. Each sub-generator
- * should clean-up its own files: see the `cleanup` method in entity/index.js for cleaning
- * up entities.
+ * Removes files that where generated in previous JHipster versions and therefore need to be removed
  *
  * @param {any} generator - reference to generator
+ * @param {string} javaDir - Java Dir
+ * @param {string} testDir - Test Dir
  */
-function cleanupOldFiles(generator) {
+function cleanupOldFiles(generator, javaDir, testDir) {
     if (generator.isJhipsterVersionLessThan('3.2.0')) {
         // removeFile and removeFolder methods should be called here for files and folders to cleanup
         generator.removeFile(`${ANGULAR_DIR}components/form/uib-pager.config.js`);
         generator.removeFile(`${ANGULAR_DIR}components/form/uib-pagination.config.js`);
     }
-    if (generator.isJhipsterVersionLessThan('5.0.0')) {
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/account.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-jwt.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-session.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/csrf.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/principal.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/state-storage.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/auth/user-route-access-service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/language/language.constants.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/language/language.helper.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/login/login-modal.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/login/login.service.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/model/base-entity.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/model/request-util.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/user/account.model.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/user/user.model.ts`);
-        generator.removeFile(`${ANGULAR_DIR}shared/user/user.service.ts`);
-
-        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/shared/user/user.service.spec.ts`);
-    }
 }
 
 /**
- * Removes server files that where generated in previous JHipster versions and therefore
- * need to be removed.
+ * Removes server files that where generated in previous JHipster versions and therefore need to be removed
  *
  * @param {any} generator - reference to generator
  * @param {string} javaDir - Java directory
diff --git a/generators/client/files-react.js b/generators/client/files-react.js
index 8ddb0ac32d..c8bee6d375 100644
--- a/generators/client/files-react.js
+++ b/generators/client/files-react.js
@@ -193,8 +193,7 @@ const files = {
             templates: [
                 'shared/reducers/index.ts',
                 'shared/reducers/action-type.util.ts',
-                'shared/reducers/authentication.ts',
-                'shared/reducers/layout.ts'
+                'shared/reducers/authentication.ts'
             ]
         },
         {
@@ -265,7 +264,7 @@ const files = {
             templates: [
                 { file: 'modules/administration/user-management/index.tsx', method: 'processJsx' },
                 { file: 'modules/administration/user-management/user-management.tsx', method: 'processJsx' },
-                { file: 'modules/administration/user-management/user-management-dialog.tsx', method: 'processJsx' },
+                { file: 'modules/administration/user-management/user-management-update.tsx', method: 'processJsx' },
                 { file: 'modules/administration/user-management/user-management-detail.tsx', method: 'processJsx' },
                 { file: 'modules/administration/user-management/user-management-delete-dialog.tsx', method: 'processJsx' },
                 'modules/administration/user-management/user-management.reducer.ts'
@@ -293,6 +292,7 @@ const files = {
                 'shared/util/url-utils.ts',
                 'shared/util/entity-utils.ts',
                 // components
+                'shared/auth/private-route.tsx',
                 // model
                 'shared/model/user.model.ts'
             ]
@@ -330,14 +330,6 @@ const files = {
     //     'shared/language/_language.constants.js',
     //     'shared/language/_language.helper.js'
     //   ]
-    // },
-    // {
-    //   condition: generator => !generator.skipUserManagement,
-    //   path: REACT_DIR,
-    //   templates: [
-    //     'shared/user/_user.model.js',
-    //     'shared/user/_user.service.js'
-    //   ]
     // }
     ],
     // angularAuthService: [
@@ -386,6 +378,7 @@ const files = {
                 'spec/app/shared/layout/header.spec.tsx',
                 'spec/app/shared/reducers/authentication.spec.ts',
                 'spec/app/shared/util/entity-utils.spec.ts',
+                'spec/app/shared/auth/private-route.spec.tsx',
                 'spec/app/modules/account/register/register.spec.tsx',
                 'spec/app/modules/account/register/register.reducer.spec.ts',
                 'spec/app/modules/account/activate/activate.reducer.spec.ts',
diff --git a/generators/client/index.js b/generators/client/index.js
index aa3625775e..1bf8cbcd08 100644
--- a/generators/client/index.js
+++ b/generators/client/index.js
@@ -105,6 +105,13 @@ module.exports = class extends BaseGenerator {
             defaults: false
         });
 
+        // This adds support for a `--skip-commit-hook` flag
+        this.option('skip-commit-hook', {
+            desc: 'Skip adding husky commit hooks',
+            type: Boolean,
+            defaults: false
+        });
+
         // This adds support for a `--npm` flag
         this.option('npm', {
             desc: 'Use npm instead of yarn',
@@ -249,6 +256,7 @@ module.exports = class extends BaseGenerator {
                 this.config.set('clientFramework', this.clientFramework);
                 this.config.set('useSass', this.useSass);
                 this.config.set('enableTranslation', this.enableTranslation);
+                this.config.set('skipCommitHook', this.skipCommitHook);
                 if (this.enableTranslation && !this.configOptions.skipI18nQuestion) {
                     this.config.set('nativeLanguage', this.nativeLanguage);
                     this.config.set('languages', this.languages);
diff --git a/generators/client/templates/angular/package.json.ejs b/generators/client/templates/angular/package.json.ejs
index 262107d2e4..9523c5830e 100644
--- a/generators/client/templates/angular/package.json.ejs
+++ b/generators/client/templates/angular/package.json.ejs
@@ -77,7 +77,9 @@
     "generator-jhipster": "<%= packagejs.version %>",
     "html-loader": "0.5.5",
     "html-webpack-plugin": "3.0.6",
+    <%_ if(!skipCommitHook) { _%>
     "husky": "0.14.3",
+    <%_ } _%>
     "jasmine-core": "2.7.0",
     <%_ if (protractorTests) { _%>
     "jasmine-reporters": "2.2.1",
@@ -92,7 +94,9 @@
     "karma-remap-istanbul": "0.6.0",
     "karma-sourcemap-loader": "0.3.7",
     "karma-webpack": "2.0.13",
+    <%_ if(!skipCommitHook) { _%>
     "lint-staged": "7.0.0",
+    <%_ } _%>
     <%_ if (enableTranslation) { _%>
     "merge-jsons-webpack-plugin": "1.0.14",
     <%_ } _%>
@@ -141,11 +145,15 @@
   "engines": {
     "node": ">=8.9.0"
   },
+  <%_ if(!skipCommitHook) { _%>
   "lint-staged": {
     "*.ts": ["prettier --write", "git add"]
   },
+  <%_ } _%>
   "scripts": {
+    <%_ if(!skipCommitHook) { _%>
     "precommit": "lint-staged",
+    <%_ } _%>
     "prettier:format":"<%= clientPackageManager %> prettier --write **/*.ts",
     "lint": "tslint --project tsconfig.json -e 'node_modules/**'",
     "lint:fix": "<%= clientPackageManager %> run lint -- --fix",
diff --git a/generators/client/templates/react/package.json.ejs b/generators/client/templates/react/package.json.ejs
index e6410477c6..5d22ffff81 100644
--- a/generators/client/templates/react/package.json.ejs
+++ b/generators/client/templates/react/package.json.ejs
@@ -26,26 +26,25 @@ limitations under the License.
     "node_modules"
   ],
   "dependencies": {
-    "availity-reactstrap-validation": "2.0.0-alpha.1",
+    "availity-reactstrap-validation": "2.0.2",
     "axios": "0.18.0",
     "bootstrap": "4.0.0",
     "loaders.css": "0.1.2",
     "lodash": "4.17.5",
-    "moment": "2.21.0",
-    "react": "16.2.0",
+    "moment": "2.22.0",
+    "react": "16.3.0",
     "react-addons-css-transition-group": "16.0.0-alpha.3",
     "react-addons-transition-group": "16.0.0-alpha.3",
-    "react-dom": "16.2.0",
+    "react-dom": "16.3.0",
     "react-hot-loader": "3.1.1",
     "react-icons": "2.2.7",
-    "react-jhipster": "0.4.9",
+    "react-jhipster": "0.4.11",
     "react-redux": "5.0.7",
     "react-redux-loading-bar": "3.1.2",
     "react-router-dom": "4.2.2",
-    "react-router-modal": "1.3.2",
-    "react-toastify": "3.4.1",
-    "react-transition-group": "2.2.1",
-    "reactstrap": "5.0.0-beta.2",
+    "react-toastify": "3.4.3",
+    "react-transition-group": "2.3.0",
+    "reactstrap": "5.0.0",
     "redux": "3.7.2",
     "redux-devtools": "3.4.1",
     "redux-devtools-dock-monitor": "1.1.3",
@@ -63,35 +62,37 @@ limitations under the License.
   "devDependencies": {
     "@types/chai": "4.1.2",
     "@types/chai-enzyme": "0.6.4",
-    "@types/lodash": "4.14.104",
-    "@types/mocha": "2.2.48",
-    "@types/node": "9.4.7",
+    "@types/lodash": "4.14.106",
+    "@types/mocha": "5.0.0",
+    "@types/node": "9.6.1",
     "@types/react": "16.1.0",
     "@types/react-dom": "16.0.4",
-    "@types/react-router-dom": "4.2.4",
+    "@types/react-router-dom": "4.2.6",
     "@types/redux": "3.6.31",
     <%_ if (protractorTests) { _%>
     "@types/selenium-webdriver": "3.0.7",
     <%_ } _%>
     "@types/webpack-env": "1.13.5",
     "browser-sync": "2.23.6",
-    "browser-sync-webpack-plugin": "2.0.1",
+    "browser-sync-webpack-plugin": "2.2.2",
     "cache-loader": "1.2.2",
     "chai": "4.1.2",
     "chai-enzyme": "1.0.0-beta.0",
     "copy-webpack-plugin": "4.5.1",
-    "core-js": "2.5.3",
+    "core-js": "2.5.4",
     "cross-env": "5.1.4",
-    "css-loader": "0.28.10",
+    "css-loader": "0.28.11",
     "enzyme": "3.3.0",
     "enzyme-adapter-react-16": "1.1.1",
     "extract-text-webpack-plugin": "4.0.0-beta.0",
     "file-loader": "1.1.11",
     "fork-ts-checker-webpack-plugin": "0.4.1",
-    "html-webpack-plugin": "3.0.6",
-    "http-proxy-middleware": "0.17.4",
+    "html-webpack-plugin": "3.1.0",
+    "http-proxy-middleware": "0.18.0",
+    <%_ if(!skipCommitHook) { _%>
     "husky": "0.14.3",
-    "image-webpack-loader": "4.1.0",
+    <%_ } _%>
+    "image-webpack-loader": "4.2.0",
     <%_ if (protractorTests) { _%>
     "jasmine-reporters": "2.2.1",
     <%_ } _%>
@@ -106,24 +107,26 @@ limitations under the License.
     "karma-notify-reporter": "1.0.1",
     "karma-remap-istanbul": "0.6.0",
     "karma-sourcemap-loader": "0.3.7",
-    "karma-webpack": "2.0.13",
-    "lint-staged": "7.0.0",
+    "karma-webpack": "3.0.0",
+    <%_ if(!skipCommitHook) { _%>
+    "lint-staged": "7.0.1",
+    <%_ } _%>
     <%_ if (enableTranslation) { _%>
     "merge-jsons-webpack-plugin": "1.0.14",
     <%_ } _%>
-    "mocha": "5.0.4",
+    "mocha": "5.0.5",
     "prettier": "1.11.1",
-    "puppeteer": "1.1.1",
+    "puppeteer": "1.2.0",
     <%_ if (protractorTests) { _%>
     "protractor": "5.1.2",
     "protractor-jasmine2-screenshot-reporter": "0.4.1",
     <%_ } _%>
     "react-addons-test-utils": "15.6.2",
     "react-infinite-scroller": "1.1.3",
-    "react-test-renderer": "16.2.0",
+    "react-test-renderer": "16.3.0",
     "redux-mock-store": "1.5.1",
     "rimraf": "2.6.2",
-    "sinon": "4.4.2",
+    "sinon": "4.5.0",
     "source-map-loader": "0.2.3",
     "sourcemap-istanbul-instrumenter-loader": "0.2.0",
     "stripcomment-loader": "0.1.0",
@@ -139,24 +142,24 @@ limitations under the License.
     "<%= module.name %>": "<%= module.version %>",
     <%_ }); _%>
     "to-string-loader": "1.1.5",
-    "ts-loader": "4.0.1",
+    "ts-loader": "4.1.0",
     <%_ if (protractorTests) { _%>
     "ts-node": "3.3.0",
     <%_ } _%>
     "tslint": "5.9.1",
-    "tslint-config-prettier": "1.9.0",
+    "tslint-config-prettier": "1.10.0",
     "tslint-eslint-rules": "5.1.0",
     "tslint-loader": "3.6.0",
     "tslint-microsoft-contrib": "5.0.3",
     "tslint-react": "3.5.1",
-    "typescript": "2.7.2",
-    "uglifyjs-webpack-plugin": "1.2.3",
-    "webpack": "4.1.1",
-    "webpack-cli": "2.0.11",
+    "typescript": "2.8.1",
+    "uglifyjs-webpack-plugin": "1.2.4",
+    "webpack": "4.4.1",
+    "webpack-cli": "2.0.13",
     "webpack-dev-server": "3.1.1",
     "webpack-merge": "4.1.2",
     "webpack-notifier": "1.6.0",
-    "workbox-webpack-plugin": "3.0.0-beta.1",
+    "workbox-webpack-plugin": "3.0.1",
     "write-file-webpack-plugin": "4.2.0"<% if (buildTool === 'maven') { %>,
     "xml2js": "0.4.19"
     <%_ } _%>
@@ -164,11 +167,15 @@ limitations under the License.
   "engines": {
     "node": ">=8.9.0"
   },
+  <%_ if(!skipCommitHook) { _%>
   "lint-staged": {
     "*.{ts,tsx}": ["prettier --write", "git add"]
   },
+  <%_ } _%>
   "scripts": {
+    <%_ if(!skipCommitHook) { _%>
     "precommit": "lint-staged",
+    <%_ } _%>
     "prettier:format": "<%= clientPackageManager %> prettier --write **/*.{ts,tsx}",
     "lint": "tslint --project tsconfig.json -e 'node_modules/**'",
     "lint:fix": "<%= clientPackageManager %> run lint -- --fix",
diff --git a/generators/client/templates/react/src/main/webapp/app/app.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/app.tsx.ejs
index e06559dfde..75c0e7a255 100644
--- a/generators/client/templates/react/src/main/webapp/app/app.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/app.tsx.ejs
@@ -22,30 +22,26 @@ import * as React from 'react';
 import { connect } from 'react-redux';
 import { Card } from 'reactstrap';
 import { HashRouter as Router } from 'react-router-dom';
-import { ModalContainer } from 'react-router-modal';
 import { ToastContainer, toast } from 'react-toastify';
 
-import { getSession, logout } from './shared/reducers/authentication';
+import { getSession } from 'app/shared/reducers/authentication';
 <%_ if (enableTranslation) { _%>
-import { setLocale } from './shared/reducers/locale';
+import { setLocale } from 'app/shared/reducers/locale';
 <%_ } _%>
-import Header from './shared/layout/header/header';
-import Footer from './shared/layout/footer/footer';
-import AppRoutes from './routes';
+import Header from 'app/shared/layout/header/header';
+import Footer from 'app/shared/layout/footer/footer';
+import { hasAnyAuthority } from 'app/shared/auth/private-route';
+import { AUTHORITIES } from 'app/config/constants';
+import AppRoutes from 'app/routes';
 
 export interface IAppProps {
-  location: any;
-  isAuthenticated?: boolean;
+  isAuthenticated: boolean;
+  isAdmin: boolean;
   <%_ if (enableTranslation) { _%>
   currentLocale: string;
-  <%_ } _%>
-  getSession: Function;
-  <%_ if (enableTranslation) { _%>
   setLocale: Function;
   <%_ } _%>
-  logout: Function;
-  getSystemProperties: Function;
-  routes: any;
+  getSession: Function;
 }
 
 export class App extends React.Component<IAppProps> {
@@ -53,10 +49,6 @@ export class App extends React.Component<IAppProps> {
     this.props.getSession();
   }
 
-  handleLogout = () => {
-    this.props.logout();
-  }
-
   render() {
     const paddingTop = '60px';
     return (
@@ -65,6 +57,7 @@ export class App extends React.Component<IAppProps> {
           <ToastContainer position={ toast.POSITION.BOTTOM_CENTER } />
           <Header
             isAuthenticated={this.props.isAuthenticated}
+            isAdmin={this.props.isAdmin}
           <%_ if (enableTranslation) { _%>
             currentLocale={this.props.currentLocale}
             onLocaleChange={this.props.setLocale}
@@ -76,21 +69,20 @@ export class App extends React.Component<IAppProps> {
             </Card>
             <Footer/>
           </div>
-          <ModalContainer />
         </div>
       </Router>
     );
   }
 }
 
-const mapStateToProps = storeState => ({
-  isAuthenticated: storeState.authentication.isAuthenticated,
+const mapStateToProps = ({ authentication<% if (enableTranslation) { %>, locale<% } %> }) => ({
   <%_ if (enableTranslation) { _%>
-  currentLocale: storeState.locale.currentLocale,
+  currentLocale: locale.currentLocale,
   <%_ } _%>
-  embedded: storeState.layout.embedded
+  isAuthenticated: authentication.isAuthenticated,
+  isAdmin: hasAnyAuthority(authentication.account.authorities, [AUTHORITIES.ADMIN])
 });
 
-const mapDispatchToProps = { getSession, <% if (enableTranslation) { %>setLocale, <% } %>logout };
+const mapDispatchToProps = { <% if (enableTranslation) { %>setLocale, <% } %>getSession };
 
 export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/generators/client/templates/react/src/main/webapp/app/config/constants.ts.ejs b/generators/client/templates/react/src/main/webapp/app/config/constants.ts.ejs
index e0e3250f0b..e0f3fdc7fb 100644
--- a/generators/client/templates/react/src/main/webapp/app/config/constants.ts.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/config/constants.ts.ejs
@@ -25,6 +25,11 @@ export default config;
 
 export const SERVER_API_URL = '';
 
+export const AUTHORITIES = {
+  ADMIN: 'ROLE_ADMIN',
+  USER: 'ROLE_USER'
+};
+
 export const messages = {
   DATA_ERROR_ALERT: 'Internal Error'
 };
diff --git a/generators/client/templates/react/src/main/webapp/app/modules/account/index.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/modules/account/index.tsx.ejs
index 43a6530348..895f778ab8 100644
--- a/generators/client/templates/react/src/main/webapp/app/modules/account/index.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/modules/account/index.tsx.ejs
@@ -27,8 +27,8 @@ import Sessions from './sessions/sessions';
 
 const Routes = ({ match }) => (
   <div>
-    <Route path={`${match.url}/settings`} component={Settings}/>
-    <Route path={`${match.url}/password`} component={Password}/>
+    <Route path={`${match.url}/settings`} component={Settings} />
+    <Route path={`${match.url}/password`} component={Password} />
     <%_ if (authenticationType === 'session') { _%>
     <Route path={`${match.url}/sessions`} component={Sessions} />
     <%_ } _%>
diff --git a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/index.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/index.tsx.ejs
index b3fa4c688c..471400ab23 100644
--- a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/index.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/index.tsx.ejs
@@ -18,44 +18,22 @@
 -%>
 import * as React from 'react';
 import { Route, Switch } from 'react-router-dom';
-import { ModalRoute } from 'react-router-modal';
 
 import UserManagement from './user-management';
 import UserManagementDetail from './user-management-detail';
-import UserManagementDialog from './user-management-dialog';
+import UserManagementUpdate from './user-management-update';
 import UserManagementDeleteDialog from './user-management-delete-dialog';
 
-export interface IRoutesProps {
-  match: any;
-  location: any;
-}
-
-export class Routes extends React.Component<IRoutesProps> {
-  previousLocation = this.props.location;
-
-  componentWillUpdate(nextProps) {
-    const { location } = this.props;
-    if (nextProps.history.action !== "POP" && (!location.state || !location.state.modal)) {
-      this.previousLocation = this.props.location;
-    }
-  }
-  
-  render() {
-    const { match, location } = this.props;
-    const isModal = !!(location.state && location.state.modal && this.previousLocation !== location);
-
-    return (
-      <div>
-        <Switch location={isModal ? this.previousLocation: location}>
-          <Route exact path={match.url} component={UserManagement} />
-          <Route exact parentPath={match.url} path={`${match.url}/new`} component={UserManagementDialog} />
-          <Route exact parentPath={match.url} path={`${match.url}/:login/edit`} component={UserManagementDialog} />
-          <Route exact path={`${match.url}/:login`} component={UserManagementDetail} />
-        </Switch>
-        {isModal ? <Route exact parentPath={match.url} path={`${match.url}/:login/delete`} component={UserManagementDeleteDialog} /> : null}
-      </div>
-    )
-  }
-}
+const Routes = ({ match }) => (
+  <>
+    <Switch>
+      <Route exact path={`${match.url}/new`} component={UserManagementUpdate} />
+      <Route exact path={`${match.url}/:login/edit`} component={UserManagementUpdate} />
+      <Route exact path={`${match.url}/:login`} component={UserManagementDetail} />
+      <Route path={match.url} component={UserManagement} />
+    </Switch>
+    <Route path={`${match.url}/:login/delete`} component={UserManagementDeleteDialog} />
+  </>
+);
 
 export default Routes;
diff --git a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-dialog.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx.ejs
similarity index 97%
rename from generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-dialog.tsx.ejs
rename to generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx.ejs
index c3926d93f1..a9cdcc5b79 100644
--- a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-dialog.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx.ejs
@@ -29,7 +29,7 @@ import { locales } from 'app/config/translation';
 <%_ } _%>
 import { getUser, getRoles, updateUser, createUser, reset } from './user-management.reducer';
 
-export interface IUserManagementDialogProps {
+export interface IUserManagementUpdateProps {
   getUser: ICrudGetAction;
   getRoles: ICrudGetAllAction;
   updateUser: ICrudPutAction;
@@ -43,13 +43,13 @@ export interface IUserManagementDialogProps {
   history: any;
 }
 
-export interface IUserManagementDialogState {
+export interface IUserManagementUpdateState {
   isNew: boolean;
 }
 
-export class UserManagementDialog extends React.Component<IUserManagementDialogProps, IUserManagementDialogState> {
+export class UserManagementUpdate extends React.Component<IUserManagementUpdateProps, IUserManagementUpdateState> {
 
-  state: IUserManagementDialogState = {
+  state: IUserManagementUpdateState = {
     isNew: !this.props.match.params || !this.props.match.params.login
   };
 
@@ -268,4 +268,4 @@ const mapStateToProps = storeState => ({
 
 const mapDispatchToProps = { getUser, getRoles, updateUser, createUser, reset };
 
-export default connect(mapStateToProps, mapDispatchToProps)(UserManagementDialog);
+export default connect(mapStateToProps, mapDispatchToProps)(UserManagementUpdate);
diff --git a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs
index 60ab137d02..6aa7502ff0 100644
--- a/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/modules/administration/user-management/user-management.tsx.ejs
@@ -174,7 +174,7 @@ export class UserManagement extends React.Component<IUserManagementProps, IPagin
                         <FaPencil/> <span className="d-none d-md-inline"><Translate contentKey="entity.action.edit">Edit</Translate></span>
                       </Button>
                       <Button
-                        tag={Link} to={{pathname: `${match.url}/${user.login}/delete`, state: { modal: true }}}
+                        tag={Link} to={`${match.url}/${user.login}/delete`}
                         color="danger" size="sm" disabled={account.login === user.login}
                       >
                         <FaTrash/> <span className="d-none d-md-inline"><Translate contentKey="entity.action.delete">Delete</Translate></span>
diff --git a/generators/client/templates/react/src/main/webapp/app/routes.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/routes.tsx.ejs
index 0ef664ec8e..5c11c37272 100644
--- a/generators/client/templates/react/src/main/webapp/app/routes.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/routes.tsx.ejs
@@ -17,36 +17,39 @@
  limitations under the License.
 -%>
 import * as React from 'react';
-import { Route } from 'react-router-dom';
-import { PrivateRoute } from 'react-jhipster';
+import { Route, Switch } from 'react-router-dom';
 
 <%_ if (authenticationType !== 'oauth2') { _%>
-import Login from './modules/login/login';
+import Login from 'app/modules/login/login';
 <%_ } _%>
-import Logout from './modules/login/logout';
-import Register from './modules/account/register/register';
-import Home from './modules/home/home';
-import Admin from './modules/administration';
-import Account from './modules/account';
-import Activate from './modules/account/activate/activate';
-import PasswordResetInit from './modules/account/password-reset/init/password-reset-init';
-import PasswordResetFinish from './modules/account/password-reset/finish/password-reset-finish';
-import Entities from './entities';
+import Logout from 'app/modules/login/logout';
+import Register from 'app/modules/account/register/register';
+import Home from 'app/modules/home/home';
+import Admin from 'app/modules/administration';
+import Account from 'app/modules/account';
+import Activate from 'app/modules/account/activate/activate';
+import PasswordResetInit from 'app/modules/account/password-reset/init/password-reset-init';
+import PasswordResetFinish from 'app/modules/account/password-reset/finish/password-reset-finish';
+import Entities from 'app/entities';
+import PrivateRoute from 'app/shared/auth/private-route';
+import { AUTHORITIES } from 'app/config/constants';
 
 const Routes = () => (
   <div className="view-routes">
-    <Route exact path="/" component={Home}/>
     <%_ if (authenticationType !== 'oauth2') { _%>
     <Route path="/login" component={Login} />
     <%_ } _%>
-    <Route path="/logout" component={Logout} />
-    <Route path="/register" component={Register} />
-    <Route path="/activate/:key?" component={Activate} />
-    <Route path="/reset/request" component={PasswordResetInit} />
-    <Route path="/reset/finish/:key?" component={PasswordResetFinish} />
-    <PrivateRoute path="/admin" component={Admin} />
-    <PrivateRoute path="/account" component={Account} />
-    <Route path="**" component={Entities} />
+    <Switch>
+      <Route path="/logout" component={Logout} />
+      <Route path="/register" component={Register} />
+      <Route path="/activate/:key?" component={Activate} />
+      <Route path="/reset/request" component={PasswordResetInit} />
+      <Route path="/reset/finish/:key?" component={PasswordResetFinish} />
+      <PrivateRoute path="/admin" component={Admin} hasAnyAuthorities={[AUTHORITIES.ADMIN]}/>
+      <PrivateRoute path="/account" component={Account} hasAnyAuthorities={[AUTHORITIES.USER]}/>
+      <PrivateRoute path="/entity" component={Entities} hasAnyAuthorities={[AUTHORITIES.USER]}/>
+      <Route path="/" component={Home}/>
+    </Switch>
   </div>
 );
 
diff --git a/generators/client/templates/react/src/main/webapp/app/shared/auth/private-route.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/shared/auth/private-route.tsx.ejs
new file mode 100644
index 0000000000..2a42a04521
--- /dev/null
+++ b/generators/client/templates/react/src/main/webapp/app/shared/auth/private-route.tsx.ejs
@@ -0,0 +1,72 @@
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Route, Redirect } from 'react-router-dom';
+import { Translate } from 'react-jhipster';
+
+export interface IPrivateRouteProps {
+  component: any;
+  isAuthenticated: boolean;
+  isAuthorized: boolean;
+  hasAnyAuthorities?: string[];
+  [key: string]: any;
+}
+
+export const PrivateRouteComponent = ({
+  component: Component,
+  isAuthenticated,
+  isAuthorized,
+  hasAnyAuthorities = [],
+  ...rest
+}: IPrivateRouteProps) => {
+  const checkAuthorities = props =>
+    isAuthorized ? (
+      <Component {...props} />
+    ) : (
+      <div className="insufficient-authority">
+        <div className="alert alert-danger">
+          <Translate contentKey="error.http.403">You are not authorized to access this page.</Translate>
+        </div>
+      </div>
+    );
+
+  const renderRedirect = props =>
+    isAuthenticated ? (
+      checkAuthorities(props)
+    ) : (
+      <Redirect
+        to={{
+          pathname: '/login',
+          search: props.location.search,
+          state: { from: props.location }
+        }}
+      />
+    );
+
+  if (!Component) throw new Error(`A component needs to be specified for private route for path ${(rest as any).path}`);
+
+  return <Route {...rest} render={renderRedirect} />;
+};
+
+export const hasAnyAuthority = (authorities: string[], hasAnyAuthorities: string[]) => {
+  if (authorities && authorities.length !== 0) {
+    if (hasAnyAuthorities.length === 0) {
+      return true;
+    }
+    return hasAnyAuthorities.some(auth => authorities.includes(auth));
+  }
+  return false;
+};
+
+const mapStoreToProps = ({ authentication: { isAuthenticated, account } }, { hasAnyAuthorities = [] }) => ({
+  isAuthenticated,
+  isAuthorized: hasAnyAuthority(account.authorities, hasAnyAuthorities)
+});
+
+/**
+ * A route wrapped in an authentication check so that routing happens only when you are authenticated.
+ * Accepts same props as React router Route.
+ * The route also checks for authorization if hasAnyAuthorities is specified.
+ */
+export const PrivateRoute = connect(mapStoreToProps, null, null, { pure: false })(PrivateRouteComponent);
+
+export default PrivateRoute;
diff --git a/generators/client/templates/react/src/main/webapp/app/shared/layout/header/header.tsx.ejs b/generators/client/templates/react/src/main/webapp/app/shared/layout/header/header.tsx.ejs
index 087629ce53..f845a10562 100644
--- a/generators/client/templates/react/src/main/webapp/app/shared/layout/header/header.tsx.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/shared/layout/header/header.tsx.ejs
@@ -53,6 +53,7 @@ import appConfig from 'app/config/constants';
 
 export interface IHeaderProps {
   isAuthenticated: boolean;
+  isAdmin: boolean;
 <%_ if (enableTranslation) { _%>
   currentLocale: string;
   onLocaleChange: Function;
@@ -93,7 +94,7 @@ export class Header extends React.Component<IHeaderProps, IHeaderState> {
   }
 
   render() {
-    const {<%_ if (enableTranslation) { _%>currentLocale,<%_ } _%> isAuthenticated } = this.props;
+    const {<%_ if (enableTranslation) { _%>currentLocale,<%_ } _%> isAuthenticated, isAdmin } = this.props;
     const entityMenuItems = [
       /* jhipster-needle-add-entity-to-menu - - JHipster will add entities to the menu here */
       <span key="dummy-placeholder"/> /* workaround to avoid error when there are no entities */
@@ -146,6 +147,27 @@ export class Header extends React.Component<IHeaderProps, IHeaderState> {
       <%_ } _%>
     }
 
+    const entitiesMenu = (
+      <UncontrolledDropdown nav inNavbar key="entities">
+        <DropdownToggle nav caret className="d-flex align-items-center">
+          <FaThList />
+          <span>Entities</span>
+        </DropdownToggle>
+        <DropdownMenu right>{entityMenuItems}</DropdownMenu>
+      </UncontrolledDropdown>
+    );
+    const adminMenu = (
+      <UncontrolledDropdown nav inNavbar key="admin">
+        <DropdownToggle nav caret className="d-flex align-items-center">
+          <FaUserPlus />
+          <span>Administration</span>
+        </DropdownToggle>
+        <DropdownMenu right style={{ width: '130%' }}>
+          {adminMenuItems}
+        </DropdownMenu>
+      </UncontrolledDropdown>
+    );
+
     return (
       <div id="app-header">
         {this.renderDevRibbon()}
@@ -165,26 +187,7 @@ export class Header extends React.Component<IHeaderProps, IHeaderState> {
                   <span>Home</span>
                 </NavLink>
               </NavItem>
-              {isAuthenticated ? [
-                <UncontrolledDropdown nav inNavbar key="entities">
-                  <DropdownToggle nav caret className="d-flex align-items-center">
-                    <FaThList />
-                    <span>Entities</span>
-                  </DropdownToggle>
-                  <DropdownMenu right>
-                    {entityMenuItems}
-                  </DropdownMenu>
-                </UncontrolledDropdown>,
-                <UncontrolledDropdown nav inNavbar key="admin">
-                  <DropdownToggle nav caret className="d-flex align-items-center">
-                    <FaUserPlus />
-                    <span>Administration</span>
-                  </DropdownToggle>
-                  <DropdownMenu right style={{ width: '130%' }}>
-                    {adminMenuItems}
-                  </DropdownMenu>
-                </UncontrolledDropdown>
-              ] : null}
+              {isAuthenticated ? (isAdmin ? [ entitiesMenu, adminMenu ] : entitiesMenu) : null}
             <%_ if (enableTranslation) { _%>
               { locales.length > 1 ?
                 <UncontrolledDropdown nav inNavbar>
diff --git a/generators/client/templates/react/src/main/webapp/app/shared/reducers/index.ts.ejs b/generators/client/templates/react/src/main/webapp/app/shared/reducers/index.ts.ejs
index b6746573a4..75dd4d6c08 100644
--- a/generators/client/templates/react/src/main/webapp/app/shared/reducers/index.ts.ejs
+++ b/generators/client/templates/react/src/main/webapp/app/shared/reducers/index.ts.ejs
@@ -22,7 +22,6 @@ import { loadingBarReducer as loadingBar } from 'react-redux-loading-bar';
 <%_ if (enableTranslation) { _%>
 import locale from './locale';
 <%_ } _%>
-import layout from './layout';
 import authentication from './authentication';
 
 import administration from 'app/modules/administration/administration.reducer';
@@ -46,7 +45,6 @@ export default combineReducers({
   <%_ if (enableTranslation) { _%>
   locale,
   <%_ } _%>
-  layout,
   administration,
   <%_ if (!skipUserManagement) { _%>
   userManagement,
diff --git a/generators/client/templates/react/src/main/webapp/app/shared/reducers/layout.ts.ejs b/generators/client/templates/react/src/main/webapp/app/shared/reducers/layout.ts.ejs
deleted file mode 100644
index a560cae355..0000000000
--- a/generators/client/templates/react/src/main/webapp/app/shared/reducers/layout.ts.ejs
+++ /dev/null
@@ -1,41 +0,0 @@
-<%#
- Copyright 2013-2018 the original author or authors from the JHipster project.
-
- This file is part of the JHipster project, see https://www.jhipster.tech/
- for more information.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--%>
-export const ACTION_TYPES = {
-  EMBEDDED_MODE: 'layout/EMBEDDED_MODE'
-};
-
-const initialState = {
-  embedded: false
-};
-
-// Reducer
-
-export default (state = initialState, action) => {
-  switch (action.type) {
-    case ACTION_TYPES.EMBEDDED_MODE:
-      return {
-        ...initialState,
-        embedded: action.embedded
-      };
-    default:
-      return state;
-  }
-};
-
-export const setEmbeddedMode = embedded => ({ type: ACTION_TYPES.EMBEDDED_MODE, embedded });
diff --git a/generators/entity-client/files.js b/generators/entity-client/files.js
index c5246276e6..17dd2e30a1 100644
--- a/generators/entity-client/files.js
+++ b/generators/entity-client/files.js
@@ -160,8 +160,8 @@ const reactFiles = {
                     renameTo: generator => `entities/${generator.entityFolderName}/${generator.entityFileName}-detail.tsx`
                 },
                 {
-                    file: 'entities/entity-dialog.tsx',
-                    renameTo: generator => `entities/${generator.entityFolderName}/${generator.entityFileName}-dialog.tsx`
+                    file: 'entities/entity-update.tsx',
+                    renameTo: generator => `entities/${generator.entityFolderName}/${generator.entityFileName}-update.tsx`
                 },
                 {
                     file: 'entities/entity.tsx',
@@ -211,14 +211,18 @@ function writeFiles() {
                 // write client side files for angular 2.x +
                 this.writeFilesToDisk(angularFiles, this, false, CLIENT_NG2_TEMPLATES_DIR);
                 this.addEntityToModule(this.entityInstance, this.entityClass, this.entityAngularName, this.entityFolderName, this.entityFileName, this.enableTranslation, this.clientFramework, this.microserviceName);
+
             } else {
                 // write client side files for react
                 this.writeFilesToDisk(reactFiles, this, false, CLIENT_REACT_TEMPLATES_DIR);
                 this.addEntityToModule(this.entityInstance, this.entityClass, this.entityAngularName, this.entityFolderName, this.entityFileName, this.enableTranslation, this.clientFramework);
+
             }
+
             if (this.applicationType === 'gateway' && !_.isUndefined(this.microserviceName)) {
                 this.addEntityToWebpack(this.microserviceName, this.clientFramework);
             }
+
             this.addEntityToMenu(this.entityStateName, this.enableTranslation, this.clientFramework, this.entityTranslationKeyMenu);
         }
     };
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.html.ejs
index 9da511f817..dfb356bb92 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.html.ejs
@@ -16,7 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_ const keyPrefix = angularAppName + '.' + entityTranslationKey; _%>
 <form name="deleteForm" (ngSubmit)="confirmDelete(<%= entityInstance %>.id)">
     <div class="modal-header">
         <h4 class="modal-title" jhiTranslate="entity.delete.title">Confirm delete operation</h4>
@@ -25,7 +24,7 @@
     </div>
     <div class="modal-body">
         <<%= jhiPrefixDashed %>-alert-error></<%= jhiPrefixDashed %>-alert-error>
-        <p jhiTranslate="<%= keyPrefix %>.delete.question" translateValues="{id: '{{<%= entityInstance %>.id}}'}">Are you sure you want to delete this <%= entityClassHumanized %>?</p>
+        <p jhiTranslate="<%= i18nKeyPrefix %>.delete.question" translateValues="{id: '{{<%= entityInstance %>.id}}'}">Are you sure you want to delete this <%= entityClassHumanized %>?</p>
     </div>
     <div class="modal-footer">
         <button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="clear()">
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.ts.ejs
index a9235dcad7..17779b54f1 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-delete-dialog.component.ts.ejs
@@ -16,14 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
 import { Component, OnInit, OnDestroy } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
index fadffec7fe..afe16276bc 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.html.ejs
@@ -16,9 +16,8 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<% const keyPrefix = angularAppName + '.' + entityTranslationKey; %>
 <div *ngIf="<%= entityInstance %>">
-    <h2><span jhiTranslate="<%= keyPrefix %>.detail.title"><%= entityClassHumanized %></span> {{<%= entityInstance %>.id}}</h2>
+    <h2><span jhiTranslate="<%= i18nKeyPrefix %>.detail.title"><%= entityClassHumanized %></span> {{<%= entityInstance %>.id}}</h2>
     <hr>
     <<%= jhiPrefixDashed %>-alert-error></<%= jhiPrefixDashed %>-alert-error>
     <dl class="row-md jh-entity-details">
@@ -26,7 +25,7 @@
         const fieldName = fields[idx].fieldName;
         const fieldType = fields[idx].fieldType;
         const fieldTypeBlobContent = fields[idx].fieldTypeBlobContent; _%>
-        <dt><span jhiTranslate="<%= keyPrefix %>.<%= fieldName %>"<% if (fields[idx].javadoc) { if (enableTranslation) { %> [ngbTooltip]="'<%= keyPrefix %>.help.<%= fieldName %>' | translate"<% } else { %> ngbTooltip="<%= fields[idx].javadoc %>"<% } } %>><%= fields[idx].fieldNameHumanized %></span></dt>
+        <dt><span jhiTranslate="<%= i18nKeyPrefix %>.<%= fieldName %>"<% if (fields[idx].javadoc) { if (enableTranslation) { %> [ngbTooltip]="'<%= i18nKeyPrefix %>.help.<%= fieldName %>' | translate"<% } else { %> ngbTooltip="<%= fields[idx].javadoc %>"<% } } %>><%= fields[idx].fieldNameHumanized %></span></dt>
         <dd>
             <%_ if (fields[idx].fieldIsEnum) { _%>
             <span jhiTranslate="{{'<%= angularAppName %>.<%= fieldType %>.' + <%= entityInstance %>.<%= fieldName %>}}">{{<%= entityInstance %>.<%= fieldName %>}}</span>
@@ -61,7 +60,7 @@
         if (relationshipType === 'many-to-one'
         || (relationshipType === 'one-to-one' && ownerSide === true)
         || (relationshipType === 'many-to-many' && ownerSide === true)) { _%>
-        <dt><span jhiTranslate="<%= keyPrefix %>.<%= relationshipName %>"><%= relationshipNameHumanized %></span></dt>
+        <dt><span jhiTranslate="<%= i18nKeyPrefix %>.<%= relationshipName %>"><%= relationshipNameHumanized %></span></dt>
         <dd>
             <%_ if (otherEntityName === 'user') { _%>
             <%_ if (relationshipType === 'many-to-many') { _%>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.ts.ejs
index 71d3d612f3..dbcac608d4 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-detail.component.ts.ejs
@@ -16,14 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
 import { Component, OnInit, OnDestroy } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { HttpResponse } from '@angular/common/http';
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
index 74079c05f4..f3e8459ffb 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.html.ejs
@@ -16,13 +16,9 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.';
-_%>
 <form name="editForm" role="form" novalidate (ngSubmit)="save()" #editForm="ngForm">
-
     <div class="modal-header">
-        <h4 class="modal-title" id="my<%= entityClass %>Label" jhiTranslate="<%= keyPrefix %>home.createOrEditLabel">Create or edit a <%= entityClassHumanized %></h4>
+        <h4 class="modal-title" id="my<%= entityClass %>Label" jhiTranslate="<%= i18nKeyPrefix %>.home.createOrEditLabel">Create or edit a <%= entityClassHumanized %></h4>
         <button type="button" class="close" data-dismiss="modal" aria-hidden="true"
                 (click)="clear()">&times;</button>
     </div>
@@ -41,7 +37,7 @@ _%>
             const fieldTypeBlobContent = fields[idx].fieldTypeBlobContent;
             let fieldInputType = 'text';
             let ngModelOption = '';
-            const translationKey = keyPrefix + fieldName;
+            const translationKey = `${i18nKeyPrefix}.${fieldName}`;
             if (['Integer', 'Long', 'Float', 'Double', 'BigDecimal'].includes(fieldType)) {
                 fieldInputType = 'number';
             } else if (fieldType === 'LocalDate') {
@@ -55,7 +51,7 @@ _%>
             }
         _%>
         <div class="form-group">
-            <label class="form-control-label" jhiTranslate="<%= translationKey %>" for="field_<%= fieldName %>"<% if (fields[idx].javadoc) { if (enableTranslation) { %> [ngbTooltip]="'<%= keyPrefix %>help.<%= fieldName %>' | translate"<% } else { %> ngbTooltip="<%= fields[idx].javadoc %>"<% } } %>><%= fieldNameHumanized %></label>
+            <label class="form-control-label" jhiTranslate="<%= translationKey %>" for="field_<%= fieldName %>"<% if (fields[idx].javadoc) { if (enableTranslation) { %> [ngbTooltip]="'<%= i18nKeyPrefix %>.help.<%= fieldName %>' | translate"<% } else { %> ngbTooltip="<%= fields[idx].javadoc %>"<% } } %>><%= fieldNameHumanized %></label>
             <%_ if (fields[idx].fieldIsEnum) { _%>
             <select class="form-control" name="<%= fieldName %>" [(ngModel)]="<%= entityInstance %>.<%= fieldName %>" id="field_<%= fieldName %>" <% if (fields[idx].fieldValidate === true && fields[idx].fieldValidateRules.includes('required')) { %> required<% } %>>
             <%_ const enumPrefix = angularAppName + '.'+ fieldType;
@@ -195,7 +191,7 @@ _%>
         const otherEntityField = relationships[idx].otherEntityField;
         const otherEntityFieldCapitalized = relationships[idx].otherEntityFieldCapitalized;
         const relationshipRequired = relationships[idx].relationshipRequired;
-        const translationKey = keyPrefix + relationshipName; _%>
+        const translationKey = `${i18nKeyPrefix}.${relationshipName}`; _%>
         <%_ if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide === true && otherEntityName === 'user')) { _%>
         <div class="form-group">
             <label class="form-control-label" jhiTranslate="<%= translationKey %>" for="field_<%= relationshipName %>"><%= relationshipNameHumanized %></label>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
index 21b831faf3..6a98dcbd4d 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management-dialog.component.ts.ejs
@@ -17,12 +17,6 @@
  limitations under the License.
 -%>
 <%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
 const query = generateEntityQueries(relationships, entityInstance, dto);
 const queries = query.queries;
 const variables = query.variables;
@@ -60,7 +54,7 @@ _%>
 import { I<%= uniqueRel.otherEntityAngularName %>, <%= uniqueRel.otherEntityAngularName%>Service } from 'app/core';
 <%_         } else { _%>
 import { I<%= uniqueRel.otherEntityAngularName %> } from 'app/shared/model/<%= uniqueRel.otherEntityModelName %>.model';
-import { <%= uniqueRel.otherEntityAngularName%>Service } from '../<%= uniqueRel.otherEntityModulePath %>';
+import { <%= uniqueRel.otherEntityAngularName%>Service } from 'app/entities/<%= uniqueRel.otherEntityPath %>';
 <%_         }
         }
     }
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.component.html.ejs
index fd8daabfab..9cc770ca59 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.component.html.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.component.html.ejs
@@ -17,12 +17,11 @@
  limitations under the License.
 -%>
 <div>
-    <%_ const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.'; _%>
     <h2>
-        <span jhiTranslate="<%= keyPrefix %>home.title"><%= entityClassPluralHumanized %></span>
+        <span jhiTranslate="<%= i18nKeyPrefix %>.home.title"><%= entityClassPluralHumanized %></span>
         <button class="btn btn-primary float-right jh-create-entity create-<%= entityUrl %>" [routerLink]="['/', { outlets: { popup: ['<%= entityUrl %>-new'] } }]">
             <span class="fa fa-plus"></span>
-            <span <% if (searchEngine === 'elasticsearch') { %>class="hidden-sm-down" <% } %> jhiTranslate="<%= keyPrefix %>home.createLabel">
+            <span <% if (searchEngine === 'elasticsearch') { %>class="hidden-sm-down" <% } %> jhiTranslate="<%= i18nKeyPrefix %>.home.createLabel">
             Create new <%= entityClassHumanized %>
             </span>
         </button>
@@ -33,7 +32,7 @@
         <div class="col-sm-12">
             <form name="searchForm" class="form-inline">
                 <div class="input-group w-100 mt-3">
-                    <input type="text" class="form-control" [(ngModel)]="currentSearch" id="currentSearch" name="currentSearch" placeholder="<% if (enableTranslation) { %>{{ '<%= keyPrefix %>home.search' | translate }}<% } else { %>Query<% } %>">
+                    <input type="text" class="form-control" [(ngModel)]="currentSearch" id="currentSearch" name="currentSearch" placeholder="<% if (enableTranslation) { %>{{ '<%= i18nKeyPrefix %>.home.search' | translate }}<% } else { %>Query<% } %>">
                     <button class="input-group-append btn btn-info" (click)="search(currentSearch)">
                         <span class="fa fa-search"></span>
                     </button>
@@ -52,14 +51,14 @@
             <tr<% if (pagination !== 'no') { %> jhiSort [(predicate)]="predicate" [(ascending)]="reverse" [callback]="<%=pagination !== 'infinite-scroll' ? 'transition.bind(this)' : 'reset.bind(this)'%>"<% } %>>
             <th<% if (pagination !== 'no') { %> jhiSortBy="id"<% } %>><span jhiTranslate="global.field.id">ID</span><% if (pagination !== 'no') { %> <span class="fa fa-sort"></span><% } %></th>
             <%_ for (idx in fields) { _%>
-            <th<% if (pagination !== 'no') { %> jhiSortBy="<%= fields[idx].fieldName%>"<% } %>><span jhiTranslate="<%=keyPrefix + fields[idx].fieldName %>"><%= fields[idx].fieldNameHumanized %></span><% if (pagination !== 'no') { %> <span class="fa fa-sort"></span><% } %></th>
+            <th<% if (pagination !== 'no') { %> jhiSortBy="<%= fields[idx].fieldName%>"<% } %>><span jhiTranslate="<%=`${i18nKeyPrefix}.${fields[idx].fieldName}` %>"><%= fields[idx].fieldNameHumanized %></span><% if (pagination !== 'no') { %> <span class="fa fa-sort"></span><% } %></th>
             <%_ } _%>
             <%_ for (idx in relationships) { _%>
             <%_ if (relationships[idx].relationshipType === 'many-to-one'
             || (relationships[idx].relationshipType === 'one-to-one' && relationships[idx].ownerSide === true)
             || (relationships[idx].relationshipType === 'many-to-many' && relationships[idx].ownerSide === true && pagination === 'no')) {
             const fieldName = dto === 'no' ? "." + relationships[idx].otherEntityField : relationships[idx].otherEntityFieldCapitalized;_%>
-            <th<% if (pagination !== 'no') { %> jhiSortBy="<%=relationships[idx].relationshipName + (fieldName)%>"<% } %>><span jhiTranslate="<%= keyPrefix + relationships[idx].relationshipName%>"><%= relationships[idx].relationshipNameHumanized %></span><% if (pagination !== 'no') { %> <span class="fa fa-sort"></span><% } %></th>
+            <th<% if (pagination !== 'no') { %> jhiSortBy="<%=relationships[idx].relationshipName + (fieldName)%>"<% } %>><span jhiTranslate="<%= `${i18nKeyPrefix}.${relationships[idx].relationshipName}` %>"><%= relationships[idx].relationshipNameHumanized %></span><% if (pagination !== 'no') { %> <span class="fa fa-sort"></span><% } %></th>
             <%_ } _%>
             <%_ } _%>
             <th></th>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.route.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.route.ts.ejs
index c467049440..b6ab6c7ec0 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.route.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-management.route.ts.ejs
@@ -16,20 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
-<%_
-let hasDate = false;
-if (fieldsContainInstant || fieldsContainZonedDateTime || fieldsContainLocalDate) {
-    hasDate = true;
-}
-_%>
 <%_ if (pagination === 'pagination' || pagination === 'pager') { _%>
 import { Injectable } from '@angular/core';
 <%_ } _%>
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
index e6a0135c9e..9dc6c50f75 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity-popup.service.ts.ejs
@@ -22,12 +22,6 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
 import { HttpResponse } from '@angular/common/http';
 import { I<%= entityAngularName %>, <%= entityAngularName %> } from 'app/shared/model/<%= entityModelFileName %>.model';
 import { <%= entityAngularName %>Service } from './<%= entityFileName %>.service';
-<%_
-let hasDate = false;
-if (fieldsContainInstant || fieldsContainZonedDateTime || fieldsContainLocalDate) {
-    hasDate = true;
-}
-_%>
 
 @Injectable()
 export class <%= entityAngularName %>PopupService {
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
index 9e367f17f1..4716a76768 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/entity.service.ts.ejs
@@ -16,16 +16,10 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-    let hasDate = false;
-    if (fieldsContainInstant || fieldsContainZonedDateTime || fieldsContainLocalDate) {
-        hasDate = true;
-    }
-_%>
 import { Injectable } from '@angular/core';
 import { HttpClient, HttpResponse } from '@angular/common/http';
 import { Observable } from 'rxjs/Observable';
-<%_ if (hasDate) { _%>
+<%_ if (fieldsContainDate) { _%>
 import * as moment from 'moment';
 <%_ } _%>
 
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/infinite-scroll-template.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/infinite-scroll-template.ejs
index 1af449abcc..37023056ed 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/infinite-scroll-template.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/infinite-scroll-template.ejs
@@ -16,15 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
-
     <%= entityInstancePlural %>: I<%= entityAngularName %>[];
     currentAccount: any;
     eventSubscriber: Subscription;
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/no-pagination-template.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/no-pagination-template.ejs
index 639a77ca4d..f80cb31a69 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/no-pagination-template.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/no-pagination-template.ejs
@@ -16,14 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
     <%= entityInstancePlural %>: I<%= entityAngularName %>[];
     currentAccount: any;
     eventSubscriber: Subscription;
diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/pagination-template.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/pagination-template.ejs
index 5a4e65c880..a45aa31fdc 100644
--- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/pagination-template.ejs
+++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/pagination-template.ejs
@@ -16,15 +16,6 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-<%_
-const i18nToLoad = [entityInstance];
-for (const idx in fields) {
-    if (fields[idx].fieldIsEnum === true) {
-        i18nToLoad.push(fields[idx].enumInstance);
-    }
-}
-_%>
-
     currentAccount: any;
     <%= entityInstancePlural %>: I<%= entityAngularName %>[];
     error: any;
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-delete-dialog.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-delete-dialog.tsx.ejs
index 36969d0fe4..f03644be59 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-delete-dialog.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-delete-dialog.tsx.ejs
@@ -50,11 +50,10 @@ export class <%= entityReactName %>DeleteDialog extends React.Component<I<%= ent
   render() {
     const { <%= entityInstance %> } = this.props;
     return (
-      <%_ const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.'; _%>
       <Modal isOpen toggle={this.handleClose}>
       <ModalHeader toggle={this.handleClose}><Translate contentKey="entity.delete.title">Confirm delete operation</Translate></ModalHeader>
       <ModalBody>
-        <Translate contentKey="<%= keyPrefix %>delete.question" interpolate={{ id: <%= entityInstance %>.id }}>
+        <Translate contentKey="<%= i18nKeyPrefix %>.delete.question" interpolate={{ id: <%= entityInstance %>.id }}>
             Are you sure you want to delete this <%= entityClass %>?
         </Translate>
       </ModalBody>
@@ -73,8 +72,8 @@ export class <%= entityReactName %>DeleteDialog extends React.Component<I<%= ent
   }
 }
 
-const mapStateToProps = storeState => ({
-    <%= entityInstance %>: storeState.<%= entityInstance %>.entity
+const mapStateToProps = ({ <%= entityInstance %> }) => ({
+    <%= entityInstance %>: <%= entityInstance %>.entity
 });
 
 const mapDispatchToProps = { getEntity, deleteEntity };
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-detail.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-detail.tsx.ejs
index 5427653736..dc98040b66 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-detail.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-detail.tsx.ejs
@@ -16,28 +16,23 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -%>
-
-<%_
-const blobs = fields.filter(e => ['byte[]', 'ByteBuffer'].includes(e.fieldType));
-const hasBlob = blobs.length > 0;
-const hasAnyBlobOrImage = blobs.filter(e => e.fieldTypeBlobContent !== 'text').length != 0;
-_%>
-
-
 import * as React from 'react';
 import { connect } from 'react-redux';
 import { Link } from 'react-router-dom';
 import { Button<% if (haveFieldWithJavadoc) { %>, UncontrolledTooltip<% } %> } from 'reactstrap';
-// TODO import TextFormat only when fieldContainsDate
 // tslint:disable-next-line:no-unused-variable
 import {
   Translate,
   ICrudGetAction,
-  <%_ if (hasBlob) { _%>
-  <% if(hasAnyBlobOrImage) { %> openFile, <% } %>
+  <%_ if (fieldsContainBlob) { _%>
+    <%_ if(fieldsContainBlobOrImage) { _%>
+  openFile,
+    <%_ } _%>
   byteSize,
   <%_ } _%>
+  <%_ if (fieldsContainDate) { _%>
   TextFormat
+  <%_ } _%>
 } from 'react-jhipster';
 import { FaArrowLeft } from 'react-icons/lib/fa';
 
@@ -60,10 +55,9 @@ export class <%= entityReactName %>Detail extends React.Component<I<%= entityRea
   render() {
     const { <%= entityInstance %> } = this.props;
     return (
-      <%_ const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.'; _%>
       <div>
         <h2>
-          <Translate contentKey="<%= keyPrefix %>detail.title"><%= entityClass %></Translate> [<b>{<%= entityInstance %>.id}</b>]
+          <Translate contentKey="<%= i18nKeyPrefix %>.detail.title"><%= entityClass %></Translate> [<b>{<%= entityInstance %>.id}</b>]
         </h2>
         <dl className="row-md jh-entity-details">
         <%_ for (idx in fields) {
@@ -72,14 +66,14 @@ export class <%= entityReactName %>Detail extends React.Component<I<%= entityRea
         _%>
           <dt>
             <span id="<%= fieldName %>">
-              <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+              <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
               <%=fields[idx].fieldName%>
               </Translate>
             </span>
             <%_ if (fields[idx].javadoc) { _%>
             <UncontrolledTooltip target="<%= fieldName %>">
               <%_ if (enableTranslation) { _%>
-              <Translate contentKey="<%= keyPrefix %>help.<%= fieldName %>"/>
+              <Translate contentKey="<%= i18nKeyPrefix %>.help.<%= fieldName %>"/>
               <%_ } else { _%>
               <%= fields[idx].javadoc %>
               <%_ } _%>
@@ -134,7 +128,7 @@ export class <%= entityReactName %>Detail extends React.Component<I<%= entityRea
               || (relationshipType === 'one-to-one' && ownerSide === true)
               || (relationshipType === 'many-to-many' && ownerSide === true)) { _%>
           <dt>
-            <Translate contentKey="<%= keyPrefix %><%= relationshipName %>">
+            <Translate contentKey="<%= i18nKeyPrefix %>.<%= relationshipName %>">
               <%= relationshipNameHumanized %>
             </Translate>
           </dt>
@@ -183,8 +177,8 @@ export class <%= entityReactName %>Detail extends React.Component<I<%= entityRea
   }
 }
 
-const mapStateToProps = storeState => ({
-    <%= entityInstance %>: storeState.<%= entityInstance %>.entity
+const mapStateToProps = ({ <%= entityInstance %> }) => ({
+    <%= entityInstance %>: <%= entityInstance %>.entity
 });
 
 const mapDispatchToProps = { getEntity };
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-dialog.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
similarity index 91%
rename from generators/entity-client/templates/react/src/main/webapp/app/entities/entity-dialog.tsx.ejs
rename to generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
index 8d64f8f90e..4c2cf76492 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-dialog.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity-update.tsx.ejs
@@ -27,10 +27,6 @@ for (const idx in fields) {
 // const queries = query.queries;
 // const variables = query.variables;
 // let hasManyToMany = query.hasManyToMany;
-
-const blobs = fields.filter(e => ['byte[]', 'ByteBuffer'].includes(e.fieldType));
-const hasBlob = blobs.length > 0;
-const hasAnyBlobOrImage = blobs.filter(e => e.fieldTypeBlobContent !== 'text').length != 0;
 _%>
 import * as React from 'react';
 import { connect } from 'react-redux';
@@ -41,31 +37,21 @@ import {
   Col,
   Label
   <% if (haveFieldWithJavadoc) { %>, UncontrolledTooltip<% } %> } from 'reactstrap';
-<%_
-  let isAvField = false;
-  for (idx in fields) {
-    fieldType = fields[idx].fieldType;
-    if (!['Instant', 'ZonedDateTime', 'Boolean'].includes(fieldType)) {
-      isAvField = true;
-      break;
-    }
-  }
-_%>
-import { AvForm, AvGroup, AvInput<% if (isAvField) { %>, AvField <% } %> } from 'availity-reactstrap-validation';
+import { AvForm, AvGroup, AvInput<% if (fieldsIsReactAvField) { %>, AvField <% } %> } from 'availity-reactstrap-validation';
 // tslint:disable-next-line:no-unused-variable
 import {
   Translate,
   translate,
   ICrudGetAction,
   ICrudGetAllAction,
-  <%_ if (hasBlob) { _%>
+  <%_ if (fieldsContainBlob) { _%>
   setFileData,
-  <% if(hasAnyBlobOrImage) { %> openFile,<% } %>
+  <% if(fieldsContainBlobOrImage) { %> openFile,<% } %>
   byteSize,
   <%_ } _%>
   ICrudPutAction
 } from 'react-jhipster';
-import { FaBan, <% if(hasBlob) { %>FaTimesCircle, <% } %>FaFloppyO, FaArrowLeft } from 'react-icons/lib/fa';
+import { FaBan, <% if(fieldsContainBlob) { %>FaTimesCircle, <% } %>FaFloppyO, FaArrowLeft } from 'react-icons/lib/fa';
 
 <%_
 let hasRelationshipQuery = false;
@@ -106,7 +92,7 @@ import { I<%= uniqueRel.otherEntityAngularName %> } from 'app/shared/model/user.
 import { getUsers } from 'app/modules/administration/user-management/user-management.reducer';
 <%_ } else { _%>
 import { I<%= uniqueRel.otherEntityAngularName %> } from 'app/shared/model/<%= uniqueRel.otherEntityModelName %>.model';
-import { getEntities as get<%= upperFirstCamelCase(uniqueRel.otherEntityNamePlural) %> } from 'app/entities/<%= uniqueRel.otherEntityModulePath %>/<%= uniqueRel.otherEntityFileName %>.reducer';
+import { getEntities as get<%= upperFirstCamelCase(uniqueRel.otherEntityNamePlural) %> } from 'app/entities/<%= uniqueRel.otherEntityPath %>/<%= uniqueRel.otherEntityFileName %>.reducer';
 <%_ }
   }
 }); _%>
@@ -115,7 +101,7 @@ import {
   updateEntity,
   createEntity,
   <%_
-    blobs.forEach(b => {
+    blobFields.forEach(b => {
       const capitalizedFirstLetter = upperFirst(b.fieldName);
   _%>
   set<%= capitalizedFirstLetter %>,
@@ -125,7 +111,7 @@ import {
 // tslint:disable-next-line:no-unused-variable
 import { convertDateTimeFromServer } from 'app/shared/util/date-utils';
 
-export interface I<%= entityReactName %>DialogProps {
+export interface I<%= entityReactName %>UpdateProps {
   getEntity: ICrudGetAction;
   updateEntity: ICrudPutAction;
   createEntity: ICrudPutAction;
@@ -135,7 +121,7 @@ export interface I<%= entityReactName %>DialogProps {
   <%_ }) _%>
   <%= entityInstance %>: any;
   <%_
-    blobs.forEach(b => {
+    blobFields.forEach(b => {
       const capitalizedFirstLetter = upperFirst(b.fieldName);
   _%>
   set<%= capitalizedFirstLetter %>: Function;
@@ -147,7 +133,7 @@ export interface I<%= entityReactName %>DialogProps {
   history: any;
 }
 
-export interface I<%= entityReactName %>DialogState {
+export interface I<%= entityReactName %>UpdateState {
   isNew: boolean;
   <%_ manyToManyOwners.forEach(val => { _%>
   ids<%= val.relationshipName %>: any[];
@@ -155,12 +141,12 @@ export interface I<%= entityReactName %>DialogState {
   <%_ relFieldNames.forEach(val => { _%>
   <%= val.relationshipFieldName %>Id: number;
   <%_ }) _%>
-  <%_ blobs.forEach(b => {_%>
+  <%_ blobFields.forEach(b => {_%>
   <%= b.fieldName %>: any;
   <%_ }) _%>
 }
 
-export class <%= entityReactName %>Dialog extends React.Component<I<%= entityReactName %>DialogProps, I<%= entityReactName %>DialogState> {
+export class <%= entityReactName %>Update extends React.Component<I<%= entityReactName %>UpdateProps, I<%= entityReactName %>UpdateState> {
 
   constructor(props) {
     super(props);
@@ -172,7 +158,7 @@ export class <%= entityReactName %>Dialog extends React.Component<I<%= entityRea
       <%_ relFieldNames.forEach(val => { _%>
       <%= val.relationshipFieldName %>Id: 0,
       <%_ }) _%>
-      <%_ blobs.forEach(b => { _%>
+      <%_ blobFields.forEach(b => { _%>
       <%= b.fieldName %>: null,
       <%_ }) _%>
     };
@@ -190,7 +176,7 @@ export class <%= entityReactName %>Dialog extends React.Component<I<%= entityRea
     <%_ }) _%>
   }
 
-  <%_ if (hasBlob) {_%>
+  <%_ if (fieldsContainBlob) {_%>
   onBlobChange = (isAnImage, reducerFunction) => event => {
     setFileData(event, (contentType, data) => reducerFunction({ contentType, data }), isAnImage);
   };
@@ -309,9 +295,9 @@ _%>
     %> <%= rel %>,<% }) %> loading, updating } = this.props;
     const { isNew } = this.state;
 
-    <%_ for (var i = 0; i < blobs.length; i++) { _%>
+    <%_ for (var i = 0; i < blobFields.length; i++) { _%>
     <%_
-      const b = blobs[i];
+      const b = blobFields[i];
       if (i === 0) {
     _%>
       const {
@@ -320,7 +306,7 @@ _%>
       <%_ if (b.fieldTypeBlobContent !== 'text') { _%>
       , <%= b.fieldName %>ContentType
       <%_ } _%>
-      <%_ if (i+1 === blobs.length) { _%>
+      <%_ if (i+1 === blobFields.length) { _%>
       } = <%= entityInstance %>;
       <%_ } else { _%>
       ,
@@ -328,12 +314,11 @@ _%>
     <%_ } _%>
 
     return (
-      <%_ const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.'; _%>
       <div>
       <Row className="justify-content-center">
         <Col md="8">
           <h1>
-            <Translate contentKey="<%= keyPrefix %>home.createOrEditLabel">Create or edit a <%= entityClass %></Translate>
+            <Translate contentKey="<%= i18nKeyPrefix %>.home.createOrEditLabel">Create or edit a <%= entityClass %></Translate>
           </h1>
         </Col>
       </Row>
@@ -356,13 +341,13 @@ _%>
             <%_ if (fieldType === 'Boolean') { _%>
               <Label id="<%= fieldName %>Label" check>
                 <AvInput type="checkbox" className="form-control" name="<%= fieldName %>" />
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
             <%_ } else if (['Instant', 'ZonedDateTime'].includes(fieldType)) { _%>
               <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
@@ -375,7 +360,7 @@ _%>
               />
             <%_ } else if (fieldType === 'LocalDate') { _%>
               <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
@@ -390,7 +375,7 @@ _%>
                 const values = fields[idx].fieldValues.replace(/\s/g, '').split(',');
             _%>
               <Label id="<%= fieldName %>Label">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
@@ -410,7 +395,7 @@ _%>
               </AvInput>
             <%_ } else if (['Integer', 'Long', 'Float', 'Double'].includes(fieldType)) { _%>
               <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
@@ -427,7 +412,7 @@ _%>
 
             <AvGroup>
               <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%= fieldName %>
                 </Translate>
               </Label>
@@ -457,7 +442,7 @@ _%>
 
             <%_ } else { _%>
               <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-                <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+                <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                   <%=fieldName%>
                 </Translate>
               </Label>
@@ -465,7 +450,7 @@ _%>
               <%_ } _%>
             <%_ } else { _%>
             <Label id="<%= fieldName %>Label" for="<%= fieldName %>">
-              <Translate contentKey="<%= keyPrefix %><%= fieldName %>">
+              <Translate contentKey="<%= i18nKeyPrefix %>.<%= fieldName %>">
                 <%=fieldName%>
               </Translate>
             </Label>
@@ -474,7 +459,7 @@ _%>
             <%_ if (fields[idx].javadoc) { _%>
             <UncontrolledTooltip target="<%= fieldName %>Label">
               <%_ if (enableTranslation) { _%>
-              <Translate contentKey="<%= keyPrefix %>help.<%= fieldName %>"/>
+              <Translate contentKey="<%= i18nKeyPrefix %>.help.<%= fieldName %>"/>
               <%_ } else { _%>
               <%= fields[idx].javadoc %>
               <%_ } _%>
@@ -495,7 +480,7 @@ _%>
                 const otherEntityField = rel.otherEntityField;
                 const otherEntityFieldCapitalized = rel.otherEntityFieldCapitalized;
                 const relationshipRequired = rel.relationshipRequired;
-                const translationKey = keyPrefix + relationshipName; _%>
+                const translationKey = `${i18nKeyPrefix}.${relationshipName}`; _%>
                 <%_ if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide === true && otherEntityName === 'user')) { _%>
             <AvGroup>
               <Label for="<%= relationshipFieldName %>.<%= otherEntityField %>">
@@ -678,7 +663,7 @@ const mapDispatchToProps = {
   getEntity,
   updateEntity,
   <%_
-    blobs.forEach(b => {
+    blobFields.forEach(b => {
       const capitalizedFirstLetter =  upperFirst(b.fieldName);
   _%>
   set<%= capitalizedFirstLetter %>,
@@ -687,4 +672,4 @@ const mapDispatchToProps = {
   reset
 };
 
-export default connect(mapStateToProps, mapDispatchToProps)(<%= entityReactName %>Dialog);
+export default connect(mapStateToProps, mapDispatchToProps)(<%= entityReactName %>Update);
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.reducer.ts.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.reducer.ts.ejs
index 03f1cdcce2..4a6b9aceb8 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.reducer.ts.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.reducer.ts.ejs
@@ -17,17 +17,11 @@
  limitations under the License.
 -%>
 <%_
-    let hasDate = false;
-    if (fieldsContainInstant || fieldsContainZonedDateTime || fieldsContainLocalDate) {
-        hasDate = true;
-    }
     let entityActionName = entityInstance.toUpperCase();
     let entityActionNamePlural = entityInstancePlural.toUpperCase();
-
-    const blobs = fields.filter(e => ['byte[]', 'ByteBuffer'].includes(e.fieldType));
 _%>
 <%_ if (pagination === 'infinite-scroll') { _%>
-  import { isEqual } from 'lodash';
+import { isEqual } from 'lodash';
 <%_ } _%>
 import axios from 'axios';
 import { ICrudGetAction, ICrudGetAllAction, ICrudPutAction, ICrudDeleteAction<% if (pagination === 'infinite-scroll') { %>, parseHeaderForLinks, loadMoreDataWhenScrolled<% } %> } from 'react-jhipster';
@@ -38,8 +32,8 @@ import { SERVER_API_URL } from 'app/config/constants';
 <%_ if (!(applicationType === 'gateway' && locals.microserviceName) && authenticationType !== 'uaa') { _%>
 
 <%_ } _%>
-<%_ if (hasDate) { _%>
-// import { JhiDateUtils } from 'ng-jhipster';
+<%_ if (fieldsContainDate) { _%>
+
 <%_ } _%>
 // import { <%= entityAngularName %> } from './<%= entityFileName %>.model';
 
@@ -53,7 +47,7 @@ export const ACTION_TYPES = {
   UPDATE_<%= entityActionName %>: '<%= entityInstance %>/UPDATE_<%= entityActionName %>',
   DELETE_<%= entityActionName %>: '<%= entityInstance %>/DELETE_<%= entityActionName %>',
   <%_
-  blobs.forEach(b => {
+  blobFields.forEach(b => {
     const upperFieldName = b.fieldName.toUpperCase();
   _%>
   SET_<%= upperFieldName %>: '<%= entityInstance %>/SET_<%= upperFieldName %>',
@@ -166,7 +160,7 @@ export default (state = initialState, action) => {
         entity: {}
       };
     <%_
-    blobs.forEach(b => {
+    blobFields.forEach(b => {
       const fieldName = b.fieldName;
       const upperFieldName = fieldName.toUpperCase();
     _%>
@@ -256,7 +250,7 @@ export const deleteEntity: ICrudDeleteAction = id => async dispatch => {
 };
 
 <%_
-  blobs.forEach(b => {
+  blobFields.forEach(b => {
     const fieldName = b.fieldName;
     const upperFirstName =  upperFirst(fieldName);
     const upperFieldName = b.fieldName.toUpperCase();
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.tsx.ejs
index 13ddbd9e76..99c5fe05b5 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/entity.tsx.ejs
@@ -26,28 +26,16 @@ import { Button<% if (searchEngine === 'elasticsearch') { %>, InputGroup<% } %>
 <%_ if (searchEngine === 'elasticsearch') { _%>
 import { AvForm, AvGroup, AvInput } from 'availity-reactstrap-validation';
 <%_ } _%>
-// TODO import TextFormat only when fieldContainsDate
 // tslint:disable-next-line:no-unused-variable
-<%_
-  let fieldContainsDate = false;
-  for (idx in fields) {
-    fieldType = fields[idx].fieldType;
-    if (['Instant', 'ZonedDateTime', 'LocalDate'].includes(fieldType)) {
-      fieldContainsDate = true;
-      break;
-    }
-  }
-
-  const blobs = fields.filter(e => ['byte[]', 'ByteBuffer'].includes(e.fieldType));
-  const hasAnyBlobOrImage = blobs.filter(e => e.fieldTypeBlobContent !== 'text').length != 0;
-_%>
 import {
-  <%_ if (blobs.length > 0) { _%>
-  <% if(hasAnyBlobOrImage) { %> openFile, <% } %>
+  <%_ if (blobFields.length > 0) { _%>
+    <%_ if(fieldsContainBlobOrImage) { _%>
+  openFile,
+    <%_ } _%>
   byteSize,
   <%_ } _%>
   Translate<% if (searchEngine === 'elasticsearch') { %>, translate<% } %>,
-  ICrudGetAllAction<% if (fieldContainsDate) { %>, TextFormat<% } %>
+  ICrudGetAllAction<% if (fieldsContainDate) { %>, TextFormat<% } %>
   <%_ if (pagination !== 'no') { _%>
   , getSortState, IPaginationBaseState
   <%_ if (pagination === 'pagination' || pagination === 'pager') { _%>
@@ -190,12 +178,11 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
   render() {
     const { <%=entityInstance %>List, match<% if (pagination === 'pagination' || pagination === 'pager') { %>, totalItems<% } %>} = this.props;
     return (
-      <%_ const keyPrefix = angularAppName + '.'+ entityTranslationKey + '.'; _%>
       <div>
         <h2>
-          <Translate contentKey="<%= keyPrefix %>home.title"><%= entityClassPluralHumanized %></Translate>
+          <Translate contentKey="<%= i18nKeyPrefix %>.home.title"><%= entityClassPluralHumanized %></Translate>
           <Link to={`${match.url}/new`} className="btn btn-primary float-right jh-create-entity">
-            <FaPlus /> <Translate contentKey="<%= keyPrefix %>home.createLabel" />
+            <FaPlus /> <Translate contentKey="<%= i18nKeyPrefix %>.home.createLabel" />
           </Link>
         </h2>
         <%_ if (searchEngine === 'elasticsearch') { _%>
@@ -204,7 +191,7 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
             <AvForm onSubmit={this.search}>
               <AvGroup>
                 <InputGroup>
-                  <AvInput type="text" name="search" value={this.state.search} onChange={this.handleSearch} placeholder={translate('<%= keyPrefix %>home.search')} />
+                  <AvInput type="text" name="search" value={this.state.search} onChange={this.handleSearch} placeholder={translate('<%= i18nKeyPrefix %>.home.search')} />
                   <Button className="input-group-addon">
                     <FaSearch/>
                   </Button>
@@ -231,14 +218,14 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
               <tr>
                 <th<% if (pagination !== 'no') { %> className="hand" onClick={this.sort('id')} <%_ } _%>><Translate contentKey="global.field.id">ID</Translate><% if (pagination !== 'no') { %> <FaSort /><% } %></th>
                 <%_ for (idx in fields) { _%>
-                <th<% if (pagination !== 'no') { %> className="hand" onClick={this.sort('<%=fields[idx].fieldName%>')} <%_ } _%>><Translate contentKey="<%=keyPrefix + fields[idx].fieldName %>"><%= fields[idx].fieldNameHumanized %></Translate><% if (pagination !== 'no') { %> <FaSort /><% } %></th>
+                <th<% if (pagination !== 'no') { %> className="hand" onClick={this.sort('<%=fields[idx].fieldName%>')} <%_ } _%>><Translate contentKey="<%= `${i18nKeyPrefix}.${fields[idx].fieldName}` %>"><%= fields[idx].fieldNameHumanized %></Translate><% if (pagination !== 'no') { %> <FaSort /><% } %></th>
                 <%_ } _%>
                 <%_ for (idx in relationships) { _%>
                     <%_ if (relationships[idx].relationshipType === 'many-to-one'
                     || (relationships[idx].relationshipType === 'one-to-one' && relationships[idx].ownerSide === true)
                     || (relationships[idx].relationshipType === 'many-to-many' && relationships[idx].ownerSide === true && pagination === 'no')) {
                     const fieldName = dto === 'no' ? "." + relationships[idx].otherEntityField : relationships[idx].otherEntityFieldCapitalized;_%>
-                <th<% if (pagination !== 'no') { %> <% } %>><Translate contentKey="<%= keyPrefix + relationships[idx].relationshipName%>"><%= relationships[idx].relationshipNameHumanized %></Translate><% if (pagination !== 'no') { %> <FaSort /><% } %></th>
+                <th<% if (pagination !== 'no') { %> <% } %>><Translate contentKey="<%= `${i18nKeyPrefix}.${relationships[idx].relationshipName}` %>"><%= relationships[idx].relationshipNameHumanized %></Translate><% if (pagination !== 'no') { %> <FaSort /><% } %></th>
                     <%_ } _%>
                 <%_ } _%>
                 <th />
@@ -266,7 +253,7 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
                     <TextFormat type="date" value={<%= entityInstance %>.<%=fieldName%>} format={APP_LOCAL_DATE_FORMAT} />
                   <%_ } else if (['byte[]', 'ByteBuffer'].includes(fieldType)) { _%>
                     <%_
-                      // Blobs
+                      // blobFields
                       const fieldBlobType = fields[idx].fieldTypeBlobContent;
                       if (fieldBlobType !== 'text') {
                     _%>
@@ -354,7 +341,7 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
                         <Button tag={Link} to={`${match.url}/${<%=entityInstance %>.id}/edit`} color="primary" size="sm">
                           <FaPencil/> <span className="d-none d-md-inline"><Translate contentKey="entity.action.edit" /></span>
                         </Button>
-                        <Button tag={Link} to={{ pathname: `${match.url}/${<%=entityInstance %>.id}/delete`, state: { modal: true }}} color="danger" size="sm">
+                        <Button tag={Link} to={`${match.url}/${<%=entityInstance %>.id}/delete`} color="danger" size="sm">
                           <FaTrash/> <span className="d-none d-md-inline"><Translate contentKey="entity.action.delete" /></span>
                         </Button>
                       </div>
@@ -366,7 +353,7 @@ export class <%= entityReactName %> extends React.Component<I<%= entityReactName
           </table>
           <%_ if (pagination === 'infinite-scroll') { _%>
           </InfiniteScroll>
-          <%_ } _%>  
+          <%_ } _%>
         </div>
         <%_ if (pagination === 'pagination' || pagination === 'pager') { _%>
         <div className="row justify-content-center">
diff --git a/generators/entity-client/templates/react/src/main/webapp/app/entities/index.tsx.ejs b/generators/entity-client/templates/react/src/main/webapp/app/entities/index.tsx.ejs
index b9e5f5fd18..36b69d8b6b 100644
--- a/generators/entity-client/templates/react/src/main/webapp/app/entities/index.tsx.ejs
+++ b/generators/entity-client/templates/react/src/main/webapp/app/entities/index.tsx.ejs
@@ -18,44 +18,22 @@
 -%>
 import * as React from 'react';
 import { Route, Switch } from 'react-router-dom';
-import { ModalRoute } from 'react-router-modal';
 
 import <%= entityReactName %> from './<%= entityFileName %>';
 import <%= entityReactName %>Detail from './<%= entityFileName %>-detail';
-import <%= entityReactName %>Dialog from './<%= entityFileName %>-dialog';
+import <%= entityReactName %>Update from './<%= entityFileName %>-update';
 import <%= entityReactName %>DeleteDialog from './<%= entityFileName %>-delete-dialog';
 
-export interface IRoutesProps {
-  match: any;
-  location: any;
-}
-
-export class Routes extends React.Component<IRoutesProps> {
-  previousLocation = this.props.location;
-
-  componentWillUpdate(nextProps) {
-    const { location } = this.props;
-    if (nextProps.history.action !== "POP" && (!location.state || !location.state.modal)) {
-      this.previousLocation = this.props.location;
-    }
-  }
-
-  render() {
-    const { match, location } = this.props;
-    const isModal = !!(location.state && location.state.modal && this.previousLocation !== location);
-
-    return (
-      <div>
-        <Switch location={isModal ? this.previousLocation : location}>
-          <Route exact path={match.url} component={<%= entityReactName %>} />
-          <Route exact parentPath={match.url} path={`${match.url}/new`} component={<%= entityReactName %>Dialog} />
-          <Route exact parentPath={match.url} path={`${match.url}/:id/edit`} component={<%= entityReactName %>Dialog} />
-          <Route exact path={`${match.url}/:id`} component={<%= entityReactName %>Detail}  />
-        </Switch>
-        {isModal ? <Route exact parentPath={match.url} path={`${match.url}/:id/delete`} component={<%= entityReactName %>DeleteDialog} /> : null}
-      </div>
-    );
-  }
-}
+const Routes = ({ match }) => (
+  <>
+    <Switch>
+      <Route exact path={`${match.url}/new`} component={<%= entityReactName %>Update} />
+      <Route exact path={`${match.url}/:id/edit`} component={<%= entityReactName %>Update} />
+      <Route exact path={`${match.url}/:id`} component={<%= entityReactName %>Detail}  />
+      <Route path={match.url} component={<%= entityReactName %>} />
+    </Switch>
+    <Route path={`${match.url}/:id/delete`} component={<%= entityReactName %>DeleteDialog} />
+  </>
+);
 
 export default Routes;
diff --git a/generators/entity/index.js b/generators/entity/index.js
index 3a8a455be1..32faa92965 100644
--- a/generators/entity/index.js
+++ b/generators/entity/index.js
@@ -464,23 +464,29 @@ module.exports = class extends BaseGenerator {
                 context.entityTranslationKeyMenu = _.camelCase(context.clientRootFolder ? `${context.clientRootFolder}-${context.entityStateName}` : context.entityStateName);
                 context.jhiTablePrefix = this.getTableName(context.jhiPrefix);
 
+                context.fieldsContainDate = false;
                 context.fieldsContainInstant = false;
                 context.fieldsContainZonedDateTime = false;
                 context.fieldsContainLocalDate = false;
                 context.fieldsContainBigDecimal = false;
                 context.fieldsContainBlob = false;
                 context.fieldsContainImageBlob = false;
+                context.fieldsContainBlobOrImage = false;
                 context.validation = false;
                 context.fieldsContainOwnerManyToMany = false;
                 context.fieldsContainNoOwnerOneToOne = false;
                 context.fieldsContainOwnerOneToOne = false;
                 context.fieldsContainOneToMany = false;
                 context.fieldsContainManyToOne = false;
+                context.fieldsIsReactAvField = false;
+                context.blobFields = [];
                 context.differentTypes = [context.entityClass];
                 if (!context.relationships) {
                     context.relationships = [];
                 }
                 context.differentRelationships = {};
+                context.i18nToLoad = [context.entityInstance];
+                context.i18nKeyPrefix = `${context.angularAppName}.${context.entityTranslationKey}`;
 
                 // Load in-memory data for fields
                 context.fields.forEach((field) => {
@@ -490,6 +496,10 @@ module.exports = class extends BaseGenerator {
                     }
                     const fieldType = field.fieldType;
 
+                    if (!['Instant', 'ZonedDateTime', 'Boolean'].includes(fieldType)) {
+                        context.fieldsIsReactAvField = true;
+                    }
+
                     const nonEnumType = [
                         'String', 'Integer', 'Long', 'Float', 'Double', 'BigDecimal',
                         'LocalDate', 'Instant', 'ZonedDateTime', 'Boolean', 'byte[]', 'ByteBuffer'
@@ -500,6 +510,10 @@ module.exports = class extends BaseGenerator {
                         field.fieldIsEnum = false;
                     }
 
+                    if (field.fieldIsEnum === true) {
+                        context.i18nToLoad.push(field.enumInstance);
+                    }
+
                     if (_.isUndefined(field.fieldNameCapitalized)) {
                         field.fieldNameCapitalized = _.upperFirst(field.fieldName);
                     }
@@ -551,17 +565,24 @@ module.exports = class extends BaseGenerator {
 
                     if (fieldType === 'ZonedDateTime') {
                         context.fieldsContainZonedDateTime = true;
+                        context.fieldsContainDate = true;
                     } else if (fieldType === 'Instant') {
                         context.fieldsContainInstant = true;
+                        context.fieldsContainDate = true;
                     } else if (fieldType === 'LocalDate') {
                         context.fieldsContainLocalDate = true;
+                        context.fieldsContainDate = true;
                     } else if (fieldType === 'BigDecimal') {
                         context.fieldsContainBigDecimal = true;
                     } else if (fieldType === 'byte[]' || fieldType === 'ByteBuffer') {
+                        context.blobFields.push(field);
                         context.fieldsContainBlob = true;
                         if (field.fieldTypeBlobContent === 'image') {
                             context.fieldsContainImageBlob = true;
                         }
+                        if (field.fieldTypeBlobContent !== 'text') {
+                            context.fieldsContainBlobOrImage = true;
+                        }
                     }
 
                     if (field.fieldValidate) {
@@ -695,9 +716,11 @@ module.exports = class extends BaseGenerator {
                                     relationship.otherEntityModulePath = `${context.entityParentPathAddition ? `${context.entityParentPathAddition}/` : ''}${otherEntityData.clientRootFolder}/${relationship.otherEntityFileName}`;
                                 }
                                 relationship.otherEntityModelName = `${otherEntityData.clientRootFolder}/${relationship.otherEntityFileName}`;
+                                relationship.otherEntityPath = `${otherEntityData.clientRootFolder}/${relationship.otherEntityFileName}`;
                             } else {
                                 relationship.otherEntityModulePath = `${context.entityParentPathAddition ? `${context.entityParentPathAddition}/` : ''}${relationship.otherEntityFileName}`;
                                 relationship.otherEntityModelName = relationship.otherEntityFileName;
+                                relationship.otherEntityPath = relationship.otherEntityFileName;
                             }
                         } else {
                             relationship.otherEntityModuleName = `${context.angularXAppName}SharedModule`;
@@ -752,15 +775,6 @@ module.exports = class extends BaseGenerator {
     get writing() {
         if (useBlueprint) return;
         return {
-
-            cleanup() {
-                const context = this.context;
-                const entityName = context.name;
-                if (this.isJhipsterVersionLessThan('5.0.0')) {
-                    this.removeFile(`${constants.ANGULAR_DIR}entities/${entityName}/${entityName}.model.ts`);
-                }
-            },
-
             composeServer() {
                 const context = this.context;
                 if (context.skipServer) return;
diff --git a/generators/generator-base.js b/generators/generator-base.js
index 83ab505ba0..84819357f9 100644
--- a/generators/generator-base.js
+++ b/generators/generator-base.js
@@ -203,7 +203,7 @@ module.exports = class extends PrivateBase {
                     needle: 'jhipster-needle-add-entity-to-menu',
                     splicable: [
                         this.stripMargin(`|(
-                        |        <DropdownItem tag={Link} key="${routerName}" to="/${routerName}">
+                        |        <DropdownItem tag={Link} key="${routerName}" to="/entity/${routerName}">
                         |          <FaAsterisk />&nbsp;
                         |          ${_.startCase(routerName)}
                         |        </DropdownItem>
@@ -276,7 +276,7 @@ module.exports = class extends PrivateBase {
                     file: indexModulePath,
                     needle: 'jhipster-needle-add-route-path',
                     splicable: [
-                        this.stripMargin(`|<Route path={'/${entityFileName}'} component={${entityAngularName}}/>`)
+                        this.stripMargin(`|<Route path={\`\${match.url}/${entityFileName}\`} component={${entityAngularName}}/>`)
                     ]
                 }, this);
 
@@ -2307,6 +2307,7 @@ module.exports = class extends PrivateBase {
     setupClientOptions(generator, context = generator) {
         generator.skipServer = context.configOptions.skipServer || context.config.get('skipServer');
         generator.skipUserManagement = context.configOptions.skipUserManagement || context.options['skip-user-management'] || context.config.get('skipUserManagement');
+        generator.skipCommitHook = context.options['skip-commit-hook'] || context.config.get('skipCommitHook');
         generator.authenticationType = context.options.auth || context.configOptions.authenticationType || context.config.get('authenticationType');
         if (generator.authenticationType === 'oauth2') {
             generator.skipUserManagement = true;
diff --git a/travis/scripts/01-generate-entities.sh b/travis/scripts/01-generate-entities.sh
index 2290673a3d..9f0cf9d30c 100755
--- a/travis/scripts/01-generate-entities.sh
+++ b/travis/scripts/01-generate-entities.sh
@@ -49,29 +49,29 @@ elif [[ "$JHIPSTER" == *"micro"* ]]; then
     moveEntity FieldTestPaginationEntity
 
 elif [[ "$JHIPSTER" == *"react"* ]]; then
-    # moveEntity BankAccount
-    # moveEntity Label
-    # moveEntity Operation
+    moveEntity BankAccount
+    moveEntity Label
+    moveEntity Operation
 
     moveEntity FieldTestEntity
     moveEntity FieldTestMapstructEntity
     moveEntity FieldTestServiceClassEntity
     moveEntity FieldTestServiceImplEntity
-    # moveEntity FieldTestInfiniteScrollEntity
-    # moveEntity FieldTestPagerEntity
-    # moveEntity FieldTestPaginationEntity
-
-    # moveEntity EntityWithDTO
-    # moveEntity EntityWithPagination
-    # moveEntity EntityWithPaginationAndDTO
-    # moveEntity EntityWithServiceClass
-    # moveEntity EntityWithServiceClassAndDTO
-    # moveEntity EntityWithServiceClassAndPagination
-    # moveEntity EntityWithServiceClassPaginationAndDTO
-    # moveEntity EntityWithServiceImpl
-    # moveEntity EntityWithServiceImplAndDTO
-    # moveEntity EntityWithServiceImplAndPagination
-    # moveEntity EntityWithServiceImplPaginationAndDTO
+    moveEntity FieldTestInfiniteScrollEntity
+    moveEntity FieldTestPagerEntity
+    moveEntity FieldTestPaginationEntity
+
+    moveEntity EntityWithDTO
+    moveEntity EntityWithPagination
+    moveEntity EntityWithPaginationAndDTO
+    moveEntity EntityWithServiceClass
+    moveEntity EntityWithServiceClassAndDTO
+    moveEntity EntityWithServiceClassAndPagination
+    moveEntity EntityWithServiceClassPaginationAndDTO
+    moveEntity EntityWithServiceImpl
+    moveEntity EntityWithServiceImplAndDTO
+    moveEntity EntityWithServiceImplAndPagination
+    moveEntity EntityWithServiceImplPaginationAndDTO
 
 elif [[ "$JHIPSTER" == *"uaa"* ]]; then
     moveEntity FieldTestEntity
diff --git a/travis/scripts/02-generate-project.sh b/travis/scripts/02-generate-project.sh
index 9fd4866f14..f79786697e 100755
--- a/travis/scripts/02-generate-project.sh
+++ b/travis/scripts/02-generate-project.sh
@@ -16,12 +16,12 @@ if [[ "$JHIPSTER" == *"uaa"* ]]; then
     mkdir -p "$UAA_APP_FOLDER"
     cp -f "$JHIPSTER_SAMPLES"/uaa/.yo-rc.json "$UAA_APP_FOLDER"/
     cd "$UAA_APP_FOLDER"
-    jhipster --force --no-insight --with-entities --skip-checks
+    jhipster --force --no-insight --with-entities --skip-checks --skip-git --skip-commit-hook
     ls -al "$UAA_APP_FOLDER"
 fi
 
 mkdir -p "$APP_FOLDER"
 cp -f "$JHIPSTER_SAMPLES"/"$JHIPSTER"/.yo-rc.json "$APP_FOLDER"/
 cd "$APP_FOLDER"
-jhipster --force --no-insight --skip-checks --with-entities
+jhipster --force --no-insight --skip-checks --with-entities --skip-git --skip-commit-hook
 ls -al "$APP_FOLDER"


Test patch:
diff --git a/generators/client/templates/react/src/test/javascript/spec/app/shared/auth/private-route.spec.tsx.ejs b/generators/client/templates/react/src/test/javascript/spec/app/shared/auth/private-route.spec.tsx.ejs
new file mode 100644
index 0000000000..883e9b84fe
--- /dev/null
+++ b/generators/client/templates/react/src/test/javascript/spec/app/shared/auth/private-route.spec.tsx.ejs
@@ -0,0 +1,89 @@
+import * as React from 'react';
+import { Route } from 'react-router-dom';
+import { shallow } from 'enzyme';
+import { expect } from 'chai';
+import { PrivateRouteComponent, hasAnyAuthority } from 'app/shared/auth/private-route';
+
+const TestComp = () => <div>Test</div>;
+
+describe('private-route component', () => {
+  // All tests will go here
+  it('Should throw error when no component is provided', () => {
+    expect(() => shallow(<PrivateRouteComponent component={null} isAuthenticated isAuthorized />)).to.throw(Error);
+  });
+
+  it('Should render an error message when the user has no authorities', () => {
+    const route = shallow(<PrivateRouteComponent component={TestComp} isAuthenticated isAuthorized={false} path="/" />);
+    const renderedRoute = route.find(Route);
+    const renderFn: Function = renderedRoute.props().render;
+    const comp = shallow(
+      renderFn({
+        location: '/'
+      })
+    );
+    expect(comp.length).to.equal(1);
+    const error = comp.find('div.insufficient-authority');
+    expect(error.length).to.equal(1);
+    expect(error.find('.alert-danger').html()).to.equal('<div class="alert alert-danger"><span>translation-not-found[error.http.403]</span></div>');
+  });
+
+  it('Should render a route for the component provided when authenticated', () => {
+    const route = shallow(<PrivateRouteComponent component={TestComp} isAuthenticated isAuthorized path="/" />);
+    const renderedRoute = route.find(Route);
+    expect(renderedRoute.length).to.equal(1);
+    expect(renderedRoute.props().path).to.equal('/');
+    // tslint:disable-next-line:no-unused-expression
+    expect(renderedRoute.props().render).to.not.be.undefined;
+    const renderFn: Function = renderedRoute.props().render;
+    const comp = shallow(
+      renderFn({
+        location: '/'
+      })
+    );
+    expect(comp.length).to.equal(1);
+    expect(comp.html()).to.equal('<div>Test</div>');
+  });
+
+  it('Should render a redirect to login when not authenticated', () => {
+    const route = shallow(<PrivateRouteComponent component={TestComp} isAuthenticated={false} isAuthorized path="/" />);
+    const renderedRoute = route.find(Route);
+    expect(renderedRoute.length).to.equal(1);
+    const renderFn: Function = renderedRoute.props().render;
+    // as rendering redirect outside router will throw error
+    expect(() =>
+      shallow(
+        renderFn({
+          location: '/'
+        })
+      )
+    ).to.throw(Error);
+  });
+});
+
+describe('hasAnyAuthority', () => {
+  // All tests will go here
+  it('Should return false when authorities is invlaid', () => {
+    expect(hasAnyAuthority(undefined, undefined)).to.equal(false);
+    expect(hasAnyAuthority(null, [])).to.equal(false);
+    expect(hasAnyAuthority([], [])).to.equal(false);
+    expect(hasAnyAuthority([], ['ROLE_USER'])).to.equal(false);
+  });
+
+  it('Should return true when authorities is valid and hasAnyAuthorities is empty', () => {
+    expect(hasAnyAuthority(['ROLE_USER'], [])).to.equal(true);
+  });
+
+  it('Should return true when authorities is valid and hasAnyAuthorities contains an authority', () => {
+    expect(hasAnyAuthority(['ROLE_USER'], ['ROLE_USER'])).to.equal(true);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLE_USER'])).to.equal(true);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLE_USER', 'ROLE_ADMIN'])).to.equal(true);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLE_USER', 'ROLEADMIN'])).to.equal(true);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLE_ADMIN'])).to.equal(true);
+  });
+
+  it('Should return false when authorities is valid and hasAnyAuthorities does not contains an authority', () => {
+    expect(hasAnyAuthority(['ROLE_USER'], ['ROLE_ADMIN'])).to.equal(false);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLE_USERSS'])).to.equal(false);
+    expect(hasAnyAuthority(['ROLE_USER', 'ROLE_ADMIN'], ['ROLEUSER', 'ROLEADMIN'])).to.equal(false);
+  });
+});
diff --git a/generators/client/templates/react/src/test/javascript/spec/app/shared/layout/header.spec.tsx.ejs b/generators/client/templates/react/src/test/javascript/spec/app/shared/layout/header.spec.tsx.ejs
index d179764b22..8cc248d53e 100644
--- a/generators/client/templates/react/src/test/javascript/spec/app/shared/layout/header.spec.tsx.ejs
+++ b/generators/client/templates/react/src/test/javascript/spec/app/shared/layout/header.spec.tsx.ejs
@@ -38,7 +38,7 @@ describe('Header', () => {
   const wrapper = () => {
     if (!mountedWrapper) {
       mountedWrapper = shallow(
-        <Header isAuthenticated<% if (enableTranslation) { %> currentLocale="en" onLocaleChange={localeSpy}<% } %>/>
+        <Header isAuthenticated isAdmin<% if (enableTranslation) { %> currentLocale="en" onLocaleChange={localeSpy}<% } %>/>
       );
     }
     return mountedWrapper;
diff --git a/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs b/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
index 9975e0fad1..b8bc99edb1 100644
--- a/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
+++ b/generators/entity-client/templates/angular/src/test/javascript/e2e/entities/entity.spec.ts.ejs
@@ -19,15 +19,9 @@
 import { browser, <% if ( fieldsContainInstant || fieldsContainZonedDateTime ) { %>protractor<% } %> } from 'protractor';
 import { NavBarPage } from './../../<%= entityParentPathAddition %>page-objects/jhi-page-objects';
 import { <%= entityClass %>ComponentsPage, <%= entityClass %>DialogPage } from './<%= entityFileName %>.page-object';
-<%_ let fieldHasByte = false;
-fields.forEach((field) => {
-    if (['byte[]', 'ByteBuffer'].includes(field.fieldType) && field.fieldTypeBlobContent !== 'text') {
-        fieldHasByte = true;
-    }
-});
-if (fieldHasByte) {
-    %>import * as path from 'path';
-<% } _%>
+<%_ if (fieldsContainBlobOrImage) { _%>
+import * as path from 'path';
+<%_ } _%>
 <%_
 let elementGetter = `getText()`;
 let openBlockComment = ``;
@@ -48,7 +42,7 @@ describe('<%= entityClass %> e2e test', () => {
     let navBarPage: NavBarPage;
     let <%= entityInstance %>DialogPage: <%= entityClass %>DialogPage;
     let <%= entityInstance %>ComponentsPage: <%= entityClass %>ComponentsPage;
-    <%_ if (fieldHasByte) { _%>
+    <%_ if (fieldsContainBlobOrImage) { _%>
     const fileToUpload = '../../../../../<%= entityParentPathAddition %>main/webapp/content/images/logo-jhipster.png';
     const absolutePath = path.resolve(__dirname, fileToUpload);
     <%_ } _%>
diff --git a/generators/entity-client/templates/react/src/test/javascript/spec/app/entities/entity-reducer.spec.ts.ejs b/generators/entity-client/templates/react/src/test/javascript/spec/app/entities/entity-reducer.spec.ts.ejs
index 7b0ef83181..3136a9ca01 100644
--- a/generators/entity-client/templates/react/src/test/javascript/spec/app/entities/entity-reducer.spec.ts.ejs
+++ b/generators/entity-client/templates/react/src/test/javascript/spec/app/entities/entity-reducer.spec.ts.ejs
@@ -19,24 +19,22 @@
 <%_
     let entityActionName = entityInstance.toUpperCase();
     let entityActionNamePlural = entityInstancePlural.toUpperCase();
-    const blobs = fields.filter(e => ['byte[]', 'ByteBuffer'].includes(e.fieldType));
-    const hasBlob = blobs.length > 0;
 _%>
 import axios from 'axios';
 import { expect } from 'chai';
-import reducer, {
-  ACTION_TYPES, createEntity, deleteEntity, getEntities, getEntity, updateEntity<% if (pagination === 'infinite-scroll') { %>, reset<% } %>
-} from 'app/entities<% if (applicationType === 'gateway' && locals.microserviceName) { %>/<%= microserviceName.toLowerCase() %><% } %>/<%= entityFileName %>/<%= entityFileName %>.reducer';
 import configureStore from 'redux-mock-store';
 import promiseMiddleware from 'redux-promise-middleware';
 import thunk from 'redux-thunk';
 import * as sinon from 'sinon';
-
-import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
 <%_ if (pagination === 'infinite-scroll') { _%>
 import { parseHeaderForLinks } from 'react-jhipster';
 <%_ } _%>
 
+import reducer, {
+  ACTION_TYPES, createEntity, deleteEntity, getEntities, getEntity, updateEntity<% if (pagination === 'infinite-scroll') { %>, reset<% } %>
+} from 'app/entities/<%= entityFolderName %>/<%= entityFileName %>.reducer';
+import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
+
 // tslint:disable no-invalid-template-strings
 describe('Entities reducer tests', () => {
 
@@ -296,10 +294,10 @@ describe('Entities reducer tests', () => {
     });
   });
 
-  <%_ if (hasBlob) { _%>
-  describe('Blobs', () => {
+  <%_ if (fieldsContainBlob) { _%>
+  describe('blobFields', () => {
     <%_
-    blobs.forEach(b => {
+    blobFields.forEach(b => {
       const nameToUpper = b.fieldName.toUpperCase();
     _%>
     it('should properly set <%= b.fieldName %> in state.', () => {