diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 884ef874..f94e143c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,11 +8,9 @@ "ghcr.io/devcontainers/features/dotnet:2": {}, "ghcr.io/devcontainers/features/aws-cli:1": {}, "ghcr.io/devcontainers/features/terraform:1": {}, - "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/docker-from-docker:1.5.0": {}, "ghcr.io/devcontainers-contrib/features/aws-cdk:2": {} - }, - "postCreateCommand": "./docker/manage build", "customizations": { "vscode": { "extensions": [ @@ -33,5 +31,8 @@ } } }, - "remoteUser": "root" + "remoteUser": "root", + "containerEnv": { + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" + } } diff --git a/.gitattributes b/.gitattributes index 2b1cd712..63d0af4e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,3 +7,4 @@ *.json text eol=lf **/s2i/bin/* text eol=lf **/root/**/* text eol=lf +/docker/manage text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 69767cb7..6079bd30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Visual Studio Code -.vscode +.vscode/tasks.json ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..db6372ff --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "configurations": [ + { + "name": ".NET Core Docker Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickRemoteProcess}", + "pipeTransport": { + "pipeProgram": "docker", + "pipeArgs": ["exec", "-i", "jasper-api-1"], + "debuggerPath": "/vsdbg/vsdbg", + "pipeCwd": "${workspaceRoot}", + "quoteArgs": false + }, + "sourceFileMap": { + "/opt/app-root/src": "${workspaceRoot}/" + } + } + ] +} diff --git a/README.md b/README.md index 0f85681d..7cf68603 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The OpenShift build and deployment configurations for the project can be found h For high level View API documentation refer to the diagram above. For details, refer to the [router](./web/src/router/index.ts) and [view components](./web/src/components/) source code. -For backend API documentation refer to the Swagger API documentation page available at the `api/` endpoint of the running application. For example, if you are running the application locally in docker, the Swagger page can be found at https://localhost:8080/scjscv/api/. Refer to [Running in Docker](#running-in-docker) section for details. +For backend API documentation refer to the Swagger API documentation page available at the `api/` endpoint of the running application. For example, if you are running the application locally in docker, the Swagger page can be found at https://localhost:8080/jasper/api/. Refer to [Running in Docker](#running-in-docker) section for details. ## Getting Help or Reporting an Issue diff --git a/api/Controllers/LocationController.cs b/api/Controllers/LocationController.cs index 3a42896b..ff2db7c9 100644 --- a/api/Controllers/LocationController.cs +++ b/api/Controllers/LocationController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -50,4 +50,4 @@ public async Task>> GetLocationsAndCourtRooms() return Ok(locationList); } } -} +} \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index ff427755..e45dc7f7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,3 +1,42 @@ +# Running the Application on DevContainer for Local Development + +Hot reloading is configured in both frontend and backend so developers can see the effects of the code changes almost instantly without having to completely restart the application. This significantly speeds up the development process. + +## Pre-requisite + +Ensure `Docker` and `Dev Containers` extenion (`ms-vscode-remote.remote-containers`) is installed in your machine. + +## Steps + +1. Launch code in VSCode. +2. Hit `Ctrl + Shift + P`, select `Dev Containers: Open Folder in Container...` and wait for it to completely load. +3. Building the project. + +``` +./manage build +``` + +4. Starting the project. + +``` +./manage debug +``` + +## Notes + +- DevContainer will fail to build/rebuild when connected to the BC Gov's VPN. + +- You may find this command handy when wiping all unused containers, volumes, networks and images. + ``` + docker system prune -a --volumes + ``` + +## Using the Application + +- By default, the main developer UI is exposed at; https://localhost:8080/ +- The Swagger API and documentation is available at; https://localhost:8080/api/ +- Which is also exposed directly at; http://localhost:5000/api/ + # Running the Application on Docker ## Management Script @@ -5,6 +44,7 @@ The `manage` script wraps the Docker process in easy to use commands. To get full usage information on the script, run: + ``` ./manage -h ``` @@ -14,6 +54,7 @@ To get full usage information on the script, run: The first thing you'll need to do is build the Docker images. To build the images, run: + ``` ./manage build ``` @@ -21,27 +62,29 @@ To build the images, run: ## Starting the Project To start the project, run: + ``` ./manage start ``` -This will start the project interactively; with all of the logs being written to the command line. Press `Ctrl-C` to shut down the services from the same shell window. +This will start the project interactively; with all of the logs being written to the command line. Press `Ctrl-C` to shut down the services from the same shell window. Any environment variables containing settings, configuration, or secrets can be placed in a `.env` file in the `docker` folder and they will automatically be picked up and loaded by the `./manage` script when you start the application. ## Stopping the Project To stop the project, run: + ``` ./manage stop ``` -This will shut down and clean up all of the containers in the project. This is a non-destructive process. The containers are not deleted so they will be reused the next time you run start. +This will shut down and clean up all of the containers in the project. This is a non-destructive process. The containers are not deleted so they will be reused the next time you run start. -Since the services are started interactively, you will have to issue this command from another shell window. This command can also be run after shutting down the services using the `Ctrl-C` method to clean up any services that may not have shutdown correctly. +Since the services are started interactively, you will have to issue this command from another shell window. This command can also be run after shutting down the services using the `Ctrl-C` method to clean up any services that may not have shutdown correctly. ## Using the Application -- By default, the main developer UI is exposed at; https://localhost:8080/scjscv/ -- The Swagger API and documentation is available at; https://localhost:8080/scjscv/api/ - - Which is also exposed directly at; http://localhost:5000/api/ \ No newline at end of file +- By default, the main developer UI is exposed at; https://localhost:8080/jasper/ +- The Swagger API and documentation is available at; https://localhost:8080/jasper/api/ +- Which is also exposed directly at; http://localhost:5000/api/ diff --git a/docker/api/Dockerfile.dev b/docker/api/Dockerfile.dev index fc735a31..0d4f88c3 100644 --- a/docker/api/Dockerfile.dev +++ b/docker/api/Dockerfile.dev @@ -6,4 +6,4 @@ ENV CORS_DOMAIN='http://localhost:8080' ENV DOTNET_STARTUP_PROJECT='./api/api.csproj' ENV DOTNET_USE_POLLING_FILE_WATCHER 1 -RUN curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l /vsdbg \ No newline at end of file +RUN curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l /vsdbg diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 36933d41..3e51565f 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -2,7 +2,7 @@ version: "3.4" services: web: - image: scv-web + image: "${COMPOSE_PROJECT_NAME}-web" environment: - API_URL=${API_URL} - USE_SELF_SIGNED_SSL=${USE_SELF_SIGNED_SSL} @@ -15,9 +15,26 @@ services: depends_on: - api + web-dev: + image: "${COMPOSE_PROJECT_NAME}-web-dev" + environment: + - API_URL=${API_URL} + - WEB_BASE_HREF=${WEB_BASE_HREF} + - DEV_MODE=false + - NODE_ENV=development + - NPM_CONFIG_LOGLEVEL=notice + - NPM_RUN=serve + ports: + - 8080:1339 + volumes: + - "${LOCAL_WORKSPACE_FOLDER-..}/web/src:/opt/app-root/src/src" + - "${LOCAL_WORKSPACE_FOLDER-..}/web/package.json:/opt/app-root/src/package.json" + depends_on: + - api + api: - image: scv-api - environment: + image: "${COMPOSE_PROJECT_NAME}-api" + environment: - ASPNETCORE_URLS=${ASPNETCORE_URLS} - FileServicesClient__Username=${FileServicesClientUsername} - FileServicesClient__Password=${FileServicesClientPassword} @@ -53,12 +70,12 @@ services: ports: - 5000:5000 volumes: - - ../api/:/opt/app-root/src/api - - ../db/:/opt/app-root/src/db - - ../jc-interface-client/:/opt/app-root/src/jc-interface-client - - scv-api-dev-bin:/opt/app-root/src/api/bin - - scv-api-dev-obj:/opt/app-root/src/api/obj - - ./seed:/opt/app-root/data + - ${LOCAL_WORKSPACE_FOLDER-..}/api/:/opt/app-root/src/api + - ${LOCAL_WORKSPACE_FOLDER-..}/db/:/opt/app-root/src/db + - ${LOCAL_WORKSPACE_FOLDER-..}/jc-interface-client/:/opt/app-root/src/jc-interface-client + - api-dev-bin:/opt/app-root/src/api/bin + - api-dev-obj:/opt/app-root/src/api/obj + - ${LOCAL_WORKSPACE_FOLDER-.}/seed:/opt/app-root/data depends_on: - db command: > @@ -77,8 +94,8 @@ services: ports: - 5432:5432 volumes: - - ./tmp:/tmp2 + - ${LOCAL_WORKSPACE_FOLDER-.}/tmp:/tmp2 volumes: - scv-api-dev-bin: - scv-api-dev-obj: \ No newline at end of file + api-dev-bin: + api-dev-obj: diff --git a/docker/manage b/docker/manage index 1676c04a..e79546e7 100755 --- a/docker/manage +++ b/docker/manage @@ -11,7 +11,7 @@ if [ -z "$(type -P "$S2I_EXE")" ]; then fi SCRIPT_HOME="$(cd "$(dirname "$0")" && pwd)" -export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME-scv}" +export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME-jasper}" # ================================================================================================================= # Usage: @@ -19,7 +19,7 @@ export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME-scv}" usage() { cat <<-EOF - Usage: $0 {start|stop|build} + Usage: $0 {start|debug|stop|build} Options: @@ -36,6 +36,7 @@ usage() { Containers: - web + - web-dev - api start - Creates the application containers from the built images @@ -43,22 +44,31 @@ usage() { Example: $0 start + debug - Used for local development that enables hot reloading for FE and BE. + Creates the application containers from the built images + and starts the services based on the docker-compose.yaml file. + Example: + $0 debug + stop - Stops the services. This is a non-destructive process. The containers are not deleted so they will be reused the next time you run start. - down - Brings down the services and removes the volumes (storage) and containers. - rm - Same as down - + dowm | rm - Brings down the services and removes the volumes (storage) and containers. Destructive. EOF exit 1 } - +# ----------------------------------------------------------------------------------------------------------------- +# Default Settings: +# ----------------------------------------------------------------------------------------------------------------- +RUNTIME_CONTAINERS="db api web" +DEBUG_CONTAINERS="db api web-dev" # ----------------------------------------------------------------------------------------------------------------- # Functions: # ----------------------------------------------------------------------------------------------------------------- build-all() { - build-web - build-api + build-web + build-web-dev + build-api } build-api() { @@ -69,7 +79,7 @@ build-api() { echo -e "Building api image using docker ..." echo -e "----------------------------------------------------------------------------------------------------" docker build \ - -t 'scv-api' \ + -t "${COMPOSE_PROJECT_NAME}-api" \ -f './api//Dockerfile.dev' '..' echo -e "====================================================================================================" @@ -80,14 +90,14 @@ build-web() { # web # # The web-runtime image is used for the final runtime image. - # The scv-app image is used to build the artifacts for the vue distribution. + # The artifacts image is used to build the artifacts for the vue distribution. # The vue-on-nginx image is copy of the nginx-runtime image complete with a copy of the build artifacts. # echo -e "\n\n====================================================================================================" - echo -e "Building the scv-web-runtime (nginx-runtime) image using Docker ..." + echo -e "Building the ${COMPOSE_PROJECT_NAME}-web-runtime (nginx-runtime) image using Docker ..." echo -e "----------------------------------------------------------------------------------------------------" docker build \ - -t 'scv-web-runtime' \ + -t "${COMPOSE_PROJECT_NAME}-web-runtime" \ -f './nginx-runtime/Dockerfile' './nginx-runtime/' echo -e "====================================================================================================" @@ -95,20 +105,20 @@ build-web() { # I tried using __webpack_public_path__, but the CSS file path and JS file path weren't correctly updated. # Also note we don't load in environment variables from the arguments here. echo -e "\n\n====================================================================================================" - echo -e "Building the scv-web-artifacts image using s2i ..." + echo -e "Building the ${COMPOSE_PROJECT_NAME}-web-artifacts image using s2i ..." echo -e "----------------------------------------------------------------------------------------------------" ${S2I_EXE} build \ --copy \ '../web' \ 'quay.io/centos7/nodejs-12-centos7:master' \ - 'scv-web-artifacts' + "${COMPOSE_PROJECT_NAME}-web-artifacts" echo -e "====================================================================================================" echo -e "\n\n====================================================================================================" - echo -e "Building the scv-web image using Docker ..." + echo -e "Building the ${COMPOSE_PROJECT_NAME}-web image using Docker ..." echo -e "----------------------------------------------------------------------------------------------------" docker build \ - -t 'scv-web' \ + -t "${COMPOSE_PROJECT_NAME}-web" \ --build-arg IMAGE_PREFIX=${COMPOSE_PROJECT_NAME}- \ -f './vue-on-nginx/Dockerfile' './vue-on-nginx/' echo -e "====================================================================================================" @@ -119,21 +129,15 @@ build-web-dev() { # web-dev # echo -e "\n\n====================================================================================================" - echo -e "Building the nginx-runtime image using Docker ..." - echo -e "----------------------------------------------------------------------------------------------------" - docker build \ - -t 'nginx-runtime' \ - -f './nginx-runtime/Dockerfile' './nginx-runtime/' - echo -e "====================================================================================================" - - echo -e "\n\n====================================================================================================" - echo -e "Building the scv-web-dev image using s2i ..." + echo -e "Building the ${COMPOSE_PROJECT_NAME}-web-dev image using s2i ..." echo -e "----------------------------------------------------------------------------------------------------" ${S2I_EXE} build \ + --copy \ -e "DEV_MODE=true" \ + -e WEB_BASE_HREF=${WEB_BASE_HREF} \ '../web' \ - 'quay.io/centos7/nodejs-12-centos7' \ - 'scv-web-dev' + 'centos/nodejs-12-centos7' \ + "${COMPOSE_PROJECT_NAME}-web-dev" echo -e "====================================================================================================" } @@ -152,21 +156,20 @@ configureEnvironment () { esac done - # scv-db + # Default database startup parameters export POSTGRESQL_DATABASE=${POSTGRESQL_DATABASE:-appdb} - export POSTGRESQL_USER=${POSTGRESQL_USER:-scv} + export POSTGRESQL_USER=${POSTGRESQL_USER:-${COMPOSE_PROJECT_NAME}} export POSTGRESQL_PASSWORD=${POSTGRESQL_PASSWORD:-jeKEumGzuRVY4EJyfcUk} export POSTGRESQL_ADMIN_PASSWORD=${POSTGRESQL_ADMIN_PASSWORD:-yM%J]7RZgY@!zb=*#4kB} - # scv-web + # Default web startup parameters export API_URL=${API_URL-http://api:5000/api/} - export WEB_BASE_HREF=${WEB_BASE_HREF-/scjscv/} + export WEB_BASE_HREF=${WEB_BASE_HREF-/jasper/} } getStartupParams() { CONTAINERS="" - - ARGS="" + ARGS="--force-recreate" for arg in $@; do case "$arg" in @@ -180,6 +183,14 @@ getStartupParams() { esac done + if [ -z "$CONTAINERS" ]; then + if [ -z "$DEBUG_MODE" ]; then + CONTAINERS="$RUNTIME_CONTAINERS" + else + CONTAINERS="$DEBUG_CONTAINERS" + fi + fi + echo ${ARGS} ${CONTAINERS} } @@ -228,8 +239,11 @@ case "$COMMAND" in configureEnvironment $@ docker-compose up ${_startupParams} ;; - web-dev) - # todo + debug) + export DEBUG_MODE=1 + _startupParams=$(getStartupParams $@) + configureEnvironment $@ + docker-compose up ${_startupParams} ;; stop) docker-compose stop @@ -259,4 +273,4 @@ case "$COMMAND" in usage esac -popd >/dev/null \ No newline at end of file +popd >/dev/null diff --git a/web/.devcontainer/Dockerfile b/web/.devcontainer/Dockerfile index 6c965bfa..1cd01b6c 100644 --- a/web/.devcontainer/Dockerfile +++ b/web/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM nginx:stable ENV STI_SCRIPTS_PATH=/usr/libexec/s2i ENV USE_SELF_SIGNED_SSL='usss' -ENV WEB_BASE_HREF='/scjscv/' +ENV WEB_BASE_HREF='/jasper/' ENV API_URL='http://host.docker.internal:5000/api/' ENV RealIpFrom='172.17.0.1' ENV NODE_ENV='development' @@ -35,7 +35,7 @@ COPY nginx.conf.template /tmp/ # - The application artifacts live in /tmp # --------------------------------------------------------------------------------- RUN chmod -R g+rwx $STI_SCRIPTS_PATH -RUN chmod og+rw /var/cache/nginx \ +RUN chmod og+rw /var/cache/nginx \ /var/run \ /etc/nginx/nginx.conf \ /tmp diff --git a/web/src/main.ts b/web/src/main.ts index c0f31aed..64550432 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -21,7 +21,7 @@ Vue.component('loading-spinner', LoadingSpinner); Vue.http.interceptors.push(function () { return function (response) { - if (response.status == 401) { + if (response.status == 401) { location.replace(`${process.env.BASE_URL}api/auth/login?redirectUri=${window.location}`); } }; @@ -29,7 +29,7 @@ Vue.http.interceptors.push(function () { Vue.http.options.root = process.env.BASE_URL; -//Redirect from / to /scjscv/ +// Redirect from / to /jasper/ if (location.pathname == "/") history.pushState({ page: "home" }, "", process.env.BASE_URL); @@ -42,5 +42,5 @@ const router = new VueRouter({ new Vue({ router, store, - render: h => h(App) -}).$mount('#app'); \ No newline at end of file + render: h => h(App) +}).$mount('#app'); diff --git a/web/vue.config.js b/web/vue.config.js index 57a5aa77..7f2781d4 100644 --- a/web/vue.config.js +++ b/web/vue.config.js @@ -2,26 +2,31 @@ const path = require("path"); const vueSrc = "src"; //I noticed when we don't have publicPath set to /, it becomes problematic using vue-cli-tools - it doesn't seem to respect history paths. -//EX. scjscv/civil-files/5555 wont work when you navigate directly to it with vue-cli-tools versus NGINX it works fine. -//When deployed over NGINX this problem seems to go away. So I've left it as / for now in local development environments. +//EX. jasper/civil-files/5555 wont work when you navigate directly to it with vue-cli-tools versus NGINX it works fine. +//When deployed over NGINX this problem seems to go away. So I've left it as / for now in local development environments. module.exports = { publicPath: process.env.NODE_ENV == 'production' ? '/S2I_INJECT_PUBLIC_PATH/' : '/', //chainWebpack: config => config.optimization.minimize(false), Disable minification. configureWebpack: { devServer: { historyApiFallback: true, - host: 'localhost', + host: '0.0.0.0', port: 1339, https: true, + watchOptions: { + ignored: /node_modules/, + aggregateTimeout: 300, + poll: 1000, + }, proxy: { - //This is for WEB_BASE_HREF = '/' specifically. + //This is for WEB_BASE_HREF = '/' specifically. //If having problems connecting, try adding: netsh http add iplisten 127.0.0.1 '^/api': { - target: "https://localhost:44369", + target: "http://api:5000", headers: { Connection: 'keep-alive', 'X-Forwarded-Host': 'localhost', - 'X-Forwarded-Port': '1339', + 'X-Forwarded-Port': '8080', 'X-Base-Href': '/' }, changeOrigin: true