Refactor server dialogue validation for better unit testing.
Victoria & Joao @ Pivotal.pull/9/head
parent
156b308fd3
commit
6b03cb78af
|
@ -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",
|
||||
|
@ -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",
|
||||
|
|
|
@ -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, 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.');
|
||||
} 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');
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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';
|
|
@ -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';
|
|
@ -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';
|
|
@ -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';
|
|
@ -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, Address or Service 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() === '';
|
||||
}
|
||||
}
|
|
@ -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, Address or Service must be specified.',
|
||||
hostaddr: 'Either Host name, Address or Service 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.'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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"
|
||||
|
@ -4267,9 +4279,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"
|
||||
|
@ -4329,6 +4341,10 @@ js-yaml@~3.7.0:
|
|||
argparse "^1.0.7"
|
||||
esprima "^2.6.0"
|
||||
|
||||
jsbn@1.1.0:
|
||||
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"
|
||||
|
||||
sprintf-js@1.1.0:
|
||||
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"
|
||||
|
|
Loading…
Reference in New Issue