Skip to content

Commit

Permalink
Merge pull request #545 from OpenSRP/runtime-configuration
Browse files Browse the repository at this point in the history
Dockerize web app
  • Loading branch information
KipSigei authored Apr 20, 2021
2 parents e583bd2 + f45a9fd commit fa04c85
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 91 deletions.
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
**/*.db
**/.env
**/.env.development.local
**/.env.local
**/.env.production.local
**/.env.test.local
**/.git*
**/.waypoint
**/build
**/dist
**/node_modules
**/npm-debug.log
.dckerignore
Dockerfile
README.md
docs
waypoint.hcl
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ build
.env.development.local
.env.test.local
.env.production.local
*.db

debug.log*
npm-debug.log*
Expand Down
70 changes: 70 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
FROM alpine/git AS sources

RUN git clone --depth=1 --branch=config-sessions https://github.com/onaio/express-server.git /usr/src/express-server

FROM node:14.9.0-alpine as build

COPY ./ /project

WORKDIR /project
ENV PATH /project/node_modules/.bin:$PATH

RUN chown -R node .
USER node

RUN cp /project/app/.env.sample /project/app/.env \
&& yarn

USER root
RUN chown -R node .
USER node
RUN yarn lerna:prepublish

FROM node:14.9.0-alpine as nodejsbuild
COPY --from=sources /usr/src/express-server /usr/src/express-server

WORKDIR /usr/src/express-server
RUN yarn && yarn tsc && npm prune -production
RUN yarn add lodash && npm prune -production

# Remove unused dependencies
RUN rm -rf ./node_modules/typescript

FROM node:14.9.0-alpine as final

# Use tini for NodeJS application https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals
RUN apk add --no-cache tini curl

# confd
RUN curl -sSL -o /usr/local/bin/confd https://github.com/kelseyhightower/confd/releases/download/v0.16.0/confd-0.16.0-linux-amd64 \
&& chmod +x /usr/local/bin/confd

COPY ./docker/confd_env.toml /etc/confd/conf.d/appconfig.toml
COPY ./docker/config.js.tmpl /etc/confd/templates/config.js.tmpl

COPY ./docker/app.sh /usr/local/bin/app.sh
RUN chmod +x /usr/local/bin/app.sh

WORKDIR /usr/src/web

COPY --from=build /project/node_modules /usr/src/web/node_modules
COPY --from=build /project/app/build /usr/src/web

RUN chown -R node /usr/src/web

WORKDIR /usr/src/app

COPY --from=nodejsbuild /usr/src/express-server/dist /usr/src/app
COPY --from=nodejsbuild /usr/src/express-server/node_modules /usr/src/app/node_modules

RUN chown -R node /usr/src/app

USER node

ENV EXPRESS_REACT_BUILD_PATH /usr/src/web/

EXPOSE 3000

CMD [ "/bin/sh", "-c", "/usr/local/bin/app.sh && node ." ]

ENTRYPOINT ["/sbin/tini", "--"]
1 change: 1 addition & 0 deletions app/public/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window._env_ = {};
1 change: 1 addition & 0 deletions app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="opensrp-root"></div>
<script src="%PUBLIC_URL%/config.js?t=CONFIG_VERSION"></script>
</body>
</html>
210 changes: 119 additions & 91 deletions app/src/configs/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,134 +15,162 @@ const defaultRoles = {
FORM_CONFIGURATION: Roles.ROLE_VIEW_KEYCLOAK_USERS,
};

export const WEBSITE_NAME = process.env.REACT_APP_WEBSITE_NAME || 'OpenSRP Web';

export const BACKEND_ACTIVE = process.env.REACT_APP_BACKEND_ACTIVE === 'true';
export const OPENSRP_ROLES =
(process.env.REACT_APP_OPENSRP_ROLES &&
JSON.parse(process.env.REACT_APP_OPENSRP_ROLES as string)) ||
defaultRoles;

