Index: .gitignore =================================================================== diff -u -N --- .gitignore (revision 0) +++ .gitignore (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,14 @@ +*~ +*.DS_Store +*.iml +*.ipr +*.iws +build/ +bower_components/ +out/ +.idea/ +node_modules/ +.env +bower_components +.tmp +.sonar Index: .npmrc =================================================================== diff -u -N --- .npmrc (revision 0) +++ .npmrc (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1 @@ +unsafe-perm=true Index: CHANGELOG.md =================================================================== diff -u -N --- CHANGELOG.md (revision 0) +++ CHANGELOG.md (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,5 @@ +1.0.0 / WIP +================== + +New functionality that are backwards-compatible: +* \ No newline at end of file Index: Dockerfile =================================================================== diff -u -N --- Dockerfile (revision 0) +++ Dockerfile (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,9 @@ +FROM debian:jessie + +WORKDIR /openlmis-offline-ui + +COPY package.json . +COPY package-yarn.json . +COPY config.json . +COPY src/ ./src/ +COPY build/messages/ ./messages/ Index: Gruntfile.js =================================================================== diff -u -N --- Gruntfile.js (revision 0) +++ Gruntfile.js (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,6 @@ +module.exports = function(grunt) { + var configSetup = require('dev-ui/tasks/config.js'); + configSetup(grunt); + + grunt.loadNpmTasks('/dev-ui'); +}; Index: Jenkinsfile =================================================================== diff -u -N --- Jenkinsfile (revision 0) +++ Jenkinsfile (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,232 @@ +import hudson.tasks.test.AbstractTestResultAction + +pipeline { + agent any + options { + buildDiscarder(logRotator( + numToKeepStr: env.BRANCH_NAME.equals("master") ? '15' : '3', + daysToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '7', + artifactDaysToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '3', + artifactNumToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '1' + )) + disableConcurrentBuilds() + skipStagesAfterUnstable() + } + environment { + PATH = "/usr/local/bin/:$PATH" + COMPOSE_PROJECT_NAME = "${env.JOB_NAME}-${BRANCH_NAME}" + } + stages { + stage('Preparation') { + steps { + checkout scm + + withCredentials([usernamePassword( + credentialsId: "cad2f741-7b1e-4ddd-b5ca-2959d40f62c2", + usernameVariable: "USER", + passwordVariable: "PASS" + )]) { + sh 'set +x' + sh 'docker login -u $USER -p $PASS' + } + script { + def properties = readProperties file: 'project.properties' + if (!properties.version) { + error("version property not found") + } + VERSION = properties.version + currentBuild.displayName += " - " + VERSION + } + } + post { + failure { + script { + notifyAfterFailure() + } + } + } + } + stage('Build') { + steps { + withCredentials([file(credentialsId: '8da5ba56-8ebb-4a6a-bdb5-43c9d0efb120', variable: 'ENV_FILE')]) { + script { + try { + sh ''' + sudo rm -f .env + cp $ENV_FILE .env + if [ "$GIT_BRANCH" != "master" ]; then + sed -i '' -e "s#^TRANSIFEX_PUSH=.*#TRANSIFEX_PUSH=false#" .env 2>/dev/null || true + fi + docker-compose pull + docker-compose down --volumes + docker-compose run --entrypoint /dev-ui/build.sh offline-ui + docker-compose build image + docker-compose down --volumes + ''' + currentBuild.result = processTestResults('SUCCESS') + } + catch (exc) { + currentBuild.result = processTestResults('FAILURE') + if (currentBuild.result == 'FAILURE') { + error(exc.toString()) + } + } + } + } + } + post { + success { + archive 'build/styleguide/*, build/styleguide/**/*, build/docs/*, build/docs/**/*, build/messages/*' + } + unstable { + script { + notifyAfterFailure() + } + } + failure { + script { + notifyAfterFailure() + } + } + } + } + stage('Build reference-ui') { + when { + expression { + return "${env.GIT_BRANCH}" == 'master' && VERSION.endsWith("SNAPSHOT") + } + } + steps { + sh "docker tag openlmis/offline-ui:latest openlmis/offline-ui:${VERSION}" + sh "docker push openlmis/offline-ui:${VERSION}" + build job: 'OpenLMIS-reference-ui-pipeline/master', wait: false + } + post { + failure { + script { + notifyAfterFailure() + } + } + } + } + stage('Sonar analysis') { + when { + expression { + return VERSION.endsWith("SNAPSHOT") + } + } + steps { + withSonarQubeEnv('Sonar OpenLMIS') { + withCredentials([string(credentialsId: 'SONAR_LOGIN', variable: 'SONAR_LOGIN'), string(credentialsId: 'SONAR_PASSWORD', variable: 'SONAR_PASSWORD')]) { + script { + sh ''' + set +x + + sudo rm -f .env + touch .env + + SONAR_LOGIN_TEMP=$(echo $SONAR_LOGIN | cut -f2 -d=) + SONAR_PASSWORD_TEMP=$(echo $SONAR_PASSWORD | cut -f2 -d=) + echo "SONAR_LOGIN=$SONAR_LOGIN_TEMP" >> .env + echo "SONAR_PASSWORD=$SONAR_PASSWORD_TEMP" >> .env + echo "SONAR_BRANCH=$GIT_BRANCH" >> .env + + docker-compose run --entrypoint ./sonar.sh offline-ui + docker-compose down --volumes + sudo rm -rf node_modules/ + ''' + // workaround because sonar plugin retrieve the path directly from the output + sh 'echo "Working dir: ${WORKSPACE}/.sonar"' + } + } + } + timeout(time: 1, unit: 'HOURS') { + script { + def gate = waitForQualityGate() + if (gate.status != 'OK') { + echo 'Quality Gate FAILED' + currentBuild.result = 'UNSTABLE' + } + } + } + } + post { + unstable { + script { + notifyAfterFailure() + } + } + failure { + script { + notifyAfterFailure() + } + } + } + } + stage('Push image') { + when { + expression { + return env.GIT_BRANCH == 'master' || env.GIT_BRANCH =~ /rel-.+/ + } + } + steps { + sh "docker tag openlmis/offline-ui:latest openlmis/offline-ui:${VERSION}" + sh "docker push openlmis/offline-ui:${VERSION}" + } + post { + success { + script { + if (!VERSION.endsWith("SNAPSHOT")) { + currentBuild.setKeepLog(true) + } + } + } + failure { + script { + notifyAfterFailure() + } + } + } + } + } + post { + fixed { + script { + BRANCH = "${env.GIT_BRANCH}".trim() + if (BRANCH.equals("master") || BRANCH.startsWith("rel-")) { + slackSend color: 'good', message: "${env.JOB_NAME} - #${env.BUILD_NUMBER} Back to normal" + } + } + } + } +} + +def notifyAfterFailure() { + messageColor = 'danger' + if (currentBuild.result == 'UNSTABLE') { + messageColor = 'warning' + } + BRANCH = "${env.GIT_BRANCH}".trim() + if (BRANCH.equals("master") || BRANCH.startsWith("rel-")) { + slackSend color: "${messageColor}", message: "${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result} (<${env.BUILD_URL}|Open>)" + } + emailext subject: "${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result}", + body: """

${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result}

Check console output to view the results.

""", + recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'DevelopersRecipientProvider']] +} + +def processTestResults(status) { + junit '**/build/test/test-results/*.xml' + + AbstractTestResultAction testResultAction = currentBuild.rawBuild.getAction(AbstractTestResultAction.class) + if (testResultAction != null) { + failuresCount = testResultAction.failCount + echo "Failed tests count: ${failuresCount}" + if (failuresCount > 0) { + echo "Setting build unstable due to test failures" + status = 'UNSTABLE' + } + } + + return status +} Index: README.md =================================================================== diff -u -N -ra7d3f2bbcd42201facf876b4b44c317ce14571ea -r1bb139b24829fbec5faca5bfaa0926a02d66002a --- README.md (.../README.md) (revision a7d3f2bbcd42201facf876b4b44c317ce14571ea) +++ README.md (.../README.md) (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -1 +1,66 @@ -# openlmis-offline-ui \ No newline at end of file +# OpenLMIS Stock Management UI Module +This repository is the UI for the [OpenLMIS Stock Management Service.](https://github.com/OpenLMIS/openlmis-stockmanagement) + +## Prerequisites +* Docker 1.11+ +* Docker Compose 1.6+ + +## Quick Start +1. Fork/clone this repository from GitHub. + + ```shell + git clone https://github.com/OpenLMIS/openlmis-offline-ui.git + ``` +2. Develop w/ Docker by running `docker-compose run --service-ports offline-ui`. +3. You should now be in an interactive shell inside the newly created development environment, build the project with: `npm install && grunt` and then you can build and start it with `grunt build --serve`. +4. Go to `http://localhost:9000/webapp/` to see the login page. + +*Note:* To change the location of where the OpenLMIS-UI attemps to access OpenLMIS, use the command `grunt build --openlmisServerUrl= --serve`. + +## Building & Testing +See the [OpenLMIS/dev-ui project](https://github.com/OpenLMIS/dev-ui) for more information on what commands are available, below are the command you might use during a normal work day. + +```shell +// Open docker in an interactive shell +> docker-compose run --service-ports offline-ui + +// Install dependencies +$ npm install +$ grunt + +// Build and run the UI against a OpenLMIS server +$ grunt build --openlmisServerURL= --serve + +// Run unit tests +$ grunt karma:unit + +// Run a watch process that will build and test your code +// NOTE: You must change a file at least once before your code is rebuilt +$ grunt watch --openlmisServerURL= --serve + +``` + +### Built Artifacts +After the OpenLMIS-UI is built and being served, you can access the following documents: +- `http://localhost:9000/webapp/` The compiled OpenLMIS application +- `http://localhost:9000/docs/` JS Documentation created from the source code +- `http://localhost:9000/styleguide/` KSS Documentation created from the CSS + + +### Build Deployment Image +The specialized docker-compose.builder.yml is geared toward CI and build +servers for automated building, testing and docker image generation of +the UI module. + +```shell +> docker-compose pull +> docker-compose run ./build.sh offline-ui +> docker-compose build image +``` + +### Internationalization (i18n) +Transifex has been integrated into the development and build process. In order to sync with the project's resources in Transifex, you must provide values for the following keys: TRANSIFEX_USER, TRANSIFEX_PASSWORD. + +For the development environment in Docker, you can sync with Transifex by running the sync_transifex.sh script. This will upload your source messages file to the Transifex project and download translated messages files. + +The build process has syncing with Transifex seamlessly built-in. Index: config.json =================================================================== diff -u -N --- config.json (revision 0) +++ config.json (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,9 @@ +{ + "orderedBuildDirectories": [ + "/openlmis-ui-components", + "/openlmis-auth-ui", + "/openlmis-ui-layout", + "/openlmis-referencedata-ui", + "/openlmis-stockmanagement-ui" + ] +} \ No newline at end of file Index: docker-compose.yml =================================================================== diff -u -N --- docker-compose.yml (revision 0) +++ docker-compose.yml (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,46 @@ +version: "2" +services: + offline-ui: + image: openlmis/dev-ui:9.0.2-SNAPSHOT + working_dir: /app + volumes: + - '.:/app' + ports: + - "9000:9000" + - "9876:9876" + env_file: .env + volumes_from: + - auth-ui + - referencedata-ui + - ui-components + - ui-layout + - stockmanagement-ui + depends_on: + - auth-ui + - referencedata-ui + - ui-components + - ui-layout + - stockmanagement-ui + auth-ui: + image: openlmis/auth-ui:6.2.6-SNAPSHOT + volumes: + - '/openlmis-auth-ui' + referencedata-ui: + image: openlmis/referencedata-ui:5.6.5-SNAPSHOT + volumes: + - '/openlmis-referencedata-ui' + ui-components: + image: openlmis/ui-components:7.2.5-SNAPSHOT + volumes: + - '/openlmis-ui-components' + ui-layout: + image: openlmis/ui-layout:5.1.9-SNAPSHOT + volumes: + - '/openlmis-ui-layout' + stockmanagement-ui: + image: openlmis/stockmanagement-ui:2.0.9-SNAPSHOT + volumes: + - '/openlmis-stockmanagement-ui' + image: + build: . + image: openlmis/offline-ui Index: npm-shrinkwrap.json =================================================================== diff -u -N --- npm-shrinkwrap.json (revision 0) +++ npm-shrinkwrap.json (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1 @@ +{} Index: package-yarn.json =================================================================== diff -u -N --- package-yarn.json (revision 0) +++ package-yarn.json (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,7 @@ +{ + "dependencies": { + }, + "engines": { + "yarn": ">= 1.0.0" + } +} Index: package.json =================================================================== diff -u -N --- package.json (revision 0) +++ package.json (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,13 @@ +{ + "repository": { + "type": "git", + "url": "https://github.com/OpenLMIS/openlmis-offline-ui" + }, + "devDependencies": { + "openlmis-ui": "file:///dev-ui" + }, + "scripts": { + "postinstall": "cp -nr node_modules/dev-ui/node_modules ." + }, + "dependencies": {} +} Index: project.properties =================================================================== diff -u -N --- project.properties (revision 0) +++ project.properties (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,4 @@ +version=1.0.0-SNAPSHOT +projectName=OpenLMIS Offline UI +projectKey=offline-ui +transifexProject=openlmis-offline-ui Index: sonar.sh =================================================================== diff -u -N --- sonar.sh (revision 0) +++ sonar.sh (revision 1bb139b24829fbec5faca5bfaa0926a02d66002a) @@ -0,0 +1,9 @@ +#!/bin/sh + +# Update everything (just in case) +npm rebuild +npm install --no-optional + +# Built and test +grunt +grunt sonar --sonarLogin=$SONAR_LOGIN --sonarPassword=$SONAR_PASSWORD --sonarBranch=$SONAR_BRANCH