diff --git a/.eslintrc.yml b/.eslintrc.yml index 4f30367b7..fc8c9fb1c 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -19,3 +19,4 @@ rules: no-eq-null: 0 no-console: 0 no-warning-comments: 0 + no-empty: 0 diff --git a/client/client/src/address-edit/address-edit.html b/client/client/src/address-edit/address-edit.html index 11ed0cccc..f703c3803 100644 --- a/client/client/src/address-edit/address-edit.html +++ b/client/client/src/address-edit/address-edit.html @@ -1,4 +1,4 @@ - + -
+ Address @@ -50,11 +50,11 @@ Notes - + {{$parent.$parent.item.description}} - + diff --git a/client/client/src/address-edit/address-edit.js b/client/client/src/address-edit/address-edit.js index 14db7035d..0ee19e2c6 100644 --- a/client/client/src/address-edit/address-edit.js +++ b/client/client/src/address-edit/address-edit.js @@ -1,76 +1,137 @@ import ngModule from '../module'; export default class Controller { - constructor($state, $http) { + constructor($state, $scope, $http, $q, $translate, vnApp) { + this.$state = $state; + this.$scope = $scope; + this.$http = $http; + this.$q = $q; + this.$translate = $translate; + this.vnApp = vnApp; + this.address = { id: parseInt($state.params.addressId) }; - this.$http = $http; - this.notes = []; + this.observations = []; + this.observationsDictionary = {}; + this.observationsRemoved = []; } _setIconAdd() { - if (this.notes.length) { - this.notes.forEach(element => { + if (this.observations.length) { + this.observations.map(element => { element.showAddIcon = false; + return true; }); - this.notes[this.notes.length - 1].showAddIcon = true; - } - } - _setRemoveAdd() { - if (this.notes.length) { - this.notes.forEach(element => { - element.showRemoveIcon = true; - }); + this.observations[this.observations.length - 1].showAddIcon = true; } else { - this.notes = [this._createEmptyNote()]; + this.addObservation(); } } - _createEmptyNote() { - return {id: this._createFakeId(), observationTypeFk: null, description: null, showRemoveIcon: true, showAddIcon: true}; + + _setDirtyForm() { + if (this.$scope.form) { + this.$scope.form.$setDirty(); + } } - _createFakeId() { - let now = Date.now(); - let random = Math.ceil((Math.random() * 100000) + 1); - return `fakeId${now}${random}`; + _unsetDirtyForm() { + if (this.$scope.form) { + this.$scope.form.$setPristine(); + } } - addNote() { - this.notes.push(this._createEmptyNote()); + + addObservation() { + this.observations.push({observationTypeFk: null, description: null, showAddIcon: true}); this._setIconAdd(); - this._setRemoveAdd(); } - removeNote(id) { - let found = false; - for (let i = 0; i < this.notes.length; i++) { - if (this.notes[i].id === id) { - this.notes.splice(i, 1); - found = true; + + removeObservation(index) { + let item = this.observations[index]; + if (item) { + this.observations.splice(index, 1); + this._setIconAdd(); + if (item.id) { + this.observationsRemoved.push(item.id); + this._setDirtyForm(); + } + } + } + _submitObservations(objectObservations) { + return this.$http.post('/client/api/crudAddressObservations', objectObservations); + } + + submit() { + this._unsetDirtyForm(); + let submitWatcher = this.$scope.watcher.dataChanged(); + let submitObservations; + let repeatedTypes = false; + let observationsObj = { + remove: this.observationsRemoved, + news: [], + modified: [] + }; + + for (let i = 0; i < this.observations.length; i++) { + let observation = this.observations[i]; + // only one observation is allowed for each of its types + if (this.observationsDictionary[observation.observationTypeFk] !== undefined && // IF the dictionary contains the type + ( + // AND (is a new Observation OR is old but with distinct Id) --> repeated + !observation.id || (observation.id && this.observationsDictionary[observation.observationTypeFk].id !== observation.id) + ) + ) { + repeatedTypes = true; break; } + + this.observationsDictionary[observation.observationTypeFk] = observation; + + if (!observation.id && observation.observationTypeFk && observation.description) { + observationsObj.news.push(observation); + } else if (observation.id && this.observationsDictionary[observation.observationTypeFk].description !== observation.description) { + observationsObj.modified.push(observation); + } } - if (found) { - this._setIconAdd(); - this._setRemoveAdd(); + submitObservations = observationsObj.modified.length > 0 || observationsObj.news.length > 0 || observationsObj.remove.length > 0; + + if (repeatedTypes) { + this.vnApp.showMessage( + this.$translate.instant('you can not repeat the types of observations') + ); + } else if (submitWatcher && !submitObservations) { + this.$scope.watcher.submit().then(() => { + this.$state.go('clientCard.addresses.list', {id: this.$state.params.id}); + }); + } else if (!submitWatcher && submitObservations) { + this._submitObservations(observationsObj).then(() => { + this.$state.go('clientCard.addresses.list', {id: this.$state.params.id}); + }); + } else if (submitWatcher && submitObservations) { + this.$q.all([this.$scope.watcher.submit(), this._submitObservations(observationsObj)]).then(() => { + this.$state.go('clientCard.addresses.list', {id: this.$state.params.id}); + }); + } else { + this.vnApp.showMessage( + this.$translate.instant('No changes to save') + ); } } + $onInit() { let filter = { - where: { - addressFk: this.address.id - }, - include: [ - {relation: 'observationType'} - ] + where: {addressFk: this.address.id}, + include: {relation: 'observationType'} }; this.$http.get(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).then(res => { - this.notes = (res.data && res.data.length) ? res.data : [this._createEmptyNote()]; - this._setIconAdd(); - this._setRemoveAdd(); + this.observations = res.data; + this.observations.forEach(item => { + this.observationsDictionary[item.observationTypeFk] = {id: item.id, description: item.description}; + }); }); } } -Controller.$inject = ['$state', '$http']; +Controller.$inject = ['$state', '$scope', '$http', '$q', '$translate', 'vnApp']; ngModule.component('vnAddressEdit', { template: require('./address-edit.html'), diff --git a/client/core/src/lib/modified.js b/client/core/src/lib/modified.js index 79f725633..f62bc91ae 100644 --- a/client/core/src/lib/modified.js +++ b/client/core/src/lib/modified.js @@ -3,6 +3,9 @@ import isEqual from './equals'; export default function getModifiedData(object, objectOld) { var newObject = {}; + if (objectOld === null) { + return object; + } for (var k in object) { var val = object[k]; var valOld = objectOld[k] === undefined ? null : objectOld[k]; diff --git a/client/core/src/watcher/watcher.js b/client/core/src/watcher/watcher.js index dab91c8fe..0e4dfc083 100644 --- a/client/core/src/watcher/watcher.js +++ b/client/core/src/watcher/watcher.js @@ -96,7 +96,7 @@ export default class Watcher extends Component { } let changedData = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post') ? this.copyInNewObject(this.data) : getModifiedData(this.data, this.orgData); - if (this.save) { + if (this.save && this.save.accept) { this.save.model = changedData; // this.copyInNewObject(changedData); return new Promise((resolve, reject) => { this.save.accept().then( @@ -108,7 +108,7 @@ export default class Watcher extends Component { // XXX: Alternative when mgCrud is not used - let id = this.orgData[this.idField]; + let id = this.idField ? this.orgData[this.idField] : null; if (id) { return new Promise((resolve, reject) => { @@ -120,7 +120,7 @@ export default class Watcher extends Component { } return new Promise((resolve, reject) => { - this.$http.post(this.url, this.data).then( + this.$http.post(this.url, changedData).then( json => this.writeData(json, resolve), json => reject(json) ); @@ -181,7 +181,7 @@ export default class Watcher extends Component { } dataChanged() { - if (this.form && !this.form.$dirty) return false; + if (this.form && this.form.$dirty) return true; let newData = this.copyInNewObject(this.data); return !isEqual(newData, this.orgData); } diff --git a/client/core/src/watcher/watcher.spec.js b/client/core/src/watcher/watcher.spec.js index 08e430b06..231680f28 100644 --- a/client/core/src/watcher/watcher.spec.js +++ b/client/core/src/watcher/watcher.spec.js @@ -145,7 +145,7 @@ describe('Component vnWatcher', () => { describe('when controller.save()', () => { it(`should set controller.save.model property`, () => { - controller.save = {}; + controller.save = {accept: () => {}}; controller.data = {originalInfo: 'original data', info: 'new data'}; controller.orgData = {originalInfo: 'original data'}; controller.submit(); diff --git a/gulpfile.js b/gulpfile.js index 5fa20ad2c..327a51579 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -101,6 +101,9 @@ gulp.task('install', () => { })); }); +// Gulp install alias +gulp.task('i', ['install']); + // Deployment gulp.task('build', ['clean'], () => { @@ -141,15 +144,50 @@ gulp.task('docker-compose', async () => { // Nginx & services -gulp.task('nginx', ['nginx-conf'], callback => { - let command = isWindows ? 'start.cmd' : 'start.sh'; - command = path.join(`${nginxDir}/${command}`); - exec(command, (err, stdout, stderr) => { - // if (stderr) console.log(stderr); - callback(err); +let nginxConf = 'temp/nginx.conf'; +let nginxTemp = `${nginxDir}/temp`; + +async function nginxGetBin() { + if (isWindows) + return 'nginx'; + try { + let nginxBin = '/usr/sbin/nginx'; + await fs.stat(nginxBin); + return nginxBin; + } catch (e) { + return 'nginx'; + } +} + +gulp.task('nginx', ['nginx-stop'], async () => { + let nginxBin = await nginxGetBin(); + + if (isWindows) + nginxBin = `start /B ${nginxBin}`; + + return new Promise((resolve, reject) => { + exec(`${nginxBin} -c "${nginxConf}" -p "${nginxDir}"`, err => { + if (err) return reject(err); + resolve(); + }); }); }); +gulp.task('nginx-stop', ['nginx-conf'], async () => { + try { + let nginxBin = await nginxGetBin(); + await fs.stat(`${nginxTemp}/nginx.pid`); + let command = `${nginxBin} -c "${nginxConf}" -p "${nginxDir}" -s stop`; + + return new Promise((resolve, reject) => { + exec(command, err => { + if (err) return reject(err); + resolve(); + }); + }); + } catch (e) {} +}); + gulp.task('nginx-conf', async () => { const mustache = require('mustache'); diff --git a/package-lock.json b/package-lock.json index 9988603b0..e10725348 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10103,7 +10103,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "1.0.1", @@ -10134,7 +10134,7 @@ "karma-webpack": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-2.0.9.tgz", - "integrity": "sha512-F1j3IG/XhiMzcunAXbWXH95uizjzr3WdTzmVWlta8xqxcCtAu9FByCb4sccIMxaVFAefpgnUW9KlCo0oLvIX6A==", + "integrity": "sha1-YciAkffdkQY1E0wDKyZqRlr/tX8=", "dev": true, "requires": { "async": "0.9.2", diff --git a/services/loopback/common/methods/client/listAddresses.js b/services/loopback/common/methods/client/listAddresses.js index eafb8e954..0c93dd1cd 100644 --- a/services/loopback/common/methods/client/listAddresses.js +++ b/services/loopback/common/methods/client/listAddresses.js @@ -38,7 +38,8 @@ module.exports = function(Client) { }, skip: (params.page - 1) * params.size, limit: params.size, - order: ['isDefaultAddress DESC', 'isActive DESC'] + order: ['isDefaultAddress DESC', 'isActive DESC'], + include: {observations: 'observationType'} }; let total = null; diff --git a/services/nginx/start.cmd b/services/nginx/start.cmd deleted file mode 100644 index a64a5ba84..000000000 --- a/services/nginx/start.cmd +++ /dev/null @@ -1,27 +0,0 @@ -@echo off - -set nginxDir=%~dp0 -set nginxTemp=%nginxDir%\temp -set nginxConf=temp\nginx.conf - -if "%1"=="" goto caseStart -if "%1"=="start" goto caseStart -if "%1"=="stop" goto caseStop -goto caseUsage - -:caseStart - call "%0" stop - echo Starting nginx. - if not exist "%nginxTemp%" (mkdir "%nginxTemp%") - start /I nginx -c "%nginxConf%" -p "%nginxDir%" - goto caseEnd - -:caseStop - echo Stoping nginx. - if exist "%nginxTemp%\nginx.pid" (nginx -c "%nginxConf%" -p "%nginxDir%" -s stop) - goto caseEnd - -:caseUsage - echo "Usage: %0 [start|stop]" - -:caseEnd diff --git a/services/nginx/start.sh b/services/nginx/start.sh deleted file mode 100755 index a8eb7e1df..000000000 --- a/services/nginx/start.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -nginxDir="$(dirname $0)" -nginxTemp="$nginxDir/temp" -nginxConf="temp/nginx.conf" -nginxBin="/usr/sbin/nginx" - -if [ ! -f $nginxBin ]; then - nginxBin="nginx" -fi - -case "$1" in - start|"") - $0 stop - echo "Starting nginx." - mkdir -p "$nginxTemp" - "$nginxBin" -c "$nginxConf" -p "$nginxDir" - ;; - stop) - echo "Stoping nginx." - if [ -f "$nginxTemp/nginx.pid" ]; then - "$nginxBin" -c "$nginxConf" -p "$nginxDir" -s stop - fi - ;; - *) - echo "Usage: `basename "$0"` [start|stop]" - exit 1 -esac