export const OPENSRP_LOGOUT_URL =
process.env.REACT_APP_OPENSRP_LOGOUT_URL ||
'https://opensrp-stage.smartregister.org/opensrp/logout.do';
export const OPENSRP_OAUTH_STATE = process.env.REACT_APP_OPENSRP_OAUTH_STATE || 'opensrp';
export const ENABLE_OPENSRP_OAUTH = process.env.REACT_APP_ENABLE_OPENSRP_OAUTH === 'true';
/** Returns a value in window._env_ or process.env or the defaultValue passed in.
*
* @param name - The configurable name that is a property of the environment/configuration.
* @param defaultValue - The default value to return the value is not defined in process.env and window._env_.
*/
export const setEnv = (name: string, defaultValue: any) => {
const { [name]: envValue } = process.env;
const value = typeof envValue === 'undefined' ? defaultValue : envValue;

if (typeof (window as any)._env_ === 'undefined') {
return value;
}
const { [name]: confValue } = (window as any)._env_;

return confValue === undefined ? value : confValue;
};

// notice the ending is NOT / here
export const OPENSRP_ACCESS_TOKEN_URL =
process.env.REACT_APP_OPENSRP_ACCESS_TOKEN_URL ||
'https://reveal-stage.smartregister.org/opensrp/oauth/token';
export const WEBSITE_NAME = setEnv('REACT_APP_WEBSITE_NAME', 'OpenSRP Web');

// notice the ending is NOT / here
export const OPENSRP_AUTHORIZATION_URL =
process.env.REACT_APP_OPENSRP_AUTHORIZATION_URL ||
'https://reveal-stage.smartregister.org/opensrp/oauth/authorize';
export const ENABLE_CARD_SUPPORT = setEnv('REACT_APP_ENABLE_CARD_SUPPORT', 'false') === 'true';

export const OPENSRP_CLIENT_ID = process.env.REACT_APP_OPENSRP_CLIENT_ID || '';
export const ENABLE_PLANS = setEnv('REACT_APP_ENABLE_PLANS', 'false') === 'true';

export const OPENSRP_OAUTH_SCOPES = (
process.env.REACT_APP_OPENSRP_OAUTH_SCOPES ?? 'read,write'
).split(',');
/** Activate the teams menu */
export const ENABLE_TEAMS = setEnv('REACT_APP_ENABLE_TEAMS', 'false') === 'true';

/** The domain name */
export const DOMAIN_NAME = process.env.REACT_APP_DOMAIN_NAME || 'http://localhost:3000';
/** Activate the plans menu */
export const ENABLE_LOCATIONS = setEnv('REACT_APP_ENABLE_LOCATIONS', 'false') === 'true';
export const OPENSRP_OAUTH_SCOPES = setEnv('REACT_APP_OPENSRP_OAUTH_SCOPES', 'read,write').split(
','
);

export const OPENSRP_USER_URL =
process.env.REACT_APP_OPENSRP_USER_URL ||
'https://reveal-stage.smartregister.org/opensrp/user-details';
export const DEFAULT_ACTIVITY_DURATION_DAYS = setEnv('REACT_APP_DEFAULT_ACTIVITY_DURATION_DAYS', 7);

export const NAVBAR_BRAND_IMG_SRC =
process.env.REACT_APP_NAVBAR_BRAND_IMG_SRC ||
'https://github.com/OpenSRP/opensrp-web/raw/master/clients/core/src/assets/images/logo.png';
export const PLAN_UUID_NAMESPACE = setEnv('REACT_APP_PLAN_UUID_NAMESPACE', '');

export const KEYCLOAK_LOGOUT_URL =
process.env.REACT_APP_KEYCLOAK_LOGOUT_URL ||
'https://keycloak-stage.smartregister.org/auth/realms/opensrp-web-stage/protocol/openid-connect/logout';
export const ACTION_UUID_NAMESPACE = setEnv('REACT_APP_ACTION_UUID_NAMESPACE', '');

