From 51cc783521b6dc5212e905f0ba6f92880cc1ddfc Mon Sep 17 00:00:00 2001 From: Daniel Herrero Date: Thu, 1 Feb 2018 13:28:45 +0100 Subject: [PATCH 1/4] side front address observations --- .../client/src/address-edit/address-edit.html | 19 ++- .../client/src/address-edit/address-edit.js | 145 +++++++++++++----- client/core/src/lib/modified.js | 3 + client/core/src/watcher/watcher.js | 8 +- client/core/src/watcher/watcher.spec.js | 2 +- services/client/common/models/address.js | 3 +- 6 files changed, 122 insertions(+), 58 deletions(-) diff --git a/client/client/src/address-edit/address-edit.html b/client/client/src/address-edit/address-edit.html index f83fee845..6ee0348d8 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 e27efc9f0..1e1640d92 100644 --- a/client/core/src/watcher/watcher.spec.js +++ b/client/core/src/watcher/watcher.spec.js @@ -144,7 +144,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/services/client/common/models/address.js b/services/client/common/models/address.js index 53c0bcbad..bafcfbd62 100644 --- a/services/client/common/models/address.js +++ b/services/client/common/models/address.js @@ -36,7 +36,8 @@ module.exports = function(Self) { scope: { fields: ["id", "name"] } - } + }, + {observations: "observationType"} ] }; next(); From 692a226b69aee21ccc475818b2d35952171de5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20S=C3=A1nchez?= Date: Mon, 5 Feb 2018 19:22:38 +0100 Subject: [PATCH 2/4] =?UTF-8?q?El=20servicio=20de=20Nginx=20ahora=20se=20i?= =?UTF-8?q?nicia=20desde=20Gulp.=20A=C3=B1adido=20alias=20de=20instalacion?= =?UTF-8?q?=20"gulp=20i".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.yml | 1 + gulpfile.js | 50 +++++++++++++++++++++++++++++++++++----- package-lock.json | 12 +++++----- services/nginx/start.cmd | 27 ---------------------- services/nginx/start.sh | 28 ---------------------- 5 files changed, 51 insertions(+), 67 deletions(-) delete mode 100644 services/nginx/start.cmd delete mode 100755 services/nginx/start.sh 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/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..018a0705e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -244,7 +244,7 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", "dev": true }, "archy": { @@ -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", @@ -11183,7 +11183,7 @@ "node-sass": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.7.2.tgz", - "integrity": "sha512-CaV+wLqZ7//Jdom5aUFCpGNoECd7BbNhjuwdsX/LkXBrHl8eb1Wjw4HvWqcFvhr5KuNgAk8i/myf/MQ1YYeroA==", + "integrity": "sha1-k2Z3i6FGnrAUOKnoWS9CYry2eU4=", "dev": true, "requires": { "async-foreach": "0.1.3", @@ -11401,7 +11401,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "dev": true, "requires": { "are-we-there-yet": "1.1.4", @@ -15164,7 +15164,7 @@ "wide-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "dev": true, "requires": { "string-width": "1.0.2" 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 From 19ddead3267ba49d2e0f8657efcd45a03fbf745d Mon Sep 17 00:00:00 2001 From: Daniel Herrero Date: Tue, 6 Feb 2018 07:24:10 +0100 Subject: [PATCH 3/4] package-lock updated --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 018a0705e..e10725348 100644 --- a/package-lock.json +++ b/package-lock.json @@ -244,7 +244,7 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, "archy": { @@ -11183,7 +11183,7 @@ "node-sass": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.7.2.tgz", - "integrity": "sha1-k2Z3i6FGnrAUOKnoWS9CYry2eU4=", + "integrity": "sha512-CaV+wLqZ7//Jdom5aUFCpGNoECd7BbNhjuwdsX/LkXBrHl8eb1Wjw4HvWqcFvhr5KuNgAk8i/myf/MQ1YYeroA==", "dev": true, "requires": { "async-foreach": "0.1.3", @@ -11401,7 +11401,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "requires": { "are-we-there-yet": "1.1.4", @@ -15164,7 +15164,7 @@ "wide-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "requires": { "string-width": "1.0.2" From f0356eb0477b4da7ece127667dfa0a7a41403f4f Mon Sep 17 00:00:00 2001 From: Daniel Herrero Date: Tue, 6 Feb 2018 07:59:36 +0100 Subject: [PATCH 4/4] join addressObservation into list Addresses service --- services/loopback/common/methods/client/listAddresses.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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;