Subject: [pgAdmin4][RM#3140] Add service parameter

From: Murtuza Zabuawala <[email-masked]>
Date: Fri, 9 Mar 2018 17:17:36 +0530

Hi,

PFA patch to add service parameter in server dialog.
- Docs updated
- Test case added for Service ID parameter

Please note,
I have extracted Connection class and Server manager class from our own
custom Psycopg2 driver module.

Patch also covers RM#3120

Please review.

--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

---

From: Dave Page <[email-masked]>
Date: Fri, 9 Mar 2018 15:55:01 +0000

HI

> Patch also covers RM#3120

 This patch seems a little confused. The "Service" and "Service ID" fields
from pgAdmin 3 are very different things. The Redmine ticket seems to be
asking for the Service field (the pg_service.conf service name), *not*
Service ID (the operating system's service ID, used to start/stop the
database server service).

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

---

From: Murtuza Zabuawala <[email-masked]>
Date: Fri, 9 Mar 2018 21:29:18 +0530

Hi Dave,

I'll change the name and send you updated patch.

On Fri, Mar 9, 2018 at 9:25 PM, Dave Page <[email-masked]> wrote:

> HI
>
> On Fri, Mar 9, 2018 at 11:47 AM, Murtuza Zabuawala <murtuza.zabuawala@
> enterprisedb.com> wrote:
>
>> Hi,
>>

---

From: Murtuza Zabuawala <[email-masked]>
Date: Mon, 12 Mar 2018 13:01:24 +0530

Hi Dave,

PFA updated patch.

On Fri, Mar 9, 2018 at 9:29 PM, Murtuza Zabuawala <
[email-masked]> wrote:

>>  This patch seems a little confused. The "Service" and "Service ID"
>> fields from pgAdmin 3 are very different things. The Redmine ticket seems
>> to be asking for the Service field (the pg_service.conf service name),
>> *not* Service ID (the operating system's service ID, used to start/stop the

---

From: Dave Page <[email-masked]>
Date: Mon, 12 Mar 2018 16:46:11 -0400

Thanks, patch applied!

On Mon, Mar 12, 2018 at 3:31 AM, Murtuza Zabuawala <
[email-masked]> wrote:

> On Fri, Mar 9, 2018 at 9:29 PM, Murtuza Zabuawala <murtuza.zabuawala@
> enterprisedb.com> wrote:
>
>> Hi Dave,
>>

---

From: Joao De Almeida Pereira <[email-masked]>
Date: Mon, 12 Mar 2018 21:18:50 +0000

Hi Dave and Murtuza,

Regarding this patch we refactored the Javascript code so that is lives in
a different file and added some tests.

Also we found an issue with karma-jasmine that does not allow us to use
jasmine 3.1 yet. You can find attached a patch that reverts that commit.

Thanks
Victoria && Joao

On Mon, Mar 12, 2018 at 4:46 PM Dave Page <[email-masked]> wrote:

>>>>> I have extracted Connection class and Server manager class from our
>>>>> own custom Psycopg2 driver module.
>>>>>
diff --git a/web/package.json b/web/package.json
index ad0f3e16..66684fc6 100644
--- a/web/package.json
+++ b/web/package.json
@@ -69,6 +69,7 @@
     "hard-source-webpack-plugin": "^0.4.9",
     "immutability-helper": "^2.2.0",
     "imports-loader": "^0.7.1",
+    "ip-address": "^5.8.9",
     "jquery": "1.11.2",
     "jquery-contextmenu": "^2.5.0",
     "jquery-ui": "^1.12.1",
diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js
index 53be2255..302fe458 100644
--- a/web/pgadmin/browser/server_groups/servers/static/js/server.js
+++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js
@@ -2,10 +2,13 @@ define('pgadmin.node.server', [
   'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
   'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
   'pgadmin.server.supported_servers', 'pgadmin.user_management.current_user',
-  'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.browser.server.privilege',
+  'pgadmin.alertifyjs', 'pgadmin.backform',
+  'sources/browser/server_groups/servers/model_validation',
+  'pgadmin.browser.server.privilege',
 ], function(
   gettext, url_for, $, _, Backbone, S, pgAdmin, pgBrowser,
-  supported_servers, current_user, Alertify, Backform
+  supported_servers, current_user, Alertify, Backform,
+  modelValidation
 ) {
 
   if (!pgBrowser.Nodes['server']) {
@@ -848,110 +851,8 @@ define('pgadmin.node.server', [
           group: gettext('Connection'),
         }],
         validate: function() {
-          var err = {},
-            errmsg,
-            self = this;
-
-          var service_id = this.get('service');
-
-          var check_for_empty = function(id, msg) {
-            var v = self.get(id);
-            if (
-              _.isUndefined(v) || v === null || String(v).replace(/^\s+|\s+$/g, '') == ''
-            ) {
-              err[id] = msg;
-              errmsg = errmsg || msg;
-              return true;
-            } else {
-              self.errorModel.unset(id);
-              return false;
-            }
-          };
-          var check_for_valid_ipv6 = function(val){
-            // Regular expression for validating IPv6 address formats
-            var exps = ['^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|',
-              '(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|',
-              '2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|',
-              '(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|',
-              ':((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|',
-              '(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|',
-              '2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|',
-              '(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|',
-              '[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|',
-              '((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|',
-              '(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|',
-              '1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|',
-              '((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$'];
-
-            var exp = new RegExp(exps.join(''));
-            return exp.test(val.trim());
-          };
-          var check_for_valid_ip = function(id, msg) {
-            var v4exps = '(^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)';
-            var v4exp = new RegExp(v4exps);
-            var v = self.get(id);
-            if (
-              v && !(v4exp.test(v.trim()))
-            ) {
-              if(!check_for_valid_ipv6(v)){
-                err[id] = msg;
-                errmsg = msg;
-              }
-            } else {
-              self.errorModel.unset(id);
-            }
-          };
-
-          if (!self.isNew() && 'id' in self.sessAttrs) {
-            err['id'] = gettext('The ID cannot be changed.');
-            errmsg = err['id'];
-          } else {
-            self.errorModel.unset('id');
-          }
-          check_for_empty('name', gettext('Name must be specified.'));
-
-          // If no service id then only check
-          if (
-              _.isUndefined(service_id) || _.isNull(service_id) ||
-              String(service_id).replace(/^\s+|\s+$/g, '') == ''
-            ) {
-            if (check_for_empty(
-              'host', gettext('Either Host name or Host address must be specified.')
-            ) && check_for_empty('hostaddr', gettext('Either Host name or Host address must be specified.'))){
-              errmsg = errmsg || gettext('Either Host name or Host address must be specified');
-            } else {
-              errmsg = undefined;
-              delete err['host'];
-              delete err['hostaddr'];
-            }
-
-            check_for_empty(
-              'db', gettext('Maintenance database must be specified.')
-            );
-            check_for_valid_ip(
-              'hostaddr', gettext('Host address must be valid IPv4 or IPv6 address.')
-            );
-            check_for_valid_ip(
-              'hostaddr', gettext('Host address must be valid IPv4 or IPv6 address.')
-            );
-          } else {
-            _.each(['host', 'hostaddr', 'db'], (item) => {
-              self.errorModel.unset(item);
-            });
-          }
-
-          check_for_empty(
-            'username', gettext('Username must be specified.')
-          );
-          check_for_empty('port', gettext('Port must be specified.'));
-
-          this.errorModel.set(err);
-
-          if (_.size(err)) {
-            return errmsg;
-          }
-
-          return null;
+          const validateModel = new modelValidation.ModelValidation(this);
+          return validateModel.validate();
         },
         isConnected: function(model) {
           return model.get('connected');
diff --git a/web/pgadmin/static/bundle/browser.js b/web/pgadmin/static/bundle/browser.js
index 3fcc69d8..83b2ad8b 100644
--- a/web/pgadmin/static/bundle/browser.js
+++ b/web/pgadmin/static/bundle/browser.js
@@ -1,6 +1,6 @@
 define('bundled_browser',[
   'pgadmin.browser',
-  'sources/browser/server_groups/servers/databases/external_tables/index',
+  'sources/browser/index',
 ], function(pgBrowser) {
   pgBrowser.init();
 });
diff --git a/web/pgadmin/static/js/browser/index.js b/web/pgadmin/static/js/browser/index.js
new file mode 100644
index 00000000..297e8bf9
--- /dev/null
+++ b/web/pgadmin/static/js/browser/index.js
@@ -0,0 +1,10 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import 'server_groups';
diff --git a/web/pgadmin/static/js/browser/server_groups/index.js b/web/pgadmin/static/js/browser/server_groups/index.js
new file mode 100644
index 00000000..b151b6f6
--- /dev/null
+++ b/web/pgadmin/static/js/browser/server_groups/index.js
@@ -0,0 +1,10 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import 'servers';
diff --git a/web/pgadmin/static/js/browser/server_groups/servers/databases/index.js b/web/pgadmin/static/js/browser/server_groups/servers/databases/index.js
new file mode 100644
index 00000000..ef17c0ad
--- /dev/null
+++ b/web/pgadmin/static/js/browser/server_groups/servers/databases/index.js
@@ -0,0 +1,10 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import 'external_tables';
diff --git a/web/pgadmin/static/js/browser/server_groups/servers/index.js b/web/pgadmin/static/js/browser/server_groups/servers/index.js
new file mode 100644
index 00000000..242a1919
--- /dev/null
+++ b/web/pgadmin/static/js/browser/server_groups/servers/index.js
@@ -0,0 +1,11 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import 'databases';
+import 'model_validation';
diff --git a/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js
new file mode 100644
index 00000000..feb4e6bd
--- /dev/null
+++ b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js
@@ -0,0 +1,104 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import gettext from 'sources/gettext';
+import _ from 'underscore';
+import {Address4, Address6} from 'ip-address';
+
+export class ModelValidation {
+  constructor(model) {
+    this.err = {};
+    this.errmsg = '';
+    this.model = model;
+  }
+
+  validate() {
+    const serviceId = this.model.get('service');
+
+    if (!this.model.isNew() && 'id' in this.model.sessAttrs) {
+      this.err['id'] = gettext('The ID cannot be changed.');
+      this.errmsg = this.err['id'];
+    } else {
+      this.model.errorModel.unset('id');
+    }
+
+    this.checkForEmpty('name', gettext('Name must be specified.'));
+
+    if (ModelValidation.isEmptyString(serviceId)) {
+      this.checkHostAndHostAddress();
+
+      this.checkForEmpty('db', gettext('Maintenance database must be specified.'));
+    } else {
+      this.clearHostAddressAndDbErrors();
+    }
+
+    this.checkForEmpty('username', gettext('Username must be specified.'));
+    this.checkForEmpty('port', gettext('Port must be specified.'));
+
+    this.model.errorModel.set(this.err);
+
+    if (_.size(this.err)) {
+      return this.errmsg;
+    }
+
+    return null;
+  }
+
+  clearHostAddressAndDbErrors() {
+    _.each(['host', 'hostaddr', 'db'], (item) => {
+      this.model.errorModel.unset(item);
+    });
+  }
+
+  checkHostAndHostAddress() {
+    const translatedStr = gettext('Either Host name or Host address must be' +
+      ' specified.');
+    if (this.checkForEmpty('host', translatedStr) &&
+      this.checkForEmpty('hostaddr', translatedStr)) {
+      this.errmsg = this.errmsg || translatedStr;
+    } else {
+      this.errmsg = undefined;
+      delete this.err['host'];
+      delete this.err['hostaddr'];
+    }
+
+    this.checkForValidIp(this.model.get('hostaddr'),
+      gettext('Host address must be valid IPv4 or IPv6 address.'));
+  }
+
+  checkForValidIp(ipAddress, msg) {
+    if (ipAddress) {
+      const isIpv6Address = new Address6(ipAddress).isValid();
+      const isIpv4Address = new Address4(ipAddress).isValid();
+      if (!isIpv4Address && !isIpv6Address) {
+        this.err['hostaddr'] = msg;
+        this.errmsg = msg;
+      }
+    } else {
+      this.model.errorModel.unset('hostaddr');
+    }
+  }
+
+  checkForEmpty(id, msg) {
+    const value = this.model.get(id);
+
+    if (ModelValidation.isEmptyString(value)) {
+      this.err[id] = msg;
+      this.errmsg = this.errmsg || msg;
+      return true;
+    } else {
+      this.model.errorModel.unset(id);
+      return false;
+    }
+  }
+
+  static isEmptyString(string) {
+    return _.isUndefined(string) || _.isNull(string) || string.trim() === '';
+  }
+}
diff --git a/web/regression/javascript/browser/server_groups/servers/model_validation_spec.js b/web/regression/javascript/browser/server_groups/servers/model_validation_spec.js
new file mode 100644
index 00000000..f0b13a8d
--- /dev/null
+++ b/web/regression/javascript/browser/server_groups/servers/model_validation_spec.js
@@ -0,0 +1,101 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import {ModelValidation} from 'sources/browser/server_groups/servers/model_validation';
+
+describe('Server#ModelValidation', () => {
+  describe('When validating a server parameters', () => {
+    let model;
+    let modelValidation;
+    beforeEach(() => {
+      model = {
+        errorModel: jasmine.createSpyObj('errorModel', ['set', 'unset']),
+        allValues: {},
+        get: function (key) {
+          return this.allValues[key];
+        },
+        sessAttrs: {},
+      };
+      model.isNew = jasmine.createSpy('isNew');
+      modelValidation = new ModelValidation(model);
+    });
+
+    describe('When all parameters are valid', () => {
+      beforeEach(() => {
+        model.isNew.and.returnValue(true);
+        model.allValues['name'] = 'some name';
+        model.allValues['username'] = 'some username';
+        model.allValues['port'] = 'some port';
+      });
+
+      describe('No service id', () => {
+        it('does not set any error in the model', () => {
+          model.allValues['host'] = 'some host';
+          model.allValues['db'] = 'some db';
+          model.allValues['hostaddr'] = '1.1.1.1';
+          expect(modelValidation.validate()).toBeNull();
+          expect(model.errorModel.set).toHaveBeenCalledWith({});
+        });
+      });
+
+      describe('Service id present', () => {
+        it('does not set any error in the model', () => {
+          model.allValues['service'] = 'asdfg';
+          expect(modelValidation.validate()).toBeNull();
+          expect(model.errorModel.set).toHaveBeenCalledWith({});
+        });
+      });
+    });
+
+    describe('When no parameters are valid', () => {
+      describe('Service id not present', () => {
+        it('does not set any error in the model', () => {
+          expect(modelValidation.validate()).toBe('Name must be specified.');
+          expect(model.errorModel.set).toHaveBeenCalledTimes(1);
+          expect(model.errorModel.set).toHaveBeenCalledWith({
+            name: 'Name must be specified.',
+            host: 'Either Host name or Host address must be specified.',
+            hostaddr: 'Either Host name or Host address must be specified.',
+            db: 'Maintenance database must be specified.',
+            username: 'Username must be specified.',
+            port: 'Port must be specified.'
+          });
+        });
+      });
+
+      describe('Host address is not valid', () => {
+        it('sets the "Host address must be a valid IPv4 or IPv6 address" error', () => {
+          model.allValues['hostaddr'] = 'something that is not an ip address';
+          expect(modelValidation.validate()).toBe('Host address must be valid IPv4 or IPv6 address.');
+          expect(model.errorModel.set).toHaveBeenCalledTimes(1);
+          expect(model.errorModel.set).toHaveBeenCalledWith({
+            name: 'Name must be specified.',
+            hostaddr: 'Host address must be valid IPv4 or IPv6 address.',
+            db: 'Maintenance database must be specified.',
+            username: 'Username must be specified.',
+            port: 'Port must be specified.'
+          });
+        });
+      });
+
+      describe('Service id present', () => {
+        it('does not set any error in the model', () => {
+          model.allValues['service'] = 'asdfg';
+          expect(modelValidation.validate()).toBe('Name must be specified.');
+          expect(model.errorModel.set).toHaveBeenCalledTimes(1);
+          expect(model.errorModel.set).toHaveBeenCalledWith({
+            name: 'Name must be specified.',
+            username: 'Username must be specified.',
+            port: 'Port must be specified.'
+          });
+        });
+      });
+    });
+  });
+});
diff --git a/web/yarn.lock b/web/yarn.lock
index 85ccbc8b..2dc4c5c2 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -3938,6 +3938,18 @@ invert-kv@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
 
+ip-address@^5.8.9:
+  version "5.8.9"
+  resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.8.9.tgz#6379277c23fc5adb20511e4d23ec2c1bde105dfd"
+  dependencies:
+    jsbn "1.1.0"
+    lodash.find "^4.6.0"
+    lodash.max "^4.0.1"
+    lodash.merge "^4.6.0"
+    lodash.padstart "^4.6.1"
+    lodash.repeat "^4.1.0"
+    sprintf-js "1.1.0"
+
 ip-regex@^1.0.1:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd"
@@ -4329,6 +4341,10 @@ js-yaml@~3.7.0:
     argparse "^1.0.7"
     esprima "^2.6.0"
 
[email-masked]:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
+
 jsbn@~0.1.0:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@@ -4738,6 +4754,10 @@ lodash.escape@^3.0.0:
   dependencies:
     lodash._root "^3.0.0"
 
+lodash.find@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
+
 lodash.flattendeep@^4.4.0:
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
@@ -4777,6 +4797,10 @@ lodash.keys@^3.0.0:
     lodash.isarguments "^3.0.0"
     lodash.isarray "^3.0.0"
 
+lodash.max@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a"
+
 lodash.memoize@^4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -4785,10 +4809,22 @@ lodash.memoize@~3.0.3:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f"
 
+lodash.merge@^4.6.0:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
+
 lodash.mergewith@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
 
+lodash.padstart@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
+
+lodash.repeat@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44"
+
 lodash.restparam@^3.0.0:
   version "3.6.1"
   resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
@@ -6863,6 +6899,10 @@ spectrum-colorpicker@^1.8.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/spectrum-colorpicker/-/spectrum-colorpicker-1.8.0.tgz#b926cf5002c0a77860b5f8351e1c093c65200107"
 
[email-masked]:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
+
 sprintf-js@^1.0.3:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
diff --git a/web/package.json b/web/package.json
index ad0f3e16..a4cb58d5 100644
--- a/web/package.json
+++ b/web/package.json
@@ -18,7 +18,7 @@
     "file-loader": "^0.11.2",
     "image-webpack-loader": "^3.3.1",
     "is-docker": "^1.1.0",
-    "jasmine-core": "~2.99.0",
+    "jasmine-core": "~3.1.0",
     "jasmine-enzyme": "~4.1.1",
     "karma": "~1.5.0",
     "karma-babel-preprocessor": "^6.0.1",
diff --git a/web/yarn.lock b/web/yarn.lock
index 85ccbc8b..5e310d79 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -4267,9 +4267,9 @@ isurl@^1.0.0-alpha5:
     has-to-string-tag-x "^1.2.0"
     is-object "^1.0.1"
 
-jasmine-core@~2.99.0:
-  version "2.99.1"
-  resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"
+jasmine-core@~3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.1.0.tgz#a4785e135d5df65024dfc9224953df585bd2766c"
 
 jasmine-enzyme@~4.1.1:
   version "4.1.1"

---

From: Dave Page <[email-masked]>
Date: Mon, 12 Mar 2018 20:48:19 -0400

Hi

> jasmine 3.1 yet. You can find attached a patch that reverts that commit.

Sounds good, but neither patch will apply (in fact, the Jasmine one looks
entirely backwards). One of the error messages was changed in Murtuza's
patch, and wasn't reflected in your update for example.

Can you rebase please?

Thanks.

>> On Mon, Mar 12, 2018 at 3:31 AM, Murtuza Zabuawala <murtuza.zabuawala@
>> enterprisedb.com> wrote:
>>
>>> Hi Dave,
>>>
>>> PFA updated patch.
>>>
>>> --
>>> Regards,
>>> Murtuza Zabuawala

---

From: Ashesh Vashi <[email-masked]>
Date: Tue, 13 Mar 2018 09:01:22 +0530

Murtuza/Dave,

I have to reviewed/seen the patch yet.
But - I have a question.
Have we used the service file in the external tools for backup, restore,
and import/export functionalities?
If not - we should fix that asap.

We had missed that during SSL support, and now - we're fixing that.

--

Thanks & Regards,

Ashesh Vashi
EnterpriseDB INDIA: Enterprise PostgreSQL Company
<http://www.enterprisedb.com>

*http://www.linkedin.com/in/asheshvashi*
<http://www.linkedin.com/in/asheshvashi>

On Tue, Mar 13, 2018 at 6:18 AM, Dave Page <[email-masked]> wrote:

>> Regarding this patch we refactored the Javascript code so that is lives
>> in a different file and added some tests.
>>

---

From: Murtuza Zabuawala <[email-masked]>
Date: Tue, 13 Mar 2018 09:42:40 +0530

Hi Ashesh,

I haven't implemented that intentionally because Khushboo is working on the
same for SSL and our code will conflict, So once Khushboo's patch gets
committed, I'll make changes for Service file as well.

On Tue, Mar 13, 2018 at 9:01 AM, Ashesh Vashi <[email-masked]
> wrote:

---

From: Ashesh Vashi <[email-masked]>
Date: Tue, 13 Mar 2018 09:45:00 +0530

On Tue, Mar 13, 2018 at 9:42 AM, Murtuza Zabuawala <
[email-masked]> wrote:

> Hi Ashesh,
>
> I haven't implemented that intentionally because Khushboo is working on
> the same for SSL and our code will conflict, So once Khushboo's patch gets
No - that's a bad practice.
You need to work on full feature set, not partial.

If you have intentionally skipped that, you should have informed the list.

-- Thanks, Ashesh

> On Tue, Mar 13, 2018 at 9:01 AM, Ashesh Vashi <
> [email-masked]> wrote:
>
>> Murtuza/Dave,
>>
>>> Sounds good, but neither patch will apply (in fact, the Jasmine one
>>> looks entirely backwards). One of the error messages was changed in
>>> Murtuza's patch, and wasn't reflected in your update for example.
>>>
>>> Can you rebase please?
>>>
>>> Thanks.
>>>
>>>
>>>>
>>>> Thanks
>>>> Victoria && Joao
>>>>
>>>>>>>>> I have extracted Connection class and Server manager class from
>>>>>>>>> our own custom Psycopg2 driver module.
>>>>>>>>>

---

From: Murtuza Zabuawala <[email-masked]>
Date: Tue, 13 Mar 2018 10:05:48 +0530

On Tue, Mar 13, 2018 at 9:45 AM, Ashesh Vashi <[email-masked]

>
> On Tue, Mar 13, 2018 at 9:42 AM, Murtuza Zabuawala <murtuza.zabuawala@
> enterprisedb.com> wrote:
>
>> Hi Ashesh,
>>

​I forgot to create sub-task, will keep that in mind next time onwards.​
https://redmine.postgresql.org/issues/3195

>>>>> Regarding this patch we refactored the Javascript code so that is
>>>>> lives in a different file and added some tests.
>>>>>
>>>>> Also we found an issue with karma-jasmine that does not allow us to
>>>>> use jasmine 3.1 yet. You can find attached a patch that reverts that commit.
>>>>>
>>>>
>>>>>>>>>  This patch seems a little confused. The "Service" and "Service
>>>>>>>>> ID" fields from pgAdmin 3 are very different things. The Redmine ticket
>>>>>>>>> seems to be asking for the Service field (the pg_service.conf service
>>>>>>>>> name), *not* Service ID (the operating system's service ID, used to
>>>>>>>>> start/stop the database server service).
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Dave Page

---

From: Dave Page <[email-masked]>
Date: Tue, 13 Mar 2018 07:45:57 -0400

> committed, I'll make changes for Service file as well.

Ashesh is right - this should have been finished (and I should have thought
about this issue).

Please fix ASAP.

Thanks.

---

From: Victoria Henry <[email-masked]>
Date: Tue, 13 Mar 2018 09:53:34 -0400

Hi Dave,

We've made updated our previous patch to fix the error messages.  Attached
are our updated patches.

index 36908733..302fe458 100644
 
-              'host', gettext('Either Host name, Address or Service must be specified.')
-            ) && check_for_empty('hostaddr', gettext('Either Host name, Address or Service must be specified.'))){
-              errmsg = errmsg || gettext('Either Host name, Address or Service must be specified.');
index 00000000..7ab129ba
+    const translatedStr = gettext('Either Host name, Address or Service must ' +
+      'be specified.');
index 00000000..a05cd455
+            host: 'Either Host name, Address or Service must be specified.',
+            hostaddr: 'Either Host name, Address or Service must be specified.',
 
+ip-address@^5.8.9:
+  version "5.8.9"
 
[email-masked]:
+  version "1.1.0"
 
+lodash.find@^4.6.0:
+  version "4.6.0"
 
+lodash.max@^4.0.1:
+  version "4.0.1"
 
+lodash.merge@^4.6.0:
+  version "4.6.1"
 
+lodash.padstart@^4.6.1:
+  version "4.6.1"
 
[email-masked]:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
+
 sprintf-js@^1.0.3:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
diff --git a/web/package.json b/web/package.json
index a4cb58d5..ad0f3e16 100644
--- a/web/package.json
+++ b/web/package.json
@@ -18,7 +18,7 @@
     "file-loader": "^0.11.2",
     "image-webpack-loader": "^3.3.1",
     "is-docker": "^1.1.0",
-    "jasmine-core": "~3.1.0",
+    "jasmine-core": "~2.99.0",
     "jasmine-enzyme": "~4.1.1",
     "karma": "~1.5.0",
     "karma-babel-preprocessor": "^6.0.1",
diff --git a/web/yarn.lock b/web/yarn.lock
index 5e310d79..85ccbc8b 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -4267,9 +4267,9 @@ isurl@^1.0.0-alpha5:
     has-to-string-tag-x "^1.2.0"
     is-object "^1.0.1"
 
-jasmine-core@~3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.1.0.tgz#a4785e135d5df65024dfc9224953df585bd2766c"
+jasmine-core@~2.99.0:
+  version "2.99.1"
+  resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"
 
 jasmine-enzyme@~4.1.1:
   version "4.1.1"

---

From: Dave Page <[email-masked]>
Date: Tue, 13 Mar 2018 14:47:49 -0400

Thanks, patches applied!