export const OPENSRP_API_BASE_URL =
process.env.REACT_APP_OPENSRP_API_BASE_URL ||
'https://opensrp-stage.smartregister.org/opensrp/rest/';
export const DEFAULT_PLAN_VERSION = setEnv('REACT_APP_DEFAULT_PLAN_VERSION', '1');

export const KEYCLOAK_API_BASE_URL =
process.env.REACT_APP_KEYCLOAK_API_BASE_URL ||
'https://keycloak-stage.smartregister.org/auth/admin/realms/opensrp-web-stage';
export const TASK_GENERATION_STATUS = setEnv('REACT_APP_TASK_GENERATION_STATUS', 'internal');

/** Express server settings */
export const EXPRESS_OAUTH_GET_STATE_URL =
process.env.REACT_APP_EXPRESS_OAUTH_GET_STATE_URL || 'http://localhost:3000/oauth/state';
export const PLAN_ASSIGNMENT_AT_GEO_LEVEL = setEnv('REACT_APP_PLAN_ASSIGNMENT_AT_GEO_LEVEL', 0);

export const EXPRESS_OAUTH_LOGOUT_URL =
process.env.REACT_APP_EXPRESS_OAUTH_LOGOUT_URL || 'http://localhost:3000/logout';
export const MAIN_LOGO_SRC = setEnv(
'REACT_APP_MAIN_LOGO_SRC',
'https://github.com/OpenSRP/web/raw/master/app/src/assets/images/opensrp-logo-color.png'
);

/** Sentry */
export const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN || '';
/** Do you want to disable login protection? */
export const DISABLE_LOGIN_PROTECTION = process.env.REACT_APP_DISABLE_LOGIN_PROTECTION === 'true';
export const DATE_FORMAT = setEnv('REACT_APP_DATE_FORMAT', 'yyyy-MM-DD');

/** Activate the product-catalogue menu */
export const ENABLE_PRODUCT_CATALOGUE = process.env.REACT_APP_ENABLE_PRODUCT_CATALOGUE === 'true';
export const DEFAULT_TIME = setEnv('REACT_APP_DEFAULT_TIME', 'T00:00:00+00:00');

export const DEFAULT_PLAN_DURATION_DAYS = setEnv('REACT_APP_DEFAULT_PLAN_DURATION_DAYS', 20);
/** Activate teams menu */
export const ENABLE_TEAMS_MODULE = process.env.REACT_APP_ENABLE_TEAMS_MODULE === 'true';

/** Activate teams assignment menu */
export const ENABLE_TEAMS_ASSIGNMENT_MODULE =
process.env.REACT_APP_ENABLE_TEAMS_ASSIGNMENT_MODULE === 'true';
export const ENABLE_TEAMS_MODULE = setEnv('REACT_APP_ENABLE_TEAMS_MODULE', 'false') === 'true';

/** Default plan id */
export const DEFAULT_PLAN_ID =
process.env.REACT_APP_DEFAULT_PLAN_ID || '27362060-0309-411a-910c-64f55ede3758';
/** Activate card support menu */
export const ENABLE_CARD_SUPPORT = process.env.REACT_APP_ENABLE_CARD_SUPPORT === 'true';
/** Activate the plans menu */
export const ENABLE_PLANS = process.env.REACT_APP_ENABLE_PLANS === 'true';
export const DEFAULT_PLAN_ID = setEnv(
'REACT_APP_DEFAULT_PLAN_ID',
'27362060-0309-411a-910c-64f55ede3758'
);

/** Activate the teams menu */
export const ENABLE_TEAMS = process.env.REACT_APP_ENABLE_TEAMS === 'true';
export const BACKEND_ACTIVE = setEnv('REACT_APP_BACKEND_ACTIVE', 'false') === 'true';

