diff --git a/samples/react-java-mysql/backend/Dockerfile b/samples/react-java-mysql/backend/Dockerfile
new file mode 100755
index 0000000..265d758
--- /dev/null
+++ b/samples/react-java-mysql/backend/Dockerfile
@@ -0,0 +1,11 @@
+FROM maven:3.5-jdk-9 AS build
+COPY pom.xml .
+RUN mvn --batch-mode dependency:resolve
+COPY . .
+RUN mvn --batch-mode package
+RUN cp target/*jar target/app.jar
+
+FROM openjdk:9-jre
+VOLUME /tmp
+COPY --from=build target/app.jar app.jar
+ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
diff --git a/samples/react-java-mysql/backend/pom.xml b/samples/react-java-mysql/backend/pom.xml
new file mode 100755
index 0000000..aeef767
--- /dev/null
+++ b/samples/react-java-mysql/backend/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+ com.company
+ project
+ 0.0.1-SNAPSHOT
+ jar
+
+ New App
+ My new SpringBoot app
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.3.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jersey
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.session
+ spring-session-core
+
+
+ org.springframework.boot
+ spring-boot-devtools
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.projectlombok
+ lombok
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/samples/react-java-mysql/backend/src/main/java/com/company/project/Application.java b/samples/react-java-mysql/backend/src/main/java/com/company/project/Application.java
new file mode 100755
index 0000000..16b8c45
--- /dev/null
+++ b/samples/react-java-mysql/backend/src/main/java/com/company/project/Application.java
@@ -0,0 +1,16 @@
+package com.company.project;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@EnableAutoConfiguration
+@ComponentScan(basePackages = {"com.company.project"})
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/samples/react-java-mysql/backend/src/main/java/com/company/project/controllers/HomeController.java b/samples/react-java-mysql/backend/src/main/java/com/company/project/controllers/HomeController.java
new file mode 100755
index 0000000..966839d
--- /dev/null
+++ b/samples/react-java-mysql/backend/src/main/java/com/company/project/controllers/HomeController.java
@@ -0,0 +1,16 @@
+package com.company.project.controllers;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@Controller
+public class HomeController {
+
+ @GetMapping("/")
+ public String showHome(String name, Model model) {
+ return "home";
+ }
+
+}
diff --git a/samples/react-java-mysql/backend/src/main/resources/application.properties b/samples/react-java-mysql/backend/src/main/resources/application.properties
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/samples/react-java-mysql/backend/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/samples/react-java-mysql/backend/src/main/resources/templates/home.ftl b/samples/react-java-mysql/backend/src/main/resources/templates/home.ftl
new file mode 100755
index 0000000..daba182
--- /dev/null
+++ b/samples/react-java-mysql/backend/src/main/resources/templates/home.ftl
@@ -0,0 +1,9 @@
+
+
+
+ Getting Started: Serving Web Content
+
+
+
+ Hello from Docker!
+
diff --git a/samples/react-java-mysql/db/password.txt b/samples/react-java-mysql/db/password.txt
new file mode 100644
index 0000000..e9031c9
--- /dev/null
+++ b/samples/react-java-mysql/db/password.txt
@@ -0,0 +1 @@
+db-57xsl
\ No newline at end of file
diff --git a/samples/react-java-mysql/docker-compose.yaml b/samples/react-java-mysql/docker-compose.yaml
new file mode 100644
index 0000000..f2621d6
--- /dev/null
+++ b/samples/react-java-mysql/docker-compose.yaml
@@ -0,0 +1,26 @@
+version: "3.7"
+services:
+ backend:
+ build: backend
+ db:
+ environment:
+ MYSQL_DATABASE: example
+ MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db-password
+ image: mysql:5.7
+ restart: always
+ secrets:
+ - db-password
+ volumes:
+ - db-data:/var/lib/mysql
+ frontend:
+ build: frontend
+ ports:
+ - 80:9000
+ volumes:
+ - ./frontend:/project
+ - /project/node_modules
+volumes:
+ db-data: {}
+secrets:
+ db-password:
+ file: db/password.txt
diff --git a/samples/react-java-mysql/frontend/.babelrc b/samples/react-java-mysql/frontend/.babelrc
new file mode 100755
index 0000000..75f783d
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.babelrc
@@ -0,0 +1,23 @@
+{
+ "presets": [
+ [
+ "env",
+ {
+ "loose": true,
+ "modules": false
+ }
+ ],
+ "react"
+ ],
+ "plugins": [
+ "react-hot-loader/babel",
+ "transform-runtime",
+ "transform-object-rest-spread",
+ "lodash"
+ ],
+ "env": {
+ "test": {
+ "plugins": ["transform-es2015-modules-commonjs"]
+ }
+ }
+}
diff --git a/samples/react-java-mysql/frontend/.browserslistrc b/samples/react-java-mysql/frontend/.browserslistrc
new file mode 100755
index 0000000..7e8de1c
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.browserslistrc
@@ -0,0 +1,5 @@
+> 1%
+last 3 versions
+Firefox ESR
+Opera 12.1
+IE >= 10
\ No newline at end of file
diff --git a/samples/react-java-mysql/frontend/.dockerignore b/samples/react-java-mysql/frontend/.dockerignore
new file mode 100755
index 0000000..e1d19f6
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.dockerignore
@@ -0,0 +1,2 @@
+node_modules
+.happypack
diff --git a/samples/react-java-mysql/frontend/.eslintignore b/samples/react-java-mysql/frontend/.eslintignore
new file mode 100755
index 0000000..ba224b4
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.eslintignore
@@ -0,0 +1 @@
+webpack/*
diff --git a/samples/react-java-mysql/frontend/.eslintrc b/samples/react-java-mysql/frontend/.eslintrc
new file mode 100755
index 0000000..d61ab73
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.eslintrc
@@ -0,0 +1,36 @@
+{
+ "extends": [
+ "standard",
+ "standard-react",
+ "plugin:jsx-a11y/recommended"
+ ],
+ "env": {
+ "es6" : true,
+ "browser" : true,
+ "node" : true,
+ "jest" : true
+ },
+ "plugins": [
+ "react",
+ "import"
+ ],
+ "parser": "babel-eslint",
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "rules" : {
+ "no-eq-null" : 0,
+ "quotes": 0,
+ "eol-last": 0,
+ "semi": [2, "always"],
+ "key-spacing": [1, {"beforeColon": true, "afterColon": true, "mode": "minimum", "align": "colon"}],
+ "padded-blocks": [1, { "switches": "never", "classes" : "always"}],
+ "space-before-function-paren": ["error", "never"],
+ "indent": [1, 4]
+ },
+ "globals" : {
+ "__DEV__" : false,
+ "__filename" : false,
+ "__dirname" : false
+ }
+}
diff --git a/samples/react-java-mysql/frontend/.gitignore b/samples/react-java-mysql/frontend/.gitignore
new file mode 100755
index 0000000..1285d59
--- /dev/null
+++ b/samples/react-java-mysql/frontend/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+.happypack
+build/*
+dist/*
diff --git a/samples/react-java-mysql/frontend/Dockerfile b/samples/react-java-mysql/frontend/Dockerfile
new file mode 100755
index 0000000..26ed305
--- /dev/null
+++ b/samples/react-java-mysql/frontend/Dockerfile
@@ -0,0 +1,9 @@
+FROM node:10
+
+RUN mkdir /project
+WORKDIR /project
+
+COPY . .
+
+RUN yarn install
+CMD ["yarn", "run", "start"]
diff --git a/samples/react-java-mysql/frontend/Dockerfile.production b/samples/react-java-mysql/frontend/Dockerfile.production
new file mode 100755
index 0000000..85b11ed
--- /dev/null
+++ b/samples/react-java-mysql/frontend/Dockerfile.production
@@ -0,0 +1,12 @@
+FROM node:10 as build
+
+RUN mkdir /project
+WORKDIR /project
+COPY . .
+RUN yarn install
+RUN yarn run package
+
+FROM nginx:1.13-alpine
+
+COPY config/nginx.conf /etc/nginx/conf.d/default.conf
+COPY --from=build /project/dist /usr/share/nginx/html
diff --git a/samples/react-java-mysql/frontend/README.md b/samples/react-java-mysql/frontend/README.md
new file mode 100755
index 0000000..7ddbcd4
--- /dev/null
+++ b/samples/react-java-mysql/frontend/README.md
@@ -0,0 +1 @@
+# Sample App
diff --git a/samples/react-java-mysql/frontend/config/nginx.conf b/samples/react-java-mysql/frontend/config/nginx.conf
new file mode 100755
index 0000000..2a3646c
--- /dev/null
+++ b/samples/react-java-mysql/frontend/config/nginx.conf
@@ -0,0 +1,9 @@
+server {
+ listen 9000;
+ server_name localhost;
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ }
+}
diff --git a/samples/react-java-mysql/frontend/jest.config.js b/samples/react-java-mysql/frontend/jest.config.js
new file mode 100755
index 0000000..2b518a6
--- /dev/null
+++ b/samples/react-java-mysql/frontend/jest.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ "moduleFileExtensions": [
+ "js",
+ "jsx",
+ "json"
+ ],
+ "moduleDirectories": [
+ "node_modules",
+ "src"
+ ],
+ "moduleNameMapper": {
+ "^.+\\.(css|scss)$": "/test/mocks/styleMock.js",
+ "^.+\\.(jpg|jpeg|gif|png|svg|eot|ttf|woff|woff2|)$": "/test/mocks/imageMock.js"
+ }
+};
diff --git a/samples/react-java-mysql/frontend/package.json b/samples/react-java-mysql/frontend/package.json
new file mode 100755
index 0000000..ed2ef83
--- /dev/null
+++ b/samples/react-java-mysql/frontend/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "react-app",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "clean": "rimraf ./dist/* && rimraf ./build/*",
+ "start": "cross-env NODE_ENV=development node webpack/dev-server.js",
+ "build": "cross-env NODE_ENV=development webpack --config webpack.config.js",
+ "package": "cross-env NODE_ENV=production webpack --config webpack.config.js",
+ "test": "cross-env NODE_ENV=test jest",
+ "lint:js": "eslint ./src"
+ },
+ "dependencies": {
+ "express": "4.16.3",
+ "axios": "0.18.0",
+ "classnames": "2.2.5",
+ "lodash": "4.17.5",
+ "moment": "2.20.0",
+ "history": "4.7.2",
+ "react": "^16.8.6",
+ "react-dom": "^16.8.6",
+ "react-redux": "^5.1.1",
+ "react-router-dom": "^4.3.1",
+ "react-router-redux": "5.0.0-alpha.8",
+ "redux": "^3.7.2",
+ "redux-actions": "^2.6.5",
+ "redux-saga": "0.16.0",
+ "reselect": "3.0.1",
+ "query-string": "6.0.0"
+ },
+ "devDependencies": {
+ "rimraf": "2.6.1",
+ "cross-env": "5.1.4",
+ "webpack": "4.5.0",
+ "webpack-cli": "3.3.1",
+ "webpack-dev-server": "3.1.3",
+ "html-webpack-plugin": "3.2.0",
+ "mini-css-extract-plugin": "0.4.0",
+ "react-hot-loader": "3.1.3",
+ "node-sass": "^4.11.0",
+ "babel-core": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "babel-loader": "7.1.4",
+ "babel-preset-env": "^1.7.0",
+ "babel-eslint": "8.2.2",
+ "babel-preset-react": "6.24.1",
+ "babel-plugin-transform-runtime": "6.23.0",
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
+ "babel-plugin-lodash": "3.3.2",
+ "css-loader": "^2.1.1",
+ "sass-loader": "6.0.7",
+ "style-loader": "0.20.3",
+ "file-loader": "1.1.11",
+ "postcss-loader": "2.1.3",
+ "autoprefixer": "8.2.0",
+ "cssnano": "4.1.10",
+ "identity-obj-proxy": "3.0.0",
+ "jest": "^20.0.4",
+ "jest-cli": "^20.0.4",
+ "babel-jest": "20.0.3",
+ "eslint": "4.19.1",
+ "eslint-config-standard": "^10.2.1",
+ "eslint-config-standard-react": "^5.0.0",
+ "eslint-loader": "^1.9.0",
+ "eslint-plugin-import": "^2.7.0",
+ "eslint-plugin-node": "^5.1.1",
+ "eslint-plugin-promise": "^3.3.0",
+ "eslint-plugin-react": "7.1.0",
+ "eslint-plugin-jsx-a11y": "6.0.2",
+ "eslint-plugin-standard": "3.0.1"
+ }
+}
diff --git a/samples/react-java-mysql/frontend/src/app/app.jsx b/samples/react-java-mysql/frontend/src/app/app.jsx
new file mode 100755
index 0000000..46b085d
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/app.jsx
@@ -0,0 +1,22 @@
+import * as React from "react"
+import { Switch } from "react-router-dom"
+import { renderRoutes } from "./routes"
+
+import { ApplicationContainer } from "app/components/layout"
+
+require("./core/styles/reset.css");
+require("./core/styles/normalize.scss");
+//require("./core/styles/main.scss");
+
+export class App extends React.Component {
+ render() {
+ return (
+
+
+ {renderRoutes()}
+
+
+ )
+ }
+}
+
diff --git a/samples/react-java-mysql/frontend/src/app/components/layout/ApplicationContainer.jsx b/samples/react-java-mysql/frontend/src/app/components/layout/ApplicationContainer.jsx
new file mode 100755
index 0000000..b80df40
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/components/layout/ApplicationContainer.jsx
@@ -0,0 +1,15 @@
+import * as React from "react";
+
+export default class ApplicationContainer extends React.Component {
+
+ render() {
+ return (
+
+
+ {this.props.children}
+
+
+ );
+ }
+
+}
diff --git a/samples/react-java-mysql/frontend/src/app/components/layout/index.js b/samples/react-java-mysql/frontend/src/app/components/layout/index.js
new file mode 100755
index 0000000..0274124
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/components/layout/index.js
@@ -0,0 +1,5 @@
+import ApplicationContainer from "./ApplicationContainer";
+
+export {
+ ApplicationContainer,
+}
diff --git a/samples/react-java-mysql/frontend/src/app/core/styles/normalize.scss b/samples/react-java-mysql/frontend/src/app/core/styles/normalize.scss
new file mode 100755
index 0000000..a2e9c64
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/core/styles/normalize.scss
@@ -0,0 +1,396 @@
+/*! normalize.css v2.1.0 | MIT License | git.io/normalize */
+
+// ==========================================================================
+// HTML5 display definitions
+// ==========================================================================
+
+//
+// Correct `block` display not defined in IE 8/9.
+//
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+//
+// Correct `inline-block` display not defined in IE 8/9.
+//
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+//
+// Prevent modern browsers from displaying `audio` without controls.
+// Remove excess height in iOS 5 devices.
+//
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+//
+// Address styling not present in IE 8/9.
+//
+
+[hidden] {
+ display: none;
+}
+
+// ==========================================================================
+// Base
+// ==========================================================================
+
+//
+// 1. Set default font family to sans-serif.
+// 2. Prevent iOS text size adjust after orientation change, without disabling
+// user zoom.
+//
+
+html {
+ font-family: sans-serif; // 1
+ -webkit-text-size-adjust: 100%; // 2
+ -ms-text-size-adjust: 100%; // 2
+}
+
+//
+// Remove default margin.
+//
+
+body {
+ margin: 0;
+}
+
+// ==========================================================================
+// Links
+// ==========================================================================
+
+//
+// Address `outline` inconsistency between Chrome and other browsers.
+//
+
+a:focus {
+ outline: thin dotted;
+}
+
+//
+// Improve readability when focused and also mouse hovered in all browsers.
+//
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+// ==========================================================================
+// Typography
+// ==========================================================================
+
+//
+// Address variable `h1` font-size and margin within `section` and `article`
+// contexts in Firefox 4+, Safari 5, and Chrome.
+//
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+//
+// Address styling not present in IE 8/9, Safari 5, and Chrome.
+//
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+//
+// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+//
+
+b,
+strong {
+ font-weight: bold;
+}
+
+//
+// Address styling not present in Safari 5 and Chrome.
+//
+
+dfn {
+ font-style: italic;
+}
+
+//
+// Address differences between Firefox and other browsers.
+//
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+//
+// Address styling not present in IE 8/9.
+//
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+//
+// Correct font family set oddly in Safari 5 and Chrome.
+//
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+//
+// Improve readability of pre-formatted text in all browsers.
+//
+
+pre {
+ white-space: pre-wrap;
+}
+
+//
+// Set consistent quote types.
+//
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+//
+// Address inconsistent and variable font size in all browsers.
+//
+
+small {
+ font-size: 80%;
+}
+
+//
+// Prevent `sub` and `sup` affecting `line-height` in all browsers.
+//
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+// ==========================================================================
+// Embedded content
+// ==========================================================================
+
+//
+// Remove border when inside `a` element in IE 8/9.
+//
+
+img {
+ border: 0;
+}
+
+//
+// Correct overflow displayed oddly in IE 9.
+//
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+// ==========================================================================
+// Figures
+// ==========================================================================
+
+//
+// Address margin not present in IE 8/9 and Safari 5.
+//
+
+figure {
+ margin: 0;
+}
+
+// ==========================================================================
+// Forms
+// ==========================================================================
+
+//
+// Define consistent border, margin, and padding.
+//
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+//
+// 1. Correct `color` not being inherited in IE 8/9.
+// 2. Remove padding so people aren't caught out if they zero out fieldsets.
+//
+
+legend {
+ border: 0; // 1
+ padding: 0; // 2
+}
+
+//
+// 1. Correct font family not being inherited in all browsers.
+// 2. Correct font size not being inherited in all browsers.
+// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+//
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; // 1
+ font-size: 100%; // 2
+ margin: 0; // 3
+}
+
+//
+// Address Firefox 4+ setting `line-height` on `input` using `!important` in
+// the UA stylesheet.
+//
+
+button,
+input {
+ line-height: normal;
+}
+
+//
+// Address inconsistent `text-transform` inheritance for `button` and `select`.
+// All other form control elements do not inherit `text-transform` values.
+// Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
+// Correct `select` style inheritance in Firefox 4+ and Opera.
+//
+
+button,
+select {
+ text-transform: none;
+}
+
+//
+// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+// and `video` controls.
+// 2. Correct inability to style clickable `input` types in iOS.
+// 3. Improve usability and consistency of cursor style between image-type
+// `input` and others.
+//
+
+button,
+html input[type="button"], // 1
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; // 2
+ cursor: pointer; // 3
+}
+
+//
+// Re-set default cursor for disabled elements.
+//
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+//
+// 1. Address box sizing set to `content-box` in IE 8/9.
+// 2. Remove excess padding in IE 8/9.
+//
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; // 1
+ padding: 0; // 2
+}
+
+//
+// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+// (include `-moz` to future-proof).
+//
+
+input[type="search"] {
+ -webkit-appearance: textfield; // 1
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; // 2
+ box-sizing: content-box;
+}
+
+//
+// Remove inner padding and search cancel button in Safari 5 and Chrome
+// on OS X.
+//
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+//
+// Remove inner padding and border in Firefox 4+.
+//
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+//
+// 1. Remove default vertical scrollbar in IE 8/9.
+// 2. Improve readability and alignment in all browsers.
+//
+
+textarea {
+ overflow: auto; // 1
+ vertical-align: top; // 2
+}
+
+// ==========================================================================
+// Tables
+// ==========================================================================
+
+//
+// Remove most spacing between table cells.
+//
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
diff --git a/samples/react-java-mysql/frontend/src/app/core/styles/reset.css b/samples/react-java-mysql/frontend/src/app/core/styles/reset.css
new file mode 100755
index 0000000..d9f27b5
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/core/styles/reset.css
@@ -0,0 +1,48 @@
+/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
diff --git a/samples/react-java-mysql/frontend/src/app/entry.jsx b/samples/react-java-mysql/frontend/src/app/entry.jsx
new file mode 100755
index 0000000..d3360fa
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/entry.jsx
@@ -0,0 +1,39 @@
+import * as React from "react";
+import { render, unmountComponentAtNode } from "react-dom"
+import { AppContainer } from "react-hot-loader"
+import { Provider } from 'react-redux';
+import { ConnectedRouter } from "react-router-redux"
+import { createBrowserHistory } from "history"
+
+import { configureStore, sagaMiddleware } from "./store"
+import { runApplicationSagas } from "./sagas"
+
+const history = createBrowserHistory();
+const store = configureStore(history);
+
+const getAppContainer = () => document.getElementById('app-container');
+
+const renderApp = () => {
+ const App = require('./app').App;
+ render(
+
+
+
+
+
+
+
+ , getAppContainer());
+};
+
+if (__DEV__ && module.hot) {
+ const hotReloadApp = () => renderApp();
+ module.hot.accept('./app', () => {
+ // Preventing the hot reloading error from react-router
+ unmountComponentAtNode(getAppContainer());
+ hotReloadApp();
+ })
+}
+
+// runApplicationSagas(sagaMiddleware);
+renderApp();
diff --git a/samples/react-java-mysql/frontend/src/app/pages/home/HomePage.jsx b/samples/react-java-mysql/frontend/src/app/pages/home/HomePage.jsx
new file mode 100755
index 0000000..3b383b8
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/pages/home/HomePage.jsx
@@ -0,0 +1,26 @@
+import * as React from "react";
+import { connect } from "react-redux";
+
+require("./home.scss");
+
+const mapStateToProps = (state, props) => {
+ return {};
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {};
+};
+
+class HomePage extends React.Component {
+
+ render() {
+ return (
+
+
My New React App
+
+ )
+ }
+
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(HomePage)
diff --git a/samples/react-java-mysql/frontend/src/app/pages/home/home.scss b/samples/react-java-mysql/frontend/src/app/pages/home/home.scss
new file mode 100755
index 0000000..66f9f24
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/pages/home/home.scss
@@ -0,0 +1,6 @@
+
+
+.home-page {
+ background-color: blue;
+ color: red;
+}
diff --git a/samples/react-java-mysql/frontend/src/app/pages/home/index.js b/samples/react-java-mysql/frontend/src/app/pages/home/index.js
new file mode 100755
index 0000000..7f0bbf7
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/pages/home/index.js
@@ -0,0 +1,7 @@
+import * as React from "react";
+import { Route } from "react-router-dom";
+import HomePage from './HomePage';
+
+const route = ;
+
+export default route;
diff --git a/samples/react-java-mysql/frontend/src/app/reducers.js b/samples/react-java-mysql/frontend/src/app/reducers.js
new file mode 100755
index 0000000..67fce7e
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/reducers.js
@@ -0,0 +1,10 @@
+import { combineReducers } from 'redux';
+import { routerReducer } from 'react-router-redux';
+
+import whalesReducer from 'app/redux/whales';
+
+export const rootReducer = combineReducers({
+ router: routerReducer,
+
+ whales: whalesReducer,
+});
diff --git a/samples/react-java-mysql/frontend/src/app/redux/whales/action-creators.js b/samples/react-java-mysql/frontend/src/app/redux/whales/action-creators.js
new file mode 100755
index 0000000..afcb792
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/redux/whales/action-creators.js
@@ -0,0 +1,4 @@
+import { createAction } from 'redux-actions';
+import * as ActionTypes from "./action-types";
+
+export const fetchWhales = createAction(ActionTypes.FETCH_WHALES);
diff --git a/samples/react-java-mysql/frontend/src/app/redux/whales/action-types.js b/samples/react-java-mysql/frontend/src/app/redux/whales/action-types.js
new file mode 100755
index 0000000..ac21c38
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/redux/whales/action-types.js
@@ -0,0 +1,4 @@
+
+const prefix = 'WHALES';
+
+export const FETCH_WHALES = `${prefix}/FETCH`;
diff --git a/samples/react-java-mysql/frontend/src/app/redux/whales/index.js b/samples/react-java-mysql/frontend/src/app/redux/whales/index.js
new file mode 100755
index 0000000..db0e338
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/redux/whales/index.js
@@ -0,0 +1,3 @@
+import Reducer from './reducer';
+
+export default Reducer;
diff --git a/samples/react-java-mysql/frontend/src/app/redux/whales/reducer.js b/samples/react-java-mysql/frontend/src/app/redux/whales/reducer.js
new file mode 100755
index 0000000..eb24c92
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/redux/whales/reducer.js
@@ -0,0 +1,16 @@
+import * as ActionTypes from "./action-types";
+import { handleActions } from "redux-actions";
+
+const defaultState = {
+ list: [],
+};
+
+const handleFetchWhales = (state, {payload}) => {
+ return state;
+};
+
+const reducer = handleActions({
+ [ActionTypes.FETCH_WHALES] : handleFetchWhales
+}, defaultState);
+
+export default reducer;
diff --git a/samples/react-java-mysql/frontend/src/app/redux/whales/selectors.js b/samples/react-java-mysql/frontend/src/app/redux/whales/selectors.js
new file mode 100755
index 0000000..e69de29
diff --git a/samples/react-java-mysql/frontend/src/app/routes.jsx b/samples/react-java-mysql/frontend/src/app/routes.jsx
new file mode 100755
index 0000000..ee9f643
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/routes.jsx
@@ -0,0 +1,10 @@
+import * as React from "react";
+import Home from "./pages/home"
+
+const routes = [
+ Home,
+];
+
+export const renderRoutes = () => {
+ return routes;
+};
diff --git a/samples/react-java-mysql/frontend/src/app/sagas.js b/samples/react-java-mysql/frontend/src/app/sagas.js
new file mode 100755
index 0000000..772f08a
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/sagas.js
@@ -0,0 +1,9 @@
+//import { templatesSaga } from "./data/templates/sagas";
+//import { appWizardSaga } from "./data/app-wizard/sagas";
+
+const startupSagas = [
+];
+
+export const runApplicationSagas = (sagaMiddleware) => {
+ startupSagas.forEach(sagaMiddleware.run);
+};
diff --git a/samples/react-java-mysql/frontend/src/app/store.js b/samples/react-java-mysql/frontend/src/app/store.js
new file mode 100755
index 0000000..c5bdc31
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/app/store.js
@@ -0,0 +1,37 @@
+import { routerMiddleware } from 'react-router-redux';
+import { createStore, applyMiddleware, compose } from 'redux';
+import createSagaMiddleware from "redux-saga";
+import { rootReducer } from "./reducers";
+
+export const sagaMiddleware = createSagaMiddleware();
+
+export const configureStore = (history, initialState = {}) => {
+
+ const middlewares = [
+ routerMiddleware(history),
+ sagaMiddleware
+ ];
+
+ const enhancers = [
+ applyMiddleware(...middlewares),
+ ];
+
+ if(__DEV__) {
+ const devToolEnhancer = () => {
+ return typeof window === 'object' && typeof window.devToolsExtension !== 'undefined'
+ ? window.devToolsExtension() : f => f;
+ };
+ enhancers.push(devToolEnhancer())
+ }
+
+ const store = createStore(rootReducer, initialState, compose(...enhancers));
+
+ if(__DEV__ && module.hot) {
+ module.hot.accept('./reducers', () => {
+ const nextReducer = require('./reducers').default;
+ store.replaceReducer(nextReducer);
+ })
+ }
+
+ return store;
+};
diff --git a/samples/react-java-mysql/frontend/src/index.ejs b/samples/react-java-mysql/frontend/src/index.ejs
new file mode 100755
index 0000000..e1bfc09
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/index.ejs
@@ -0,0 +1,10 @@
+
+
+
+
+ Sample application
+
+
+
+
+
diff --git a/samples/react-java-mysql/frontend/src/test/mocks/imageMock.js b/samples/react-java-mysql/frontend/src/test/mocks/imageMock.js
new file mode 100755
index 0000000..6b78380
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/test/mocks/imageMock.js
@@ -0,0 +1,3 @@
+// Return an empty string or other mock path to emulate the url that
+// Webpack provides via the file-loader
+module.exports = 'mocked-image.jpg';
\ No newline at end of file
diff --git a/samples/react-java-mysql/frontend/src/test/mocks/styleMock.js b/samples/react-java-mysql/frontend/src/test/mocks/styleMock.js
new file mode 100755
index 0000000..f1eb8f5
--- /dev/null
+++ b/samples/react-java-mysql/frontend/src/test/mocks/styleMock.js
@@ -0,0 +1,2 @@
+// Return a Proxy to emulate css modules (if you are using them)
+module.exports = require('identity-obj-proxy');
\ No newline at end of file
diff --git a/samples/react-java-mysql/frontend/webpack.config.js b/samples/react-java-mysql/frontend/webpack.config.js
new file mode 100755
index 0000000..91f9355
--- /dev/null
+++ b/samples/react-java-mysql/frontend/webpack.config.js
@@ -0,0 +1 @@
+module.exports = require("./webpack/config-builder")(process.env.NODE_ENV || 'production');
diff --git a/samples/react-java-mysql/frontend/webpack/config-builder.js b/samples/react-java-mysql/frontend/webpack/config-builder.js
new file mode 100755
index 0000000..c07bc69
--- /dev/null
+++ b/samples/react-java-mysql/frontend/webpack/config-builder.js
@@ -0,0 +1,231 @@
+'use strict';
+
+const path = require('path'),
+ webpack = require('webpack'),
+ HtmlWebpackPlugin = require('html-webpack-plugin'),
+ MiniCssExtractPlugin = require("mini-css-extract-plugin");
+
+const PROJECT_ROOT = path.resolve(__dirname, "..");
+
+module.exports = (env) => {
+ const isDev = env === 'development';
+ const isTest = env === 'test';
+ const isProd = !isDev && !isTest;
+
+ const getAppEntry = () => {
+ const appEntry = path.resolve(PROJECT_ROOT, "src/app/entry.jsx");
+ if(isDev) {
+ return [
+ 'react-hot-loader/patch',
+ 'webpack-dev-server/client?http://localhost:9000',
+ 'webpack/hot/only-dev-server',
+ appEntry
+ ]
+ } else {
+ return [appEntry]
+ }
+ };
+
+ const getPlugins = () => {
+
+ // common plugins
+ let plugins = [
+ // Global variables
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify(env),
+ '__DEV__': isDev,
+ '__PROD__': isProd,
+ '__TEST__': isTest,
+ }),
+ // ignore moment locale files
+ new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
+ // extract styles to css file
+ new MiniCssExtractPlugin({
+ filename: "[name].[contenthash].css",
+ chunkFilename: "[id].css",
+ disable: isDev,
+ }),
+ // makes index.html
+ new HtmlWebpackPlugin({
+ template: path.resolve(PROJECT_ROOT, 'src/index.ejs'),
+ })
+ ];
+
+ // development plugins
+ if(isDev) {
+ plugins.push(
+ // Hot Reload (HMR)
+ new webpack.HotModuleReplacementPlugin(),
+ // Named Modules
+ new webpack.NamedModulesPlugin()
+ );
+ }
+
+ // production plugins
+ if(isProd) {
+ plugins.push(
+ new webpack.optimize.ModuleConcatenationPlugin()
+ );
+ }
+
+ return plugins;
+ };
+
+ return {
+ target: 'web',
+ mode: isProd ? "production" : "development",
+ context: PROJECT_ROOT,
+
+ entry: {
+ app: getAppEntry()
+ },
+
+ output: {
+ path: path.resolve(PROJECT_ROOT, isProd ? 'dist' : 'build'),
+ filename: isProd ? '[name].[chunkhash:8].js' : '[name].js',
+ publicPath: '/',
+ sourceMapFilename: '[file].map',
+ chunkFilename: isProd ? '[name].[chunkhash:8].js' : '[name].js',
+ pathinfo: isDev
+
+ },
+
+ devtool: isProd ? "hidden-sourcemap" : 'eval',
+
+ resolve: {
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ modules: ["node_modules", "src"],
+ alias: {}
+ },
+
+ module: {
+ rules: [
+ // JS / JSX files
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /(node_modules)/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ cacheDirectory: true
+ }
+ }
+ ]
+ },
+ // SASS files
+ {
+ test: /\.scss$/,
+ exclude: /(node_modules|bower_components)/,
+ use: [
+ isDev ? "style-loader" : MiniCssExtractPlugin.loader,
+ {
+ loader: "css-loader",
+ options: {
+ importLoaders: 2,
+ url: true,
+ import: false,
+ sourceMap: isDev
+ }
+ },
+ {
+ loader: "postcss-loader",
+ options: {
+ sourceMap: isDev,
+ plugins: isDev ? [] : [
+ require("autoprefixer"),
+ require("cssnano")({
+ safe: true,
+ zindex: false,
+ discardComments: {
+ removeAll: true
+ }
+ })
+ ]
+ }
+ },
+ {
+ loader: "sass-loader",
+ options: {
+ sourceMap: isDev,
+ includePaths: [".", path.join(process.cwd(), "src/app/core/styles")]
+ }
+ }
+ ]
+ },
+ // Plain CSS files
+ {
+ test: /\.css$/,
+ use: [
+ isDev ? "style-loader" : MiniCssExtractPlugin.loader,
+ {
+ loader: "css-loader",
+ options: {
+ importLoaders: 1,
+ url: true,
+ import: false,
+ sourceMap: isDev
+ }
+ },
+ {
+ loader: "postcss-loader",
+ options: {
+ sourceMap: isDev,
+ plugins: isDev ? [] : [
+ require("autoprefixer"),
+ require("cssnano")({
+ safe: true,
+ zindex: false,
+ discardComments: {
+ removeAll: true
+ }
+ })
+ ]
+ }
+ }
+ ]
+ },
+ // images loader
+ {
+ test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: "[name].[ext]",
+ outputPath: isProd ? "../images/" : "images/"
+ }
+ }
+ ]
+ },
+ // font loader
+ {
+ test: /\.(woff|woff2|ttf|eot)(\?.*)?$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: "[name].[ext]",
+ publicPath: isProd ? "" : "/webpack/",
+ useRelativePath: isProd,
+ outputPath: isProd ? "../fonts/" : "fonts/"
+ }
+ }
+ ]
+ }
+ ]
+ },
+
+ plugins: getPlugins(),
+
+ node: {
+ __filename: true,
+ __dirname: true,
+ fs: 'empty',
+ vm: 'empty',
+ net: 'empty',
+ tls: 'empty',
+ }
+
+ };
+};
diff --git a/samples/react-java-mysql/frontend/webpack/dev-server.js b/samples/react-java-mysql/frontend/webpack/dev-server.js
new file mode 100755
index 0000000..f40ec11
--- /dev/null
+++ b/samples/react-java-mysql/frontend/webpack/dev-server.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const webpack = require('webpack'),
+ WebpackDevServer = require('webpack-dev-server'),
+ makeConfig = require("./config-builder");
+
+const startWebpackServer = () => {
+ const config = makeConfig('development');
+
+ const SERVER_PORT = 9000;
+
+ new WebpackDevServer(webpack(config), {
+ publicPath : config.output.publicPath,
+ hot : true,
+ historyApiFallback : true,
+ contentBase : "./build/",
+
+ watchOptions: { // no file events on D4W
+ aggregateTimeout: 300,
+ poll: 1000
+ },
+
+ proxy : {
+ "/api/*" : "http://127.0.0.1:8080" // proxy to backend
+ },
+
+ before : function(app) {
+ // manually configure app `app.use(...)`
+ }
+ }).listen(SERVER_PORT, '0.0.0.0', function (err, result) {
+ if (err) {
+ console.log(err);
+ }
+ console.log('Webpack dev server listening at localhost:' + SERVER_PORT);
+ });
+};
+
+startWebpackServer();