/** Activate the plans menu */
export const ENABLE_LOCATIONS = process.env.REACT_APP_ENABLE_LOCATIONS === 'true';
export const OPENSRP_LOGOUT_URL = setEnv(
'REACT_APP_OPENSRP_LOGOUT_URL',
'https://opensrp-stage.smartregister.org/opensrp/logout.do'
);
export const OPENSRP_OAUTH_STATE = setEnv('REACT_APP_OPENSRP_OAUTH_STATE', 'opensrp');
export const ENABLE_OPENSRP_OAUTH = setEnv('REACT_APP_ENABLE_OPENSRP_OAUTH', 'false') === 'true';

// notice the ending is NOT / here
export const OPENSRP_ACCESS_TOKEN_URL = setEnv(
'REACT_APP_OPENSRP_ACCESS_TOKEN_URL',
'https://opensrp-stage.smartregister.org/opensrp/oauth/token'
);

// notice the ending is NOT / here
export const OPENSRP_AUTHORIZATION_URL = setEnv(
'REACT_APP_OPENSRP_AUTHORIZATION_URL',
'https://opensrp-stage.smartregister.org/opensrp/oauth/authorize'
);

export const DATE_FORMAT = process.env.REACT_APP_DATE_FORMAT || 'yyyy-MM-DD';
export const OPENSRP_CLIENT_ID = setEnv('REACT_APP_OPENSRP_CLIENT_ID', '');

export const DEFAULT_TIME = process.env.REACT_APP_DEFAULT_TIME || 'T00:00:00+00:00';
/** The domain name */
export const DOMAIN_NAME = setEnv('REACT_APP_DOMAIN_NAME', 'http://localhost:3000');

export const DEFAULT_PLAN_DURATION_DAYS = process.env.REACT_APP_DEFAULT_PLAN_DURATION_DAYS || 20;
export const OPENSRP_USER_URL = setEnv(
'REACT_APP_OPENSRP_USER_URL',
'https://opensrp-stage.smartregister.org/opensrp/user-details'
);

export const DEFAULT_ACTIVITY_DURATION_DAYS =
process.env.REACT_APP_DEFAULT_ACTIVITY_DURATION_DAYS || 7;
export const NAVBAR_BRAND_IMG_SRC = setEnv(
'REACT_APP_NAVBAR_BRAND_IMG_SRC',
'https://github.com/OpenSRP/opensrp-web/raw/master/clients/core/src/assets/images/logo.png'
);

export const OPENSRP_ROLES =
(process.env.REACT_APP_OPENSRP_ROLES &&
JSON.parse(process.env.REACT_APP_OPENSRP_ROLES as string)) ||
defaultRoles;
export const KEYCLOAK_LOGOUT_URL = setEnv(
'REACT_APP_KEYCLOAK_LOGOUT_URL',
'https://keycloak-stage.smartregister.org/auth/realms/opensrp-web-stage/protocol/openid-connect/logout'
);

export const OPENSRP_API_BASE_URL = setEnv(
'REACT_APP_OPENSRP_API_BASE_URL',
'https://opensrp-stage.smartregister.org/opensrp/rest/'
);

export const PLAN_UUID_NAMESPACE =
process.env.REACT_APP_PLAN_UUID_NAMESPACE || '85f7dbbf-07d0-4c92-aa2d-d50d141dde00';
export const KEYCLOAK_API_BASE_URL = setEnv(
'REACT_APP_KEYCLOAK_API_BASE_URL',
'https://keycloak-stage.smartregister.org/auth/admin/realms/opensrp-web-stage'
);

/** Express server settings */
export const EXPRESS_OAUTH_GET_STATE_URL = setEnv(
'REACT_APP_EXPRESS_OAUTH_GET_STATE_URL',
'http://localhost:3000/oauth/state'
);

export const ACTION_UUID_NAMESPACE =
process.env.REACT_APP_ACTION_UUID_NAMESPACE || '35968df5-f335-44ae-8ae5-25804caa2d86';
export const EXPRESS_OAUTH_LOGOUT_URL = setEnv(
'REACT_APP_EXPRESS_OAUTH_LOGOUT_URL',
'http://localhost:3000/logout'
);

export const DEFAULT_PLAN_VERSION = process.env.REACT_APP_DEFAULT_PLAN_VERSION || '1';
/** Do you want to disable login protection? */
export const DISABLE_LOGIN_PROTECTION =
setEnv('REACT_APP_DISABLE_LOGIN_PROTECTION', 'false') === 'true';

export const TASK_GENERATION_STATUS = process.env.REACT_APP_TASK_GENERATION_STATUS || 'internal';
/** Activate the product-catalogue menu */
export const ENABLE_PRODUCT_CATALOGUE =
setEnv('REACT_APP_ENABLE_PRODUCT_CATALOGUE', 'false') === 'true';

/** Activate form configuration */
export const ENABLE_FORM_CONFIGURATION = process.env.REACT_APP_ENABLE_FORM_CONFIGURATION === 'true';
export const ENABLE_FORM_CONFIGURATION =
setEnv('REACT_APP_ENABLE_FORM_CONFIGURATION', 'false') === 'true';

export const LANGUAGE_CODE = process.env.REACT_APP_LANGUAGE_CODE || 'en';
export const LANGUAGE_CODE = setEnv('REACT_APP_LANGUAGE_CODE', 'en');

export const PROJECT_LANGUAGE_CODE = process.env.REACT_APP_PROJECT_LANGUAGE_CODE || 'eusm';
export const PROJECT_LANGUAGE_CODE = setEnv('REACT_APP_PROJECT_LANGUAGE_CODE', 'eusm');

export const ENABLE_INVENTORY = process.env.REACT_APP_ENABLE_INVENTORY === 'true';
export const ENABLE_INVENTORY = setEnv('REACT_APP_ENABLE_INVENTORY', 'false') === 'true';

export const PLAN_ASSIGNMENT_AT_GEO_LEVEL = Number(
process.env.REACT_APP_PLAN_ASSIGNMENT_AT_GEO_LEVEL || '0'
);
export const SENTRY_DSN = setEnv('REACT_APP_SENTRY_DSN', '');

export const MAIN_LOGO_SRC =
process.env.REACT_APP_MAIN_LOGO_SRC ||
'https://github.com/OpenSRP/web/raw/master/app/src/assets/images/opensrp-logo-color.png';
export const SUPPORTED_LANGUAGES = setEnv('REACT_APP_SUPPORTED_LANGUAGES', '').split(',');

export const SUPPORTED_LANGUAGES = (process.env.REACT_APP_SUPPORTED_LANGUAGES ?? '').split(',');
export const ENABLE_LANGUAGE_SWITCHER =
setEnv('REACT_APP_ENABLE_LANGUAGE_SWITCHER', 'false') === 'true';

export const ENABLE_LANGUAGE_SWITCHER = process.env.REACT_APP_ENABLE_LANGUAGE_SWITCHER === 'true';
export const DEFAULT_HOME_MODE = setEnv('REACT_APP_DEFAULT_HOME_MODE', 'default');

export const DEFAULT_HOME_MODE = process.env.REACT_APP_DEFAULT_HOME_MODE || 'default';
export const ENABLE_TEAMS_ASSIGNMENT_MODULE =
setEnv('REACT_ENABLE_TEAMS_ASSIGNMENT_MODULE', 'false') === 'true';
7 changes: 7 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
web:
build: .
ports:
- "3000:3000"
environment:
- "API_URL=production.example.com"
8 changes: 8 additions & 0 deletions docker/app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
# vim:sw=4:ts=4:et

set -e

confd -onetime -backend env
sed -i "s/CONFIG_VERSION/`date '+%s'`/" /usr/src/web/index.html
sed -i "s/Redirected path should match configured path/Redirected path ' + Url.parse(options.redirectUri).pathname + 'should match configured path/" /usr/src/web/node_modules/client-oauth2/src/client-oauth2.js
Loading

0 comments on commit fa04c85

Please sign in to comment.