mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
@@ -31,7 +31,5 @@ jobs:
|
||||
run: yarn run gulp client
|
||||
working-directory: client
|
||||
- name: Run Unit Tests
|
||||
run: yarn run qunit
|
||||
working-directory: client
|
||||
- run: yarn jest
|
||||
working-directory: client
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
"vuejs-accessibility/no-autofocus": "error",
|
||||
"vuejs-accessibility/tabindex-no-positive": "error"
|
||||
},
|
||||
"ignorePatterns": ["dist", "src/qunit", "src/mocha", "src/libs", "src/nls", "src/legacy"],
|
||||
"ignorePatterns": ["dist", "src/libs", "src/nls", "src/legacy"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.vue"],
|
||||
|
||||
+1
-13
@@ -122,10 +122,6 @@ utils](https://vue-test-utils.vuejs.org/) to mount individual components in a
|
||||
test bed and check them for rendered features. Please use jest-based mocking
|
||||
for isolating test functionality.
|
||||
|
||||
A set of older qUnit tests also exist which will be phased-out as the code they
|
||||
support is replaced with modern component-based implementations. In the
|
||||
meantime, we still run the qunit tests in sequence.
|
||||
|
||||
### Running the tests
|
||||
|
||||
#### At Build-Time
|
||||
@@ -145,15 +141,7 @@ commands.
|
||||
This is what CI is going to run, and also what 'make client-test' invokes,
|
||||
executing all the client tests:
|
||||
|
||||
yarn run test
|
||||
|
||||
You can also bypass qunit and single-run all of the jest tests like so:
|
||||
|
||||
yarn run jest
|
||||
|
||||
Or, if you want to run just the qunit tests:
|
||||
|
||||
yarn run qunit
|
||||
yarn test
|
||||
|
||||
##### Watch and rerun jest unit tests every time a source file changes
|
||||
|
||||
|
||||
+1
-8
@@ -128,10 +128,9 @@
|
||||
"format": "prettier --write . --cache",
|
||||
"format-check": "prettier --check .",
|
||||
"prettier": "yarn run format",
|
||||
"test": "yarn run qunit && yarn run jest",
|
||||
"test": "yarn run jest",
|
||||
"jest": "jest --config tests/jest/jest.config.js",
|
||||
"jest-watch": "jest --config tests/jest/jest.config.js --watch",
|
||||
"qunit": "karma start tests/karma/karma.config.qunit.js",
|
||||
"eslint-precommit": "eslint -c .eslintrc.json --quiet --ext .js,.vue,.ts src tests/jest/standalone",
|
||||
"eslint": "eslint -c .eslintrc.json --ext .js,.vue,.ts src tests/jest/standalone"
|
||||
},
|
||||
@@ -170,16 +169,10 @@
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest-location-mock": "^1.0.9",
|
||||
"json-loader": "^0.5.7",
|
||||
"karma": "^6.3.16",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-polyfill": "^1.1.0",
|
||||
"karma-qunit": "^4.1.2",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"mini-css-extract-plugin": "^2.5.3",
|
||||
"postcss-loader": "^7.0.2",
|
||||
"prettier": "^2.8.3",
|
||||
"process": "^0.11.10",
|
||||
"qunit": "^2.17.2",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass": "^1.58.0",
|
||||
"sass-loader": "^13.2.0",
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { getGalaxyInstance, setGalaxyInstance } from "app";
|
||||
import Backbone from "backbone";
|
||||
import galaxyOptions from "@tests/test-data/bootstrapped";
|
||||
|
||||
export function setupTestGalaxy(galaxyOptions_ = null) {
|
||||
galaxyOptions_ = galaxyOptions_ || galaxyOptions;
|
||||
setGalaxyInstance((GalaxyApp) => {
|
||||
const galaxy = new GalaxyApp(galaxyOptions_);
|
||||
galaxy.currHistoryPanel = {
|
||||
model: new Backbone.Model(),
|
||||
};
|
||||
return galaxy;
|
||||
});
|
||||
}
|
||||
|
||||
describe("App base construction/initializiation defaults", () => {
|
||||
beforeEach(() => {
|
||||
setupTestGalaxy(galaxyOptions);
|
||||
});
|
||||
|
||||
test("App base construction/initializiation defaults", function () {
|
||||
const app = getGalaxyInstance();
|
||||
expect(app.options && typeof app.options === "object").toBeTruthy();
|
||||
expect(app.config && typeof app.config === "object").toBeTruthy();
|
||||
expect(app.user && typeof app.config === "object").toBeTruthy();
|
||||
expect(app.localize).toBe(window._l);
|
||||
});
|
||||
|
||||
test("App base default options", function () {
|
||||
const app = getGalaxyInstance();
|
||||
expect(app.options !== undefined && typeof app.options === "object").toBeTruthy();
|
||||
expect(app.options.root).toBe("/");
|
||||
expect(app.options.patchExisting).toBe(true);
|
||||
});
|
||||
|
||||
test("App base extends from Backbone.Events", function () {
|
||||
const app = getGalaxyInstance();
|
||||
["on", "off", "trigger", "listenTo", "stopListening"].forEach(function (fn) {
|
||||
expect(Object.prototype.hasOwnProperty.call(app, fn) && typeof app[fn] === "function").toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
// // We no longer want this behavior, but leaving the test to express that
|
||||
test("App base will patch in attributes from existing Galaxy objects", function () {
|
||||
const existingApp = getGalaxyInstance();
|
||||
existingApp.foo = 123;
|
||||
|
||||
const newApp = setGalaxyInstance((GalaxyApp) => {
|
||||
return new GalaxyApp();
|
||||
});
|
||||
|
||||
expect(newApp.foo === 123).toBeTruthy();
|
||||
});
|
||||
|
||||
test("App base config", function () {
|
||||
const app = getGalaxyInstance();
|
||||
expect(app.config && typeof app.config === "object").toBeTruthy();
|
||||
expect(app.config.allow_user_deletion).toBe(false);
|
||||
expect(app.config.allow_user_creation).toBe(true);
|
||||
expect(app.config.wiki_url).toBe("https://galaxyproject.org/");
|
||||
expect(app.config.ftp_upload_site).toBe(null);
|
||||
});
|
||||
|
||||
test("App base user", function () {
|
||||
const app = getGalaxyInstance();
|
||||
expect(app.user !== undefined && typeof app.user === "object").toBeTruthy();
|
||||
expect(app.user.isAdmin() === false).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,42 +1,8 @@
|
||||
import $ from "jquery";
|
||||
import _ from "underscore";
|
||||
import Backbone from "backbone";
|
||||
import addLogging from "utils/add-logging";
|
||||
import _l from "utils/localization";
|
||||
|
||||
//==============================================================================
|
||||
/** @class Mixin to add logging capabilities to an object.
|
||||
* Designed to allow switching an objects log output off/on at one central
|
||||
* statement. Can be used with plain browser console (or something more
|
||||
* complex like an AJAX logger).
|
||||
* <br />NOTE: currently only uses the console.debug log function
|
||||
* (as opposed to debug, error, warn, etc.)
|
||||
* @name LoggableMixin
|
||||
*
|
||||
* @example
|
||||
* // Add to your models/views at the definition using chaining:
|
||||
* var MyModel = Backbone.Model.extend( LoggableMixin ).extend({ // ... });
|
||||
*
|
||||
* // or - more explicitly AFTER the definition:
|
||||
* var MyModel = Backbone.Model.extend({
|
||||
* logger : console
|
||||
* // ...
|
||||
* this.log( '$#%& it! - broken already...' );
|
||||
* })
|
||||
* _.extend( MyModel.prototype, LoggableMixin )
|
||||
*
|
||||
*/
|
||||
var LoggableMixin = /** @lends LoggableMixin# */ {
|
||||
// replace null with console (if available) to see all logs for a particular view/model
|
||||
/** The logging object whose log function will be used to output
|
||||
* messages. Null will supress all logging. Commonly set to console.
|
||||
*/
|
||||
logger: null,
|
||||
/** @type {String} a namespace for filtering/focusing log output */
|
||||
_logNamespace: ".",
|
||||
};
|
||||
addLogging(LoggableMixin);
|
||||
|
||||
//==============================================================================
|
||||
/** Backbone model that syncs to the browser's sessionStorage API.
|
||||
* This all largely happens behind the scenes and no special calls are required.
|
||||
@@ -196,7 +162,7 @@ var SearchableModelMixin = {
|
||||
/** search the attribute with key attrKey for the string searchFor; T/F if found */
|
||||
searchAttribute: function (attrKey, searchFor) {
|
||||
var attrVal = this.get(attrKey);
|
||||
//this.debug( 'searchAttribute', attrKey, attrVal, searchFor );
|
||||
//console.debug( 'searchAttribute', attrKey, attrVal, searchFor );
|
||||
// bail if empty searchFor or unsearchable values
|
||||
if (!searchFor || attrVal === undefined || attrVal === null) {
|
||||
return false;
|
||||
@@ -210,7 +176,7 @@ var SearchableModelMixin = {
|
||||
|
||||
/** deep(er) search for array attributes; T/F if found */
|
||||
_searchArrayAttribute: function (array, searchFor) {
|
||||
//this.debug( '_searchArrayAttribute', array, searchFor );
|
||||
//console.debug( '_searchArrayAttribute', array, searchFor );
|
||||
searchFor = searchFor.toLowerCase();
|
||||
//precondition: searchFor has already been validated as non-empty string
|
||||
//precondition: assumes only 1 level array
|
||||
@@ -575,7 +541,6 @@ function buildComparator(attribute_name, options) {
|
||||
|
||||
//==============================================================================
|
||||
export default {
|
||||
LoggableMixin: LoggableMixin,
|
||||
SessionStorageModel: SessionStorageModel,
|
||||
mixin: mixin,
|
||||
SearchableModelMixin: SearchableModelMixin,
|
||||
|
||||
+5
-124
@@ -1,10 +1,7 @@
|
||||
import $ from "jquery";
|
||||
import _ from "underscore";
|
||||
import Backbone from "backbone";
|
||||
import BASE_MVC from "./base-mvc";
|
||||
import userModel from "./user-model";
|
||||
import metricsLogger from "utils/metrics-logger";
|
||||
import addLogging from "utils/add-logging";
|
||||
import { localize, _setUserLocale, _getUserLocale } from "utils/localization";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import { create, dialog } from "utils/data";
|
||||
@@ -12,7 +9,6 @@ import { create, dialog } from "utils/data";
|
||||
// ============================================================================
|
||||
/** Base galaxy client-side application.
|
||||
* Iniitializes:
|
||||
* logger : the logger/metrics-logger
|
||||
* localize : the string localizer
|
||||
* config : the current configuration (any k/v in
|
||||
* galaxy.ini available from the configuration API)
|
||||
@@ -22,29 +18,9 @@ export function GalaxyApp(options = {}, bootstrapped = {}) {
|
||||
this._init(options, bootstrapped);
|
||||
}
|
||||
|
||||
// add logging shortcuts for this object
|
||||
addLogging(GalaxyApp, "GalaxyApp");
|
||||
|
||||
// a debug flag can be set via local storage and made available during script/page loading
|
||||
const DEBUGGING_KEY = "galaxy:debug";
|
||||
|
||||
const NAMESPACE_KEY = `${DEBUGGING_KEY}:namespaces`;
|
||||
const FLATTEN_LOG_MESSAGES_KEY = `${DEBUGGING_KEY}:flatten`;
|
||||
|
||||
let localDebugging = false;
|
||||
try {
|
||||
localDebugging = localStorage.getItem(DEBUGGING_KEY) == "true";
|
||||
} catch (storageErr) {
|
||||
console.log(localize("localStorage not available for debug flag retrieval"));
|
||||
}
|
||||
|
||||
/** initalize options and sub-components */
|
||||
GalaxyApp.prototype._init = function (options, bootstrapped) {
|
||||
_.extend(this, Backbone.Events);
|
||||
if (localDebugging) {
|
||||
this.logger = console;
|
||||
console.debug("debugging galaxy:", "options:", options, "bootstrapped:", bootstrapped);
|
||||
}
|
||||
|
||||
this._processOptions(options);
|
||||
this._initConfig(options.config || {});
|
||||
@@ -62,24 +38,15 @@ GalaxyApp.prototype._init = function (options, bootstrapped) {
|
||||
this.params = options.params || {};
|
||||
this.session_csrf_token = options.session_csrf_token || null;
|
||||
|
||||
this._initLogger(this.options.loggerOptions || {});
|
||||
// at this point, either logging or not and namespaces are enabled - chat it up
|
||||
this.debug("GalaxyApp.options: ", this.options);
|
||||
this.debug("GalaxyApp.config: ", this.config);
|
||||
this.debug("GalaxyApp.logger: ", this.logger);
|
||||
|
||||
this._initLocale();
|
||||
this.debug("GalaxyApp.localize: ", this.localize);
|
||||
|
||||
this.config = options.config || {};
|
||||
this.debug("GalaxyApp.config: ", this.config);
|
||||
|
||||
this._initUser(options.user || {});
|
||||
this.debug("GalaxyApp.user: ", this.user);
|
||||
|
||||
_setUserLocale(this.user, this.config);
|
||||
_getUserLocale();
|
||||
this.debug("currentLocale: ", sessionStorage.getItem("currentLocale"));
|
||||
console.debug("currentLocale: ", sessionStorage.getItem("currentLocale"));
|
||||
|
||||
this._setUpListeners();
|
||||
this.trigger("ready", this);
|
||||
@@ -119,9 +86,6 @@ GalaxyApp.prototype._processOptions = function _processOptions(options) {
|
||||
GalaxyApp.prototype._initConfig = function _initConfig(config) {
|
||||
this.config = config;
|
||||
|
||||
// give precendence to localdebugging for this setting
|
||||
this.config.debug = localDebugging || this.config.debug;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -129,56 +93,20 @@ GalaxyApp.prototype._initConfig = function _initConfig(config) {
|
||||
GalaxyApp.prototype._patchGalaxy = function _patchGalaxy(patchWith) {
|
||||
// in case req or plain script tag order has created a prev. version of the Galaxy obj...
|
||||
if (this.options.patchExisting && patchWith) {
|
||||
// this.debug( 'found existing Galaxy object:', patchWith );
|
||||
// console.debug( 'found existing Galaxy object:', patchWith );
|
||||
// ...(for now) monkey patch any added attributes that the previous Galaxy may have had
|
||||
//TODO: move those attributes to more formal assignment in GalaxyApp
|
||||
for (const k in patchWith) {
|
||||
if (Object.prototype.hasOwnProperty.call(patchWith, k)) {
|
||||
// this.debug( '\t patching in ' + k + ' to Galaxy:', this[ k ] );
|
||||
// console.debug( '\t patching in ' + k + ' to Galaxy:', this[ k ] );
|
||||
this[k] = patchWith[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** set up the metrics logger (utils/metrics-logger) and pass loggerOptions */
|
||||
GalaxyApp.prototype._initLogger = function _initLogger(loggerOptions) {
|
||||
// default to console logging at the debug level if the debug flag is set
|
||||
if (this.config.debug) {
|
||||
loggerOptions.consoleLogger = loggerOptions.consoleLogger || console;
|
||||
loggerOptions.consoleLevel = loggerOptions.consoleLevel || metricsLogger.MetricsLogger.ALL;
|
||||
// load any logging namespaces from localStorage if we can
|
||||
try {
|
||||
loggerOptions.consoleNamespaceWhitelist = localStorage.getItem(NAMESPACE_KEY).split(",");
|
||||
} catch (storageErr) {
|
||||
console.debug(storageErr);
|
||||
}
|
||||
try {
|
||||
loggerOptions.consoleFlattenMessages = localStorage.getItem(FLATTEN_LOG_MESSAGES_KEY) == "true";
|
||||
} catch (storageErr) {
|
||||
console.debug(storageErr);
|
||||
}
|
||||
console.log(loggerOptions.consoleFlattenMessages);
|
||||
}
|
||||
|
||||
this.logger = new metricsLogger.MetricsLogger(loggerOptions);
|
||||
this.emit = {};
|
||||
["log", "debug", "info", "warn", "error", "metric"].map((i) => {
|
||||
this.emit[i] = (data) => {
|
||||
this.logger.emit(i, arguments[0], Array.prototype.slice.call(arguments, 1));
|
||||
};
|
||||
});
|
||||
|
||||
if (this.config.debug) {
|
||||
// add this logger to mvc's loggable mixin so that all models can use the logger
|
||||
BASE_MVC.LoggableMixin.logger = this.logger;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/** add the localize fn to this object and the window namespace (as '_l') */
|
||||
GalaxyApp.prototype._initLocale = function _initLocale(options) {
|
||||
this.debug("_initLocale:", options);
|
||||
GalaxyApp.prototype._initLocale = function _initLocale() {
|
||||
this.localize = localize;
|
||||
// add to window as global shortened alias
|
||||
// TODO: temporary - remove when can require for plugins
|
||||
@@ -220,9 +148,8 @@ GalaxyApp.prototype._initUserLocale = function _initUserLocale(options) {
|
||||
|
||||
/** set up the current user as a Backbone model (mvc/user/user-model) */
|
||||
GalaxyApp.prototype._initUser = function _initUser(userJSON) {
|
||||
this.debug("_initUser:", userJSON);
|
||||
console.debug("_initUser:", userJSON);
|
||||
this.user = new userModel.User(userJSON);
|
||||
this.user.logger = this.logger;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -248,52 +175,6 @@ GalaxyApp.prototype._setUpListeners = function _setUpListeners() {
|
||||
return this;
|
||||
};
|
||||
|
||||
/** Turn debugging/console-output on/off by passing boolean. Pass nothing to get current setting. */
|
||||
GalaxyApp.prototype.debugging = function _debugging(setting) {
|
||||
try {
|
||||
if (setting === undefined) {
|
||||
return localStorage.getItem(DEBUGGING_KEY) === "true";
|
||||
}
|
||||
if (setting) {
|
||||
localStorage.setItem(DEBUGGING_KEY, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
localStorage.removeItem(DEBUGGING_KEY);
|
||||
// also remove all namespaces
|
||||
this.debuggingNamespaces(null);
|
||||
} catch (storageErr) {
|
||||
console.log(localize("localStorage not available for debug flag retrieval"));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Add, remove, or clear namespaces from the debugging filters
|
||||
* Pass no arguments to retrieve the existing namespaces as an array.
|
||||
* Pass in null to clear all namespaces (all logging messages will show now).
|
||||
* Pass in an array of strings or single string of the namespaces to filter to.
|
||||
* Returns the new/current namespaces as an array;
|
||||
*/
|
||||
GalaxyApp.prototype.debuggingNamespaces = function _debuggingNamespaces(namespaces) {
|
||||
try {
|
||||
if (namespaces === undefined) {
|
||||
const csv = localStorage.getItem(NAMESPACE_KEY);
|
||||
return typeof csv === "string" ? csv.split(",") : [];
|
||||
} else if (namespaces === null) {
|
||||
localStorage.removeItem(NAMESPACE_KEY);
|
||||
} else {
|
||||
localStorage.setItem(NAMESPACE_KEY, namespaces);
|
||||
}
|
||||
const newSettings = this.debuggingNamespaces();
|
||||
if (this.logger) {
|
||||
this.logger.options.consoleNamespaceWhitelist = newSettings;
|
||||
}
|
||||
return newSettings;
|
||||
} catch (storageErr) {
|
||||
console.log(localize("localStorage not available for debug namespace retrieval"));
|
||||
}
|
||||
};
|
||||
|
||||
/** string rep */
|
||||
GalaxyApp.prototype.toString = function toString() {
|
||||
const userEmail = this.user ? this.user.get("email") || "(anonymous)" : "uninitialized";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* TODO: Make this part of galaxy.js later, once the global refs are gone
|
||||
*/
|
||||
|
||||
import addLogging from "utils/add-logging";
|
||||
import config from "config";
|
||||
import { GalaxyApp } from "./galaxy";
|
||||
import { serverPath } from "utils/serverPath";
|
||||
@@ -17,9 +16,6 @@ export function setGalaxyInstance(factory) {
|
||||
if (!(newInstance instanceof GalaxyApp)) {
|
||||
newInstance = new GalaxyApp(newInstance);
|
||||
}
|
||||
if (newInstance.debug === undefined) {
|
||||
addLogging(newInstance, "GalaxyApp");
|
||||
}
|
||||
|
||||
storage._galaxyInstance = newInstance;
|
||||
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import Backbone from "backbone";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import baseMVC from "./base-mvc";
|
||||
import _l from "utils/localization";
|
||||
|
||||
var logNamespace = "user";
|
||||
//==============================================================================
|
||||
/** @class Model for a Galaxy user (including anonymous users).
|
||||
* @name User
|
||||
*/
|
||||
var User = Backbone.Model.extend(baseMVC.LoggableMixin).extend(
|
||||
var User = Backbone.Model.extend(
|
||||
/** @lends User.prototype */ {
|
||||
_logNamespace: logNamespace,
|
||||
|
||||
/** API location for this resource */
|
||||
urlRoot: function () {
|
||||
return `${getAppRoot()}api/users`;
|
||||
@@ -36,13 +32,11 @@ var User = Backbone.Model.extend(baseMVC.LoggableMixin).extend(
|
||||
* @param {Object} data Initial model data.
|
||||
*/
|
||||
initialize: function (data) {
|
||||
this.log("User.initialize:", data);
|
||||
|
||||
this.on("loaded", function (model, resp) {
|
||||
this.log(`${this} has loaded:`, model, resp);
|
||||
console.log(`${this} has loaded:`, model, resp);
|
||||
});
|
||||
this.on("change", function (model, data) {
|
||||
this.log(`${this} has changed:`, model, data.changes);
|
||||
console.log(`${this} has changed:`, model, data.changes);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -142,15 +136,6 @@ User.getCurrentUserFromApi = (options) => {
|
||||
return currentUser;
|
||||
};
|
||||
|
||||
// (stub) collection for users (shouldn't be common unless admin UI)
|
||||
//var UserCollection = Backbone.Collection.extend(baseMVC.LoggableMixin).extend({
|
||||
// model: User,
|
||||
// urlRoot: function() {
|
||||
// return `${getAppRoot()}api/users`;
|
||||
// }
|
||||
// //logger : console,
|
||||
//});
|
||||
|
||||
//==============================================================================
|
||||
export default {
|
||||
User: User,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import PairedListCollectionCreator from "components/Collections/PairedListCollectionCreator";
|
||||
import DATA from "../../../tests/qunit/test-data/paired-collection-creator.data.js";
|
||||
import DATA from "@tests/test-data/paired-collection-creator.data.js";
|
||||
|
||||
describe("PairedListCollectionCreator", () => {
|
||||
let wrapper;
|
||||
|
||||
@@ -669,7 +669,7 @@ export default {
|
||||
},
|
||||
/** sort initial list */
|
||||
_sortInitialList: function () {
|
||||
//this.debug( '-- _sortInitialList' );
|
||||
//console.debug( '-- _sortInitialList' );
|
||||
this._sortDatasetList(this.workingElements);
|
||||
},
|
||||
|
||||
@@ -813,7 +813,7 @@ export default {
|
||||
}
|
||||
|
||||
// uncomment to see printlns while running tests
|
||||
//this.debug = function(){ console.log.apply( console, arguments ); };
|
||||
//console.debug = function(){ console.log.apply( console, arguments ); };
|
||||
|
||||
// then try the remainder with something less strict
|
||||
strategy = strategy || this.strategy;
|
||||
@@ -909,7 +909,7 @@ export default {
|
||||
};
|
||||
|
||||
return function _strategy(params) {
|
||||
// this.debug("autopair _strategy ---------------------------");
|
||||
// console.debug("autopair _strategy ---------------------------");
|
||||
params = params || {};
|
||||
var listA = params.listA;
|
||||
var listB = params.listB;
|
||||
@@ -923,8 +923,8 @@ export default {
|
||||
|
||||
var paired = [];
|
||||
//console.debug( 'params:', JSON.stringify( params, null, ' ' ) );
|
||||
// this.debug("starting list lens:", listA.length, listB.length);
|
||||
// this.debug("bestMatch (starting):", JSON.stringify(bestMatch, null, " "));
|
||||
// console.debug("starting list lens:", listA.length, listB.length);
|
||||
// console.debug("bestMatch (starting):", JSON.stringify(bestMatch, null, " "));
|
||||
|
||||
while (indexA < listA.length) {
|
||||
var matchTo = listA[indexA];
|
||||
@@ -932,8 +932,8 @@ export default {
|
||||
|
||||
for (indexB = 0; indexB < listB.length; indexB++) {
|
||||
var possible = listB[indexB];
|
||||
// this.debug(`${indexA}:${matchTo.name}`);
|
||||
// this.debug(`${indexB}:${possible.name}`);
|
||||
// console.debug(`${indexA}:${matchTo.name}`);
|
||||
// console.debug(`${indexB}:${possible.name}`);
|
||||
|
||||
// no matching with self
|
||||
if (listA[indexA] !== listB[indexB]) {
|
||||
@@ -946,16 +946,16 @@ export default {
|
||||
bestMatch: bestMatch,
|
||||
})
|
||||
);
|
||||
// this.debug("bestMatch:", JSON.stringify(bestMatch, null, " "));
|
||||
// console.debug("bestMatch:", JSON.stringify(bestMatch, null, " "));
|
||||
if (bestMatch.score === 1.0) {
|
||||
// this.debug("breaking early due to perfect match");
|
||||
// console.debug("breaking early due to perfect match");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var scoreThreshold = options.scoreThreshold.call(this);
|
||||
// this.debug("scoreThreshold:", scoreThreshold);
|
||||
// this.debug("bestMatch.score:", bestMatch.score);
|
||||
// console.debug("scoreThreshold:", scoreThreshold);
|
||||
// console.debug("bestMatch.score:", bestMatch.score);
|
||||
|
||||
if (bestMatch.score >= scoreThreshold) {
|
||||
//console.debug( 'autoPairFnBuilder.strategy', listA[ indexA ].name, listB[ bestMatch.index ].name );
|
||||
@@ -975,8 +975,8 @@ export default {
|
||||
return paired;
|
||||
}
|
||||
}
|
||||
// this.debug("paired:", JSON.stringify(paired, null, " "));
|
||||
// this.debug("autopair _strategy ---------------------------");
|
||||
// console.debug("paired:", JSON.stringify(paired, null, " "));
|
||||
// console.debug("autopair _strategy ---------------------------");
|
||||
return paired;
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../../tests/qunit/test-data/json/datatypes.json
|
||||
@@ -1 +0,0 @@
|
||||
../../../../tests/qunit/test-data/json/datatypes.mapping.json
|
||||
@@ -1,6 +1,6 @@
|
||||
// TODO: Swap these awful relative paths to an alias
|
||||
import DatatypesMappingJson from "./test-data/datatypes.mapping.json";
|
||||
import DatatypesJson from "./test-data/datatypes.json";
|
||||
import DatatypesMappingJson from "@tests/test-data/json/datatypes.mapping.json";
|
||||
import DatatypesJson from "@tests/test-data/json/datatypes.json";
|
||||
import { DatatypesMapperModel } from "./model";
|
||||
import type { DatatypesCombinedMap } from "./model";
|
||||
|
||||
|
||||
@@ -37,12 +37,11 @@ export default Backbone.View.extend({
|
||||
|
||||
/** Returns an input field for a given field type */
|
||||
create: function (input_def) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
var fieldClass = this.types[input_def.type];
|
||||
this.field = typeof this[fieldClass] === "function" ? this[fieldClass].call(this, input_def) : null;
|
||||
if (!this.field) {
|
||||
this.field = input_def.options ? this._fieldSelect(input_def) : this._fieldText(input_def);
|
||||
Galaxy.emit.debug("form-parameters::_addRow()", `Auto matched field type (${input_def.type}).`);
|
||||
console.debug("form-parameters::_addRow()", `Auto matched field type (${input_def.type}).`);
|
||||
}
|
||||
if (input_def.value === undefined) {
|
||||
input_def.value = null;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "@/components/Common/models/testData/exportData";
|
||||
import flushPromises from "flush-promises";
|
||||
import type { components } from "@/schema";
|
||||
import { getLocalVue } from "../../../../tests/jest/helpers";
|
||||
import { getLocalVue } from "@tests/jest/helpers";
|
||||
import HistoryExport from "./HistoryExport.vue";
|
||||
import { getExportRecords } from "./services";
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Backbone from "backbone";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import { getGalaxyInstance } from "app";
|
||||
|
||||
// ============================================================================
|
||||
// HELPER FUNCTIONS
|
||||
@@ -140,7 +139,6 @@ var FolderContainer = Backbone.Model.extend({
|
||||
},
|
||||
|
||||
parse: function (obj) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
// empty the collection
|
||||
this.get("folder").reset();
|
||||
// response is not a simple array, it contains metadata
|
||||
@@ -153,7 +151,7 @@ var FolderContainer = Backbone.Model.extend({
|
||||
var file_item = new Ldda(obj.folder_contents[i]);
|
||||
this.get("folder").add(file_item);
|
||||
} else {
|
||||
Galaxy.emit.error("Unknown folder item type encountered while parsing response.");
|
||||
console.error("Unknown folder item type encountered while parsing response.");
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import flushPromises from "flush-promises";
|
||||
import { getLocalVue } from "../../../../../../tests/jest/helpers";
|
||||
import { getLocalVue } from "@tests/jest/helpers";
|
||||
import CleanupOperationSummary from "./CleanupOperationSummary.vue";
|
||||
import { CleanableSummary, type CleanupOperation, CleanupResult } from "./model";
|
||||
|
||||
|
||||
@@ -222,7 +222,6 @@ const View = Backbone.View.extend({
|
||||
|
||||
/** Return the currently selected dataset values */
|
||||
value: function (new_value) {
|
||||
const galaxy = getGalaxyInstance();
|
||||
if (new_value) {
|
||||
this._patchValue(new_value);
|
||||
this.model.set("value", new_value);
|
||||
@@ -240,7 +239,7 @@ const View = Backbone.View.extend({
|
||||
const unpatchedValue = this._unpatchValue(details);
|
||||
result.values.push(unpatchedValue);
|
||||
} else {
|
||||
galaxy.emit.debug(
|
||||
console.debug(
|
||||
"ui-select-content::value()",
|
||||
`Requested details not found for '${id_list[i]}'.`
|
||||
);
|
||||
@@ -252,7 +251,7 @@ const View = Backbone.View.extend({
|
||||
}
|
||||
}
|
||||
} else {
|
||||
galaxy.emit.debug("ui-select-content::value()", `Invalid value/source '${new_value}'.`);
|
||||
console.debug("ui-select-content::value()", `Invalid value/source '${new_value}'.`);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -303,7 +302,7 @@ const View = Backbone.View.extend({
|
||||
this.config = Configurations[config_id];
|
||||
} else {
|
||||
this.config = Configurations["data"];
|
||||
galaxy.emit.debug("ui-select-content::_changeType()", `Invalid configuration/type id '${config_id}'.`);
|
||||
console.debug("ui-select-content::_changeType()", `Invalid configuration/type id '${config_id}'.`);
|
||||
}
|
||||
|
||||
// prepare extension component of error message
|
||||
|
||||
@@ -3,7 +3,6 @@ import _l from "utils/localization";
|
||||
import _ from "underscore";
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import Utils from "utils/utils";
|
||||
import Portlet from "./portlet";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
@@ -42,9 +41,8 @@ export var View = Backbone.View.extend({
|
||||
|
||||
/** Add new repeat block */
|
||||
add: function (options) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (!options.id || this.list[options.id]) {
|
||||
Galaxy.emit.debug("form-repeat::add()", "Duplicate or invalid repeat block id.");
|
||||
console.debug("form-repeat::add()", "Duplicate or invalid repeat block id.");
|
||||
return;
|
||||
}
|
||||
var button_delete = new Ui.Button({
|
||||
@@ -75,9 +73,8 @@ export var View = Backbone.View.extend({
|
||||
|
||||
/** Delete repeat block */
|
||||
del: function (id) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (!this.list[id]) {
|
||||
Galaxy.emit.debug("form-repeat::del()", "Invalid repeat block id.");
|
||||
console.debug("form-repeat::del()", "Invalid repeat block id.");
|
||||
return;
|
||||
}
|
||||
this.$list.find(`#${id}`).remove();
|
||||
|
||||
@@ -10,10 +10,6 @@ import { getAppRoot } from "onload/loadConfig";
|
||||
*/
|
||||
export var Visualization = Backbone.Model.extend(
|
||||
/** @lends Visualization.prototype */ {
|
||||
///** logger used to record this.log messages, commonly set to console */
|
||||
//// comment this out to suppress log output
|
||||
//logger : console,
|
||||
|
||||
/** default attributes for a model */
|
||||
defaults: {
|
||||
config: {},
|
||||
@@ -29,8 +25,6 @@ export var Visualization = Backbone.Model.extend(
|
||||
* @see Backbone.Model#initialize
|
||||
*/
|
||||
initialize: function (data) {
|
||||
//this.log( this + '.initialize', data, this.attributes );
|
||||
|
||||
// munge config sub-object here since bbone won't handle defaults with this
|
||||
if (_.isObject(data.config) && _.isObject(this.defaults.config)) {
|
||||
_.defaults(data.config, this.defaults.config);
|
||||
@@ -84,10 +78,6 @@ export var VisualizationCollection = Backbone.Collection.extend(
|
||||
/** @lends VisualizationCollection.prototype */ {
|
||||
model: Visualization,
|
||||
|
||||
///** logger used to record this.log messages, commonly set to console */
|
||||
//// comment this out to suppress log output
|
||||
//logger : console,
|
||||
|
||||
url: function () {
|
||||
return `${getAppRoot()}api/visualizations`;
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ export const defaultAppFactory = (config, label = "Galaxy") => {
|
||||
return setGalaxyInstance((GalaxyApp) => {
|
||||
const { options, bootstrapped } = config;
|
||||
const app = new GalaxyApp(options, bootstrapped);
|
||||
app.debug(`${label} app`);
|
||||
console.debug(`${label} app`);
|
||||
return app;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
//==============================================================================
|
||||
var LOGGING_FNS = ["log", "debug", "info", "warn", "error", "metric"];
|
||||
/** adds logging functions to an obj.prototype (or obj directly) adding a namespace for filtering
|
||||
* @param {Object} obj
|
||||
* @param {String} namespace
|
||||
*/
|
||||
function addLogging(obj, namespace) {
|
||||
var addTo = obj.prototype !== undefined ? obj.prototype : obj;
|
||||
if (namespace !== undefined) {
|
||||
addTo._logNamespace = namespace;
|
||||
}
|
||||
|
||||
// give the object each
|
||||
LOGGING_FNS.forEach((logFn) => {
|
||||
addTo[logFn] = function () {
|
||||
if (!this.logger) {
|
||||
return undefined;
|
||||
}
|
||||
if (this.logger.emit) {
|
||||
return this.logger.emit(logFn, this._logNamespace, arguments);
|
||||
}
|
||||
if (this.logger[logFn]) {
|
||||
//TODO:! there has to be a way to get the lineno/file into this
|
||||
// http://stackoverflow.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number
|
||||
// http://www.paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
|
||||
return this.logger[logFn].apply(this.logger, arguments);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
export default addLogging;
|
||||
@@ -4,7 +4,6 @@
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import Utils from "utils/utils";
|
||||
import { getGalaxyInstance } from "app";
|
||||
|
||||
export default Backbone.Model.extend({
|
||||
initialize: function () {
|
||||
@@ -19,7 +18,6 @@ export default Backbone.Model.extend({
|
||||
var self = this;
|
||||
var id = Utils.uid();
|
||||
var has_deferred = callback.length > 0;
|
||||
const Galaxy = getGalaxyInstance();
|
||||
|
||||
// register process
|
||||
this.active[id] = true;
|
||||
@@ -29,7 +27,7 @@ export default Backbone.Model.extend({
|
||||
process.promise().always(function () {
|
||||
delete self.active[id];
|
||||
has_deferred &&
|
||||
Galaxy.emit.debug(
|
||||
console.debug(
|
||||
"deferred::execute()",
|
||||
`${this.state().charAt(0).toUpperCase() + this.state().slice(1)} ${id}`
|
||||
);
|
||||
@@ -38,7 +36,7 @@ export default Backbone.Model.extend({
|
||||
// deferred queue
|
||||
$.when(this.last).always(() => {
|
||||
if (self.active[id]) {
|
||||
has_deferred && Galaxy.emit.debug("deferred::execute()", `Running ${id}`);
|
||||
has_deferred && console.debug("deferred::execute()", `Running ${id}`);
|
||||
callback(process);
|
||||
!has_deferred && process.resolve();
|
||||
} else {
|
||||
@@ -51,8 +49,7 @@ export default Backbone.Model.extend({
|
||||
/** Resets the promise queue. All currently queued but unexecuted callbacks/promises will be rejected.
|
||||
*/
|
||||
reset: function () {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
Galaxy.emit.debug("deferred::execute()", "Reset");
|
||||
console.debug("deferred::execute()", "Reset");
|
||||
for (var i in this.active) {
|
||||
this.active[i] = false;
|
||||
}
|
||||
|
||||
@@ -1,623 +0,0 @@
|
||||
/** deep equal of two dictionaries */
|
||||
function matches(d, d2) {
|
||||
for (var k in d2) {
|
||||
if (Object.prototype.hasOwnProperty.call(d2, k)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(d, k) || d[k] !== d2[k]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** map key/values in obj
|
||||
* if propsOrFn is an object, return only those k/v that match the object
|
||||
* if propsOrFn is function, call the fn and returned the mapped values from it
|
||||
*/
|
||||
function iterate(obj, propsOrFn) {
|
||||
var fn = typeof propsOrFn === "function" ? propsOrFn : undefined;
|
||||
var props = typeof propsOrFn === "object" ? propsOrFn : undefined;
|
||||
var returned = [];
|
||||
var index = 0;
|
||||
for (var key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var value = obj[key];
|
||||
if (fn) {
|
||||
returned.push(fn.call(value, value, key, index));
|
||||
} else if (props) {
|
||||
//TODO: break out to sep?
|
||||
if (typeof value === "object" && matches(value, props)) {
|
||||
returned.push(value);
|
||||
}
|
||||
} else {
|
||||
returned.push(value);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
return returned;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
/** A graph edge containing the name/id of both source and target and optional data
|
||||
*/
|
||||
function Edge(source, target, data) {
|
||||
var self = this;
|
||||
self.source = source !== undefined ? source : null;
|
||||
self.target = target !== undefined ? target : null;
|
||||
self.data = data || null;
|
||||
//if( typeof data === 'object' ){
|
||||
// extend( self, data );
|
||||
//}
|
||||
return self;
|
||||
}
|
||||
/** String representation */
|
||||
Edge.prototype.toString = function () {
|
||||
return `${this.source}->${this.target}`;
|
||||
};
|
||||
|
||||
/** Return a plain object representing this edge */
|
||||
Edge.prototype.toJSON = function () {
|
||||
//TODO: this is safe in most browsers (fns will be stripped) - alter tests to incorporate this in order to pass data
|
||||
//return this;
|
||||
var json = {
|
||||
source: this.source,
|
||||
target: this.target,
|
||||
};
|
||||
if (this.data) {
|
||||
json.data = this.data;
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** A graph vertex with a (unique) name/id and optional data.
|
||||
* A vertex contains a list of Edges (whose sources are this vertex) and maintains the degree.
|
||||
*/
|
||||
function Vertex(name, data) {
|
||||
var self = this;
|
||||
self.name = name !== undefined ? name : "(unnamed)";
|
||||
self.data = data || null;
|
||||
self.edges = {};
|
||||
self.degree = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
/** String representation */
|
||||
Vertex.prototype.toString = function () {
|
||||
return `Vertex(${this.name})`;
|
||||
};
|
||||
|
||||
//TODO: better name w no collision for either this.eachEdge or this.edges
|
||||
/** Iterate over each edge from this vertex */
|
||||
Vertex.prototype.eachEdge = function (propsOrFn) {
|
||||
return iterate(this.edges, propsOrFn);
|
||||
};
|
||||
|
||||
/** Return a plain object representing this vertex */
|
||||
Vertex.prototype.toJSON = function () {
|
||||
//return this;
|
||||
return {
|
||||
name: this.name,
|
||||
data: this.data,
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** Base (abstract) class for Graph search algorithms.
|
||||
* Pass in the graph to search
|
||||
* and an optional dictionary containing the 3 vertex/edge processing fns listed below.
|
||||
*/
|
||||
var GraphSearch = function (graph, processFns) {
|
||||
var self = this;
|
||||
self.graph = graph;
|
||||
|
||||
self.processFns = processFns || {
|
||||
vertexEarly: function (vertex, search) {
|
||||
//console.debug( 'processing vertex:', vertex.name, vertex );
|
||||
},
|
||||
edge: function (from, edge, search) {
|
||||
//console.debug( this, 'edge:', from, edge, search );
|
||||
},
|
||||
vertexLate: function (vertex, search) {
|
||||
//console.debug( this, 'vertexLate:', vertex, search );
|
||||
},
|
||||
};
|
||||
|
||||
self._cache = {};
|
||||
return self;
|
||||
};
|
||||
|
||||
/** Search interface where start is the vertex (or the name/id of the vertex) to begin the search at
|
||||
* This public interface caches searches and returns the cached version if it's already been done.
|
||||
*/
|
||||
GraphSearch.prototype.search = function _search(start) {
|
||||
var self = this;
|
||||
if (start in self._cache) {
|
||||
return self._cache[start];
|
||||
}
|
||||
if (!(start instanceof Vertex)) {
|
||||
start = self.graph.vertices[start];
|
||||
}
|
||||
return (self._cache[start.name] = self._search(start));
|
||||
};
|
||||
|
||||
/** Actual search (private) function (abstract here) */
|
||||
GraphSearch.prototype._search = function __search(start, search) {
|
||||
search = search || {
|
||||
discovered: {},
|
||||
//parents : {},
|
||||
edges: [],
|
||||
};
|
||||
return search;
|
||||
};
|
||||
|
||||
/** Searches graph from start and returns a search tree of the results */
|
||||
GraphSearch.prototype.searchTree = function _searchTree(start) {
|
||||
return this._searchTree(this.search(start));
|
||||
};
|
||||
|
||||
/** Helper fn that returns a graph (a search tree) based on the search object passed in (does not actually search) */
|
||||
GraphSearch.prototype._searchTree = function __searchTree(search) {
|
||||
var self = this;
|
||||
return new Graph(true, {
|
||||
edges: search.edges,
|
||||
vertices: Object.keys(search.discovered).map((key) => self.graph.vertices[key].toJSON()),
|
||||
});
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** Breadth first search algo.
|
||||
*/
|
||||
var BreadthFirstSearch = function (graph, processFns) {
|
||||
var self = this;
|
||||
GraphSearch.call(this, graph, processFns);
|
||||
return self;
|
||||
};
|
||||
BreadthFirstSearch.prototype = new GraphSearch();
|
||||
BreadthFirstSearch.prototype.constructor = BreadthFirstSearch;
|
||||
|
||||
/** (Private) implementation of BFS */
|
||||
BreadthFirstSearch.prototype._search = function __search(start, search) {
|
||||
search = search || {
|
||||
discovered: {},
|
||||
//parents : {},
|
||||
edges: [],
|
||||
};
|
||||
|
||||
var self = this;
|
||||
var queue = [];
|
||||
|
||||
function discoverAdjacent(adj, edge) {
|
||||
var source = this;
|
||||
if (self.processFns.edge) {
|
||||
self.processFns.edge.call(self, source, edge, search);
|
||||
}
|
||||
if (!search.discovered[adj.name]) {
|
||||
//console.debug( '\t\t\t', adj.name, 'is undiscovered:', search.discovered[ adj.name ] );
|
||||
search.discovered[adj.name] = true;
|
||||
//search.parents[ adj.name ] = source;
|
||||
search.edges.push({ source: source.name, target: adj.name });
|
||||
//console.debug( '\t\t\t queuing undiscovered: ', adj );
|
||||
queue.push(adj);
|
||||
}
|
||||
}
|
||||
|
||||
//console.debug( 'BFS starting. start:', start );
|
||||
search.discovered[start.name] = true;
|
||||
queue.push(start);
|
||||
while (queue.length) {
|
||||
var vertex = queue.shift();
|
||||
//console.debug( '\t Queue is shifting. Current:', vertex, 'queue:', queue );
|
||||
if (self.processFns.vertexEarly) {
|
||||
self.processFns.vertexEarly.call(self, vertex, search);
|
||||
}
|
||||
self.graph.eachAdjacent(vertex, discoverAdjacent);
|
||||
if (self.processFns.vertexLate) {
|
||||
self.processFns.vertexLate.call(self, vertex, search);
|
||||
}
|
||||
}
|
||||
//console.debug( 'search.edges:', JSON.stringify( search.edges ) );
|
||||
return search;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** Depth first search algorithm.
|
||||
*/
|
||||
var DepthFirstSearch = function (graph, processFns) {
|
||||
var self = this;
|
||||
GraphSearch.call(this, graph, processFns);
|
||||
return self;
|
||||
};
|
||||
DepthFirstSearch.prototype = new GraphSearch();
|
||||
DepthFirstSearch.prototype.constructor = DepthFirstSearch;
|
||||
|
||||
/** (Private) implementation of DFS */
|
||||
DepthFirstSearch.prototype._search = function (start, search) {
|
||||
//console.debug( 'depthFirstSearch:', start );
|
||||
search = search || {
|
||||
discovered: {},
|
||||
//parents : {},
|
||||
edges: [],
|
||||
entryTimes: {},
|
||||
exitTimes: {},
|
||||
};
|
||||
var self = this;
|
||||
var time = 0;
|
||||
|
||||
// discover verts adjacent to the source (this):
|
||||
// processing each edge, saving the edge to the tree, and caching the reverse path with parents
|
||||
function discoverAdjacentVertices(adjacent, edge) {
|
||||
//console.debug( '\t\t adjacent:', adjacent, 'edge:', edge );
|
||||
var sourceVertex = this;
|
||||
if (self.processFns.edge) {
|
||||
self.processFns.edge.call(self, sourceVertex, edge, search);
|
||||
}
|
||||
if (!search.discovered[adjacent.name]) {
|
||||
//search.parents[ adjacent.name ] = sourceVertex;
|
||||
search.edges.push({
|
||||
source: sourceVertex.name,
|
||||
target: adjacent.name,
|
||||
});
|
||||
recurse(adjacent);
|
||||
}
|
||||
}
|
||||
|
||||
// use function stack for DFS stack process verts, times, and discover adjacent verts (recursing into them)
|
||||
function recurse(vertex) {
|
||||
//console.debug( '\t recursing into: ', vertex );
|
||||
search.discovered[vertex.name] = true;
|
||||
if (self.processFns.vertexEarly) {
|
||||
self.processFns.vertexEarly.call(self, vertex, search);
|
||||
}
|
||||
search.entryTimes[vertex.name] = time++;
|
||||
|
||||
self.graph.eachAdjacent(vertex, discoverAdjacentVertices);
|
||||
|
||||
if (self.processFns.vertexLate) {
|
||||
self.processFns.vertexLate.call(self, vertex, search);
|
||||
}
|
||||
search.exitTimes[vertex.name] = time++;
|
||||
}
|
||||
// begin recursion with the desired start
|
||||
recurse(start);
|
||||
|
||||
return search;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** A directed/non-directed graph object.
|
||||
*/
|
||||
function Graph(directed, data, options) {
|
||||
//TODO: move directed to options
|
||||
this.directed = directed || false;
|
||||
return this.init(options).read(data);
|
||||
}
|
||||
window.Graph = Graph;
|
||||
|
||||
/** Set up options and instance variables */
|
||||
Graph.prototype.init = function (options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
|
||||
self.allowReflexiveEdges = options.allowReflexiveEdges || false;
|
||||
|
||||
self.vertices = {};
|
||||
self.numEdges = 0;
|
||||
return self;
|
||||
};
|
||||
|
||||
/** Read data from the plain object data - both in d3 form (nodes and links) or vertices and edges */
|
||||
Graph.prototype.read = function (data) {
|
||||
if (!data) {
|
||||
return this;
|
||||
}
|
||||
var self = this;
|
||||
if (Object.prototype.hasOwnProperty.call(data, "nodes")) {
|
||||
return self.readNodesAndLinks(data);
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(data, "vertices")) {
|
||||
return self.readVerticesAndEdges(data);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
//TODO: the next two could be combined
|
||||
/** Create the graph using a list of nodes and a list of edges (where source and target are indeces into nodes) */
|
||||
Graph.prototype.readNodesAndLinks = function (data) {
|
||||
if (!(data && Object.prototype.hasOwnProperty.call(data, "nodes"))) {
|
||||
return this;
|
||||
}
|
||||
//console.debug( 'readNodesAndLinks:', data );
|
||||
//console.debug( 'data:\n' + JSON.stringify( data, null, ' ' ) );
|
||||
var self = this;
|
||||
data.nodes.forEach((node) => {
|
||||
self.createVertex(node.name, node.data);
|
||||
});
|
||||
//console.debug( JSON.stringify( self.vertices, null, ' ' ) );
|
||||
|
||||
(data.links || []).forEach((edge, i) => {
|
||||
var sourceName = data.nodes[edge.source].name;
|
||||
var targetName = data.nodes[edge.target].name;
|
||||
self.createEdge(sourceName, targetName, self.directed);
|
||||
});
|
||||
//self.print();
|
||||
//console.debug( JSON.stringify( self.toNodesAndLinks(), null, ' ' ) );
|
||||
return self;
|
||||
};
|
||||
|
||||
/** Create the graph using a list of nodes and a list of edges (where source and target are names of nodes) */
|
||||
Graph.prototype.readVerticesAndEdges = function (data) {
|
||||
if (!(data && Object.prototype.hasOwnProperty.call(data, "vertices"))) {
|
||||
return this;
|
||||
}
|
||||
//console.debug( 'readVerticesAndEdges:', data );
|
||||
//console.debug( 'data:\n' + JSON.stringify( data, null, ' ' ) );
|
||||
var self = this;
|
||||
data.vertices.forEach((node) => {
|
||||
self.createVertex(node.name, node.data);
|
||||
});
|
||||
//console.debug( JSON.stringify( self.vertices, null, ' ' ) );
|
||||
|
||||
(data.edges || []).forEach((edge, i) => {
|
||||
self.createEdge(edge.source, edge.target, self.directed);
|
||||
});
|
||||
//self.print();
|
||||
//console.debug( JSON.stringify( self.toNodesAndLinks(), null, ' ' ) );
|
||||
return self;
|
||||
};
|
||||
|
||||
/** Return the vertex with name, creating it if necessary */
|
||||
Graph.prototype.createVertex = function (name, data) {
|
||||
//console.debug( 'createVertex:', name, data );
|
||||
if (this.vertices[name]) {
|
||||
return this.vertices[name];
|
||||
}
|
||||
return (this.vertices[name] = new Vertex(name, data));
|
||||
};
|
||||
|
||||
/** Create an edge in vertex named sourceName to targetName (optionally adding data to it)
|
||||
* If directed is false, create a second edge from targetName to sourceName.
|
||||
*/
|
||||
Graph.prototype.createEdge = function (sourceName, targetName, directed, data) {
|
||||
//note: allows multiple 'equivalent' edges (to/from same source/target)
|
||||
//console.debug( 'createEdge:', source, target, directed );
|
||||
var isReflexive = sourceName === targetName;
|
||||
if (!this.allowReflexiveEdges && isReflexive) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var sourceVertex = this.vertices[sourceName];
|
||||
var targetVertex = this.vertices[targetName];
|
||||
//note: silently ignores edges from/to unknown vertices
|
||||
if (!(sourceVertex && targetVertex)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: prob. move to vertex
|
||||
var self = this;
|
||||
|
||||
var edge = new Edge(sourceName, targetName, data);
|
||||
sourceVertex.edges[targetName] = edge;
|
||||
sourceVertex.degree += 1;
|
||||
self.numEdges += 1;
|
||||
|
||||
//TODO:! don't like having duplicate edges for non-directed graphs
|
||||
// mirror edges (reversing source and target) in non-directed graphs
|
||||
// but only if not reflexive
|
||||
if (!isReflexive && !directed) {
|
||||
// flip directed to prevent recursion loop
|
||||
self.createEdge(targetName, sourceName, true);
|
||||
}
|
||||
|
||||
return edge;
|
||||
};
|
||||
|
||||
/** Walk over all the edges of the graph using the vertex.eachEdge iterator */
|
||||
Graph.prototype.edges = function (propsOrFn) {
|
||||
return Array.prototype.concat.apply(
|
||||
[],
|
||||
this.eachVertex((vertex) => vertex.eachEdge(propsOrFn))
|
||||
);
|
||||
};
|
||||
|
||||
/** Iterate over all the vertices in the graph */
|
||||
Graph.prototype.eachVertex = function (propsOrFn) {
|
||||
return iterate(this.vertices, propsOrFn);
|
||||
};
|
||||
|
||||
/** Return a list of the vertices adjacent to vertex */
|
||||
Graph.prototype.adjacent = function (vertex) {
|
||||
var self = this;
|
||||
return iterate(vertex.edges, (edge) => self.vertices[edge.target]);
|
||||
};
|
||||
|
||||
/** Call fn on each vertex adjacent to vertex */
|
||||
Graph.prototype.eachAdjacent = function (vertex, fn) {
|
||||
var self = this;
|
||||
return iterate(vertex.edges, (edge) => {
|
||||
var adj = self.vertices[edge.target];
|
||||
return fn.call(vertex, adj, edge);
|
||||
});
|
||||
};
|
||||
|
||||
/** Print the graph to the console (debugging) */
|
||||
Graph.prototype.print = function () {
|
||||
var self = this;
|
||||
console.log(`Graph has ${Object.keys(self.vertices).length} vertices`);
|
||||
self.eachVertex((vertex) => {
|
||||
console.log(vertex.toString());
|
||||
vertex.eachEdge((edge) => {
|
||||
console.log(`\t ${edge}`);
|
||||
});
|
||||
});
|
||||
return self;
|
||||
};
|
||||
|
||||
/** Return a DOT format string of this graph */
|
||||
Graph.prototype.toDOT = function () {
|
||||
var self = this;
|
||||
var strings = [];
|
||||
strings.push("graph bler {");
|
||||
self.edges((edge) => {
|
||||
strings.push(`\t${edge.from} -- ${edge.to};`);
|
||||
});
|
||||
strings.push("}");
|
||||
return strings.join("\n");
|
||||
};
|
||||
|
||||
/** Return vertices and edges of this graph in d3 node/link format */
|
||||
Graph.prototype.toNodesAndLinks = function () {
|
||||
var self = this;
|
||||
var indeces = {};
|
||||
return {
|
||||
nodes: self.eachVertex((vertex, key, i) => {
|
||||
indeces[vertex.name] = i;
|
||||
return vertex.toJSON();
|
||||
}),
|
||||
links: self.edges((edge) => {
|
||||
var json = edge.toJSON();
|
||||
json.source = indeces[edge.source];
|
||||
json.target = indeces[edge.target];
|
||||
return json;
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
/** Return vertices and edges of this graph where edges use the name/id as source and target */
|
||||
Graph.prototype.toVerticesAndEdges = function () {
|
||||
var self = this;
|
||||
return {
|
||||
vertices: self.eachVertex((vertex, key) => vertex.toJSON()),
|
||||
edges: self.edges((edge) => edge.toJSON()),
|
||||
};
|
||||
};
|
||||
|
||||
/** Search this graph using BFS */
|
||||
Graph.prototype.breadthFirstSearch = function (start, processFns) {
|
||||
return new BreadthFirstSearch(this).search(start);
|
||||
};
|
||||
|
||||
/** Return a searchtree of this graph using BFS */
|
||||
Graph.prototype.breadthFirstSearchTree = function (start, processFns) {
|
||||
return new BreadthFirstSearch(this).searchTree(start);
|
||||
};
|
||||
|
||||
/** Search this graph using DFS */
|
||||
Graph.prototype.depthFirstSearch = function (start, processFns) {
|
||||
return new DepthFirstSearch(this).search(start);
|
||||
};
|
||||
|
||||
/** Return a searchtree of this graph using DFS */
|
||||
Graph.prototype.depthFirstSearchTree = function (start, processFns) {
|
||||
return new DepthFirstSearch(this).searchTree(start);
|
||||
};
|
||||
|
||||
//Graph.prototype.shortestPath = function( start, end ){
|
||||
//};
|
||||
//
|
||||
//Graph.prototype.articulationVertices = function(){
|
||||
//};
|
||||
//
|
||||
//Graph.prototype.isAcyclic = function(){
|
||||
//};
|
||||
//
|
||||
//Graph.prototype.isBipartite = function(){
|
||||
//};
|
||||
|
||||
/** Return an array of weakly connected (no edges between) sub-graphs in this graph */
|
||||
Graph.prototype.weakComponents = function () {
|
||||
//TODO: alternately, instead of returning graph-like objects:
|
||||
// - could simply decorate the vertices (vertex.component = componentIndex), or clone the graph and do that
|
||||
var self = this;
|
||||
|
||||
var searchGraph = this;
|
||||
var undiscovered;
|
||||
var components = [];
|
||||
|
||||
function getComponent(undiscoveredVertex) {
|
||||
//TODO: better interface on dfs (search v. searchTree)
|
||||
var search = new DepthFirstSearch(searchGraph)._search(undiscoveredVertex);
|
||||
|
||||
// remove curr discovered from undiscovered
|
||||
undiscovered = undiscovered.filter((name) => !(name in search.discovered));
|
||||
|
||||
return {
|
||||
vertices: Object.keys(search.discovered).map((vertexName) => self.vertices[vertexName].toJSON()),
|
||||
edges: search.edges.map((edge) => {
|
||||
// restore any reversed edges
|
||||
var hasBeenReversed = self.vertices[edge.target].edges[edge.source] !== undefined;
|
||||
if (self.directed && hasBeenReversed) {
|
||||
var swap = edge.source;
|
||||
edge.source = edge.target;
|
||||
edge.target = swap;
|
||||
}
|
||||
return edge;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (self.directed) {
|
||||
// if directed - convert to undirected for search
|
||||
searchGraph = new Graph(false, self.toNodesAndLinks());
|
||||
}
|
||||
undiscovered = Object.keys(searchGraph.vertices);
|
||||
//console.debug( '(initial) undiscovered:', undiscovered );
|
||||
while (undiscovered.length) {
|
||||
var undiscoveredVertex = searchGraph.vertices[undiscovered.shift()];
|
||||
components.push(getComponent(undiscoveredVertex));
|
||||
//console.debug( 'undiscovered now:', undiscovered );
|
||||
}
|
||||
|
||||
//console.debug( 'components:\n', JSON.stringify( components, null, ' ' ) );
|
||||
return components;
|
||||
};
|
||||
|
||||
/** Return a single graph containing the weakly connected components in this graph */
|
||||
Graph.prototype.weakComponentGraph = function () {
|
||||
//note: although this can often look like the original graph - edges can be lost
|
||||
var components = this.weakComponents();
|
||||
return new Graph(this.directed, {
|
||||
vertices: components.reduce((reduction, curr) => reduction.concat(curr.vertices), []),
|
||||
edges: components.reduce((reduction, curr) => reduction.concat(curr.edges), []),
|
||||
});
|
||||
};
|
||||
|
||||
/** Return an array of graphs of the weakly connected components in this graph */
|
||||
Graph.prototype.weakComponentGraphArray = function () {
|
||||
//note: although this can often look like the original graph - edges can be lost
|
||||
var graph = this;
|
||||
return this.weakComponents().map((component) => new Graph(graph.directed, component));
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
/** Create a random graph with numVerts vertices and numEdges edges (for testing)
|
||||
*/
|
||||
function randGraph(directed, numVerts, numEdges) {
|
||||
//console.debug( 'randGraph', directed, numVerts, numEdges );
|
||||
var data = { nodes: [], links: [] };
|
||||
function randRange(range) {
|
||||
return Math.floor(Math.random() * range);
|
||||
}
|
||||
for (var i = 0; i < numVerts; i++) {
|
||||
data.nodes.push({ name: i });
|
||||
}
|
||||
for (i = 0; i < numEdges; i++) {
|
||||
data.links.push({
|
||||
source: randRange(numVerts),
|
||||
target: randRange(numVerts),
|
||||
});
|
||||
}
|
||||
//console.debug( JSON.stringify( data, null, ' ' ) );
|
||||
return new Graph(directed, data);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
export default {
|
||||
Vertex: Vertex,
|
||||
Edge: Edge,
|
||||
BreadthFirstSearch: BreadthFirstSearch,
|
||||
DepthFirstSearch: DepthFirstSearch,
|
||||
Graph: Graph,
|
||||
randGraph: randGraph,
|
||||
};
|
||||
@@ -1,504 +0,0 @@
|
||||
/*=============================================================================
|
||||
TODO:
|
||||
while anon: logs saved to 'logs-null' - this will never post
|
||||
unless we manually do so at/after login
|
||||
OR prepend when userId and localStorage has 'logs-null'
|
||||
wire up _delayPost and test
|
||||
|
||||
=============================================================================*/
|
||||
/** @class MetricsLogger
|
||||
*
|
||||
* Object to cache, output, and post log/metric messages to the server.
|
||||
* Meant to be attached to the Galaxy object.
|
||||
*
|
||||
* Log from objects by either attaching logger directly:
|
||||
* panel.logger.metric( 'user dataset deletion', panel.user.id, hda.toJSON() )
|
||||
* or using the LoggableMixin or addLogging function:
|
||||
* MyBackboneModel.extend( LoggableMixin ).extend({ ... })
|
||||
* addLogging( MyBackboneModel, 'my-backbone-model' )
|
||||
*
|
||||
* Log from templates by calling directly from Galaxy object:
|
||||
* Galaxy.logger.metric( 'template loaded', { ownedByUser : true });
|
||||
*
|
||||
* If you attempt to log an un-serializable object (circular reference, window, etc.),
|
||||
* that entry will not be cached (or sent). If you set consoleLevel and consoleLogger
|
||||
* appropriately, a warning will be shown when this happens:
|
||||
* > panel.metric( 'something weird with window', { window : window })
|
||||
* !'Metrics logger could not stringify logArguments: ...'
|
||||
*/
|
||||
import jQuery from "jquery";
|
||||
|
||||
function MetricsLogger(options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
|
||||
///** get the current user's id from bootstrapped data or options */
|
||||
self.userId = window.bootstrapped && window.bootstrapped.user ? window.bootstrapped.user.id : null;
|
||||
self.userId = self.userId || options.userId || null;
|
||||
|
||||
/** the (optional) console to emit logs to */
|
||||
self.consoleLogger = options.consoleLogger || null;
|
||||
|
||||
self._init(options);
|
||||
return self;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------- defaults and constants
|
||||
// see: python std lib, logging
|
||||
MetricsLogger.ALL = 0;
|
||||
MetricsLogger.LOG = 0;
|
||||
MetricsLogger.DEBUG = 10;
|
||||
MetricsLogger.INFO = 20;
|
||||
MetricsLogger.WARN = 30;
|
||||
MetricsLogger.ERROR = 40;
|
||||
// metrics levels here?
|
||||
//MetricsLogger.MinorEvent = 45;
|
||||
//MetricsLogger.MajorEvent = 50;
|
||||
MetricsLogger.METRIC = 50;
|
||||
MetricsLogger.NONE = 100;
|
||||
|
||||
/** default options - override these through the constructor */
|
||||
MetricsLogger.defaultOptions = {
|
||||
/** if an incoming message has a level >= this, it will be cached - can also be a string (e.g. 'debug') */
|
||||
logLevel: MetricsLogger.NONE,
|
||||
/** if an incoming message has a level >= this, it will be output to the console */
|
||||
consoleLevel: MetricsLogger.NONE,
|
||||
/** the default 'namespace' or label associated with an incoming message (if none is passed) */
|
||||
defaultNamespace: "Galaxy",
|
||||
/** the namespaces output to the console (all namespaces will be output if this is falsy)
|
||||
* note: applies only to the console (not the event/metrics log/cache)
|
||||
*/
|
||||
consoleNamespaceWhitelist: null,
|
||||
/** Force all messages into simple strings. */
|
||||
consoleFlattenMessages: false,
|
||||
/** the prefix attached to client-side logs to distinguish them in the metrics db */
|
||||
clientPrefix: "client.",
|
||||
|
||||
/** the maximum number of messages the cache should hold; if exceeded older messages are removed first */
|
||||
maxCacheSize: 3000,
|
||||
/** the number of messages accumulate before posting to the server; should be <= maxCacheSize */
|
||||
postSize: 1000,
|
||||
/** T/F whether to add a timestamp to incoming cached messages */
|
||||
addTime: true,
|
||||
/** string to prefix to userid for cache web storage */
|
||||
cacheKeyPrefix: "logs-",
|
||||
|
||||
/** the relative url to post messages to */
|
||||
postUrl: "/api/metrics",
|
||||
/** delay before trying post again after two failures */
|
||||
delayPostInMs: 1000 * 60 * 10,
|
||||
|
||||
/** an (optional) function that should return an object; used to send additional data with the metrics */
|
||||
getPingData: undefined,
|
||||
/** an (optional) function that will handle the servers response after successfully posting messages */
|
||||
onServerResponse: undefined,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------- set up
|
||||
/** initialize the logger with options, set up instance vars and cache, and add onpageunload to window */
|
||||
MetricsLogger.prototype._init = function _init(options) {
|
||||
var self = this;
|
||||
self.options = {};
|
||||
for (var k in MetricsLogger.defaultOptions) {
|
||||
if (Object.prototype.hasOwnProperty.call(MetricsLogger.defaultOptions, k)) {
|
||||
self.options[k] = Object.prototype.hasOwnProperty.call(options, k)
|
||||
? options[k]
|
||||
: MetricsLogger.defaultOptions[k];
|
||||
}
|
||||
}
|
||||
self.options.logLevel = self._parseLevel(self.options.logLevel);
|
||||
self.options.consoleLevel = self._parseLevel(self.options.consoleLevel);
|
||||
//self._emitToConsole( 'debug', 'MetricsLogger', 'MetricsLogger.options:', self.options );
|
||||
|
||||
/** is the logger currently sending? */
|
||||
self._sending = false;
|
||||
/** the setTimeout id if the logger POST has failed more than once */
|
||||
self._waiting = null;
|
||||
/** the current number of entries to send in a POST */
|
||||
self._postSize = self.options.postSize;
|
||||
|
||||
self._initCache();
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
/** initialize the cache */
|
||||
MetricsLogger.prototype._initCache = function _initCache() {
|
||||
try {
|
||||
this.cache = new LoggingCache({
|
||||
maxSize: this.options.maxCacheSize,
|
||||
key: this.options.cacheKeyPrefix + this.userId,
|
||||
});
|
||||
} catch (err) {
|
||||
this._emitToConsole("warn", "MetricsLogger", ["Could not intitialize logging cache:", err]);
|
||||
this.options.logLevel = MetricsLogger.NONE;
|
||||
}
|
||||
};
|
||||
|
||||
/** return the numeric log level if level in 'none, debug, log, info, warn, error' */
|
||||
MetricsLogger.prototype._parseLevel = function _parseLevel(level) {
|
||||
var type = typeof level;
|
||||
if (type === "number") {
|
||||
return level;
|
||||
}
|
||||
if (type === "string") {
|
||||
var upper = level.toUpperCase();
|
||||
if (Object.prototype.hasOwnProperty.call(MetricsLogger, upper)) {
|
||||
return MetricsLogger[upper];
|
||||
}
|
||||
}
|
||||
throw new Error(`Unknown log level: ${level}`);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------- main entry point
|
||||
/** record a log/message's arguments to the cache and/or the console based on level and namespace */
|
||||
MetricsLogger.prototype.emit = function emit(level, namespace, logArguments) {
|
||||
//this._emitToConsole( 'debug', 'MetricsLogger', [ 'emit:', level, namespace, logArguments ]);
|
||||
var self = this;
|
||||
namespace = namespace || self.options.defaultNamespace;
|
||||
if (!level || !logArguments) {
|
||||
return self;
|
||||
}
|
||||
// add to cache if proper level
|
||||
//TODO: respect do not track?
|
||||
//if( !navigator.doNotTrack && level >= self.options.logLevel ){
|
||||
level = self._parseLevel(level);
|
||||
if (level >= self.options.logLevel) {
|
||||
self._addToCache(level, namespace, logArguments);
|
||||
}
|
||||
// also emit to consoleLogger if proper level for that
|
||||
if (self.consoleLogger && level >= self.options.consoleLevel) {
|
||||
self._emitToConsole(level, namespace, logArguments);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------- cache
|
||||
/** add a message to the cache and if messages.length is high enough post them to the server */
|
||||
MetricsLogger.prototype._addToCache = function _addToCache(level, namespace, logArguments) {
|
||||
this._emitToConsole("debug", "MetricsLogger", [
|
||||
"_addToCache:",
|
||||
arguments,
|
||||
this.options.addTime,
|
||||
this.cache.length(),
|
||||
]);
|
||||
//this._emitToConsole( 'debug', 'MetricsLogger', [ '\t logArguments:', logArguments ]);
|
||||
var self = this;
|
||||
// try add to the cache and if we've got _postSize number of entries, attempt to post them to the server
|
||||
try {
|
||||
var newLength = self.cache.add(self._buildEntry(level, namespace, logArguments));
|
||||
if (newLength >= self._postSize) {
|
||||
self._postCache();
|
||||
}
|
||||
// discard entry if an error occurs, but warn if level set to do so
|
||||
} catch (err) {
|
||||
self._emitToConsole("warn", "MetricsLogger", [
|
||||
"Metrics logger could not stringify logArguments:",
|
||||
namespace,
|
||||
logArguments,
|
||||
]);
|
||||
self._emitToConsole("error", "MetricsLogger", [err]);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
/** build a log cache entry object from the given level, namespace, and arguments (optionally adding timestamp */
|
||||
MetricsLogger.prototype._buildEntry = function _buildEntry(level, namespace, logArguments) {
|
||||
this._emitToConsole("debug", "MetricsLogger", ["_buildEntry:", arguments]);
|
||||
var entry = {
|
||||
level: level,
|
||||
namespace: this.options.clientPrefix + namespace,
|
||||
args: logArguments,
|
||||
};
|
||||
if (this.options.addTime) {
|
||||
entry.time = new Date().toISOString();
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
||||
/** post _postSize messages from the cache to the server, removing them if successful
|
||||
* if the post fails, wait until maxCacheSize is accumulated instead and try again then
|
||||
* in addition to the messages from the cache ('metrics'), any info from getPingData (if set) will be sent
|
||||
* onServerResponse will be called (if set) with any response from the server
|
||||
*/
|
||||
MetricsLogger.prototype._postCache = function _postCache(options) {
|
||||
options = options || {};
|
||||
this._emitToConsole("info", "MetricsLogger", ["_postCache", options, this._postSize]);
|
||||
|
||||
// short circuit if we're already sending
|
||||
if (!this.options.postUrl || this._sending) {
|
||||
return jQuery.when({});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var postSize = options.count || self._postSize;
|
||||
|
||||
var // do not splice - remove after *successful* post
|
||||
entries = self.cache.get(postSize);
|
||||
|
||||
var entriesLength = entries.length;
|
||||
|
||||
var // use the optional getPingData to add any extra info we may want to send
|
||||
postData = typeof self.options.getPingData === "function" ? self.options.getPingData() : {};
|
||||
|
||||
//console.debug( postSize, entriesLength );
|
||||
|
||||
// add the metrics and send
|
||||
postData.metrics = JSON.stringify(entries);
|
||||
//console.debug( postData.metrics );
|
||||
self._sending = true;
|
||||
return jQuery
|
||||
.post(self.options.postUrl, postData)
|
||||
.always(() => {
|
||||
self._sending = false;
|
||||
})
|
||||
.fail((xhr, status, message) => {
|
||||
// if we failed the previous time, set the next post target to the max num of entries
|
||||
self._postSize = self.options.maxCacheSize;
|
||||
//TODO:??
|
||||
// log this failure to explain any gap in metrics
|
||||
self.emit("error", "MetricsLogger", [
|
||||
"_postCache error:",
|
||||
xhr.readyState,
|
||||
xhr.status,
|
||||
xhr.responseJSON || xhr.responseText,
|
||||
]);
|
||||
//TODO: still doesn't solve the problem that when cache == max, post will be tried on every emit
|
||||
//TODO: see _delayPost
|
||||
})
|
||||
.done((response) => {
|
||||
if (typeof self.options.onServerResponse === "function") {
|
||||
self.options.onServerResponse(response);
|
||||
}
|
||||
// only remove if post successful
|
||||
self.cache.remove(entriesLength);
|
||||
//console.debug( 'removed entries:', entriesLength, 'size now:', self.cache.length() );
|
||||
// if we succeeded, reset the post target to the normal num of entries
|
||||
self._postSize = self.options.postSize;
|
||||
});
|
||||
// return the xhr promise
|
||||
};
|
||||
|
||||
/** set _waiting to true and, after delayPostInMs, set it back to false */
|
||||
MetricsLogger.prototype._delayPost = function _delayPost() {
|
||||
//TODO: this won't work between pages
|
||||
var self = this;
|
||||
self._waiting = window.setTimeout(() => {
|
||||
self._waiting = null;
|
||||
}, self.options.delayPostInMs);
|
||||
};
|
||||
|
||||
function usefulToString(arg) {
|
||||
var asStr = String(arg);
|
||||
if (asStr == "[object Object]") {
|
||||
try {
|
||||
asStr = JSON.stringify(arg);
|
||||
} catch (e) {
|
||||
// If arg has cyclic reference, return String
|
||||
// otherwise rendering stops and we have incomplete page
|
||||
console.error(e);
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
return asStr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------- console
|
||||
/** output message to console based on level and consoleLogger type */
|
||||
MetricsLogger.prototype._emitToConsole = function _emitToConsole(level, namespace, logArguments) {
|
||||
//console.debug( '_emitToConsole:', level, namespace, logArguments );
|
||||
var self = this;
|
||||
|
||||
var whitelist = self.options.consoleNamespaceWhitelist;
|
||||
if (!self.consoleLogger) {
|
||||
return self;
|
||||
}
|
||||
// if a whitelist for namespaces is set, bail if this namespace is not in the list
|
||||
if (whitelist && whitelist.indexOf(namespace) === -1) {
|
||||
return self;
|
||||
}
|
||||
|
||||
var args = Array.prototype.slice.call(logArguments, 0);
|
||||
args.unshift(namespace);
|
||||
if (self.options.consoleFlattenMessages) {
|
||||
args = [args.map(usefulToString).join(" ")];
|
||||
}
|
||||
//TODO: script location and/or source maps?
|
||||
//TODO: branch on navigator.userAgent == AIIEEE - it only has log
|
||||
if (level >= MetricsLogger.METRIC && typeof self.consoleLogger.info === "function") {
|
||||
return self.consoleLogger.info.apply(self.consoleLogger, args);
|
||||
} else if (level >= MetricsLogger.ERROR && typeof self.consoleLogger.error === "function") {
|
||||
return self.consoleLogger.error.apply(self.consoleLogger, args);
|
||||
} else if (level >= MetricsLogger.WARN && typeof self.consoleLogger.warn === "function") {
|
||||
self.consoleLogger.warn.apply(self.consoleLogger, args);
|
||||
} else if (level >= MetricsLogger.INFO && typeof self.consoleLogger.info === "function") {
|
||||
self.consoleLogger.info.apply(self.consoleLogger, args);
|
||||
} else if (level >= MetricsLogger.DEBUG && typeof self.consoleLogger.debug === "function") {
|
||||
self.consoleLogger.debug.apply(self.consoleLogger, args);
|
||||
} else if (typeof self.consoleLogger.log === "function") {
|
||||
self.consoleLogger.log.apply(self.consoleLogger, args);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------- shortcuts
|
||||
// generic functions when logging from non-namespaced object (e.g. templates)
|
||||
/** log to default namespace */
|
||||
MetricsLogger.prototype.log = function log() {
|
||||
this.emit(1, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/** debug to default namespace */
|
||||
MetricsLogger.prototype.debug = function debug() {
|
||||
this.emit(MetricsLogger.DEBUG, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/** info to default namespace */
|
||||
MetricsLogger.prototype.info = function info() {
|
||||
this.emit(MetricsLogger.INFO, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/** warn to default namespace */
|
||||
MetricsLogger.prototype.warn = function warn() {
|
||||
this.emit(MetricsLogger.WARN, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/** error to default namespace */
|
||||
MetricsLogger.prototype.error = function error() {
|
||||
this.emit(MetricsLogger.ERROR, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/** metric to default namespace */
|
||||
MetricsLogger.prototype.metric = function metric() {
|
||||
this.emit(MetricsLogger.METRIC, this.options.defaultNamespace, Array.prototype.slice.call(arguments, 0));
|
||||
};
|
||||
|
||||
/* ============================================================================
|
||||
TODO:
|
||||
need a performance pass - the JSON un/parsing is a bit much
|
||||
|
||||
============================================================================ */
|
||||
/** @class LoggingCache
|
||||
* Simple implementation of cache wrapping an array.
|
||||
*
|
||||
* Formats an entry before it's cached and only keeps options.maxSize number
|
||||
* of entries. Older entries are deleted first.
|
||||
*/
|
||||
function LoggingCache(options) {
|
||||
var self = this;
|
||||
return self._init(options || {});
|
||||
}
|
||||
|
||||
/** default options */
|
||||
LoggingCache.defaultOptions = {
|
||||
/** maximum number of entries to keep before discarding oldest */
|
||||
maxSize: 5000,
|
||||
};
|
||||
|
||||
/** initialize with options */
|
||||
LoggingCache.prototype._init = function _init(options) {
|
||||
if (!this._hasStorage()) {
|
||||
//TODO: fall back to local storage
|
||||
throw new Error("LoggingCache needs localStorage");
|
||||
}
|
||||
if (!options.key) {
|
||||
throw new Error("LoggingCache needs key for localStorage");
|
||||
}
|
||||
this.key = options.key;
|
||||
this._initStorage();
|
||||
|
||||
this.maxSize = options.maxSize || LoggingCache.defaultOptions.maxSize;
|
||||
return this;
|
||||
};
|
||||
|
||||
/** tests for localStorage fns */
|
||||
LoggingCache.prototype._hasStorage = function _hasStorage() {
|
||||
//TODO: modernizr
|
||||
var test = "test";
|
||||
try {
|
||||
localStorage.setItem(test, test);
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** if no localStorage set for key, initialize to empty array */
|
||||
LoggingCache.prototype._initStorage = function _initStorage() {
|
||||
if (localStorage.getItem(this.key) === null) {
|
||||
return this.empty();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/** add an entry to the cache, removing the oldest beforehand if size >= maxSize */
|
||||
LoggingCache.prototype.add = function add(entry) {
|
||||
var self = this;
|
||||
var _cache = self._fetchAndParse();
|
||||
var overage = _cache.length + 1 - self.maxSize;
|
||||
if (overage > 0) {
|
||||
_cache.splice(0, overage);
|
||||
}
|
||||
_cache.push(entry);
|
||||
self._unparseAndStore(_cache);
|
||||
return _cache.length;
|
||||
};
|
||||
|
||||
/** get the entries from localStorage and parse them */
|
||||
LoggingCache.prototype._fetchAndParse = function _fetchAndParse() {
|
||||
var self = this;
|
||||
return JSON.parse(localStorage.getItem(self.key));
|
||||
};
|
||||
|
||||
/** stringify the entries and put them in localStorage */
|
||||
LoggingCache.prototype._unparseAndStore = function _unparseAndStore(entries) {
|
||||
var self = this;
|
||||
return localStorage.setItem(self.key, JSON.stringify(entries));
|
||||
};
|
||||
|
||||
///** process the entry before caching */
|
||||
//LoggingCache.prototype._preprocessEntry = function _preprocessEntry( entry ){
|
||||
// return JSON.stringify( entry );
|
||||
//};
|
||||
|
||||
/** return the length --- oh, getters where are you? */
|
||||
LoggingCache.prototype.length = function length() {
|
||||
return this._fetchAndParse().length;
|
||||
};
|
||||
|
||||
/** get count number of entries starting with the oldest */
|
||||
LoggingCache.prototype.get = function get(count) {
|
||||
return this._fetchAndParse().slice(0, count);
|
||||
};
|
||||
|
||||
/** remove count number of entries starting with the oldest */
|
||||
LoggingCache.prototype.remove = function remove(count) {
|
||||
var _cache = this._fetchAndParse();
|
||||
var removed = _cache.splice(0, count);
|
||||
this._unparseAndStore(_cache);
|
||||
return removed;
|
||||
};
|
||||
|
||||
/** empty/clear the entire cache */
|
||||
LoggingCache.prototype.empty = function empty() {
|
||||
localStorage.setItem(this.key, "[]");
|
||||
return this;
|
||||
};
|
||||
|
||||
/** stringify count number of entries (but do not remove) */
|
||||
LoggingCache.prototype.stringify = function stringify(count) {
|
||||
return JSON.stringify(this.get(count));
|
||||
};
|
||||
|
||||
/** outputs entire cache to console */
|
||||
LoggingCache.prototype.print = function print() {
|
||||
// popup? (really, carl? a popup?) - easier to copy/paste
|
||||
console.log(JSON.stringify(this._fetchAndParse(), null, " "));
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
export default {
|
||||
MetricsLogger: MetricsLogger,
|
||||
LoggingCache: LoggingCache,
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import Utils from "./utils";
|
||||
|
||||
describe("test utils", () => {
|
||||
it("test isEmpty", async () => {
|
||||
expect(Utils.isEmpty([])).toBe(true); // "Empty array");
|
||||
expect(Utils.isEmpty(["data", undefined])).toBe(true); // , "Array contains `undefined`");
|
||||
expect(Utils.isEmpty(["data", null])).toBe(true); //, "Array contains `null`");
|
||||
expect(Utils.isEmpty(["data", "__null__"])).toBe(true); // , "Array contains `__null__`");
|
||||
expect(Utils.isEmpty(["data", "__undefined__"])).toBe(true); // , "Array contains `__undefined__`");
|
||||
expect(Utils.isEmpty(null)).toBe(true); //, "Array is null");
|
||||
expect(Utils.isEmpty("__null__")).toBe(true); //, "Array is __null__");
|
||||
expect(Utils.isEmpty("__undefined__")).toBe(true); //, "Array is __undefined__");
|
||||
expect(Utils.isEmpty(["data"])).toBe(false); //, "Array contains `data`");
|
||||
expect(Utils.isEmpty(1)).toBe(false); //, "Value is int");
|
||||
expect(Utils.isEmpty(0)).toBe(false); //, "Value is zero");
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,11 @@
|
||||
export default (l) => {
|
||||
export function _setUserLocale(user, config) {
|
||||
sessionStorage.setItem("currentLocale", "en");
|
||||
}
|
||||
|
||||
export function _getUserLocale(user, config) {
|
||||
return "en";
|
||||
}
|
||||
|
||||
export default function localize(l) {
|
||||
return l;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ module.exports = {
|
||||
roots: ["<rootDir>/src/", "<rootDir>/tests/jest/standalone/"],
|
||||
setupFilesAfterEnv: ["<rootDir>/tests/jest/jest.setup.js"],
|
||||
testEnvironment: "jsdom",
|
||||
testPathIgnorePatterns: ["/node_modules/", "/dist/"],
|
||||
transform: {
|
||||
"^.+\\.js$": "babel-jest",
|
||||
"^.*\\.(vue)$": "@vue/vue2-jest",
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Base karma config, assumes chrome headless and webpack
|
||||
*/
|
||||
|
||||
const webpackConfigFunc = require("./webpack.config.unittest");
|
||||
|
||||
module.exports = (config) => {
|
||||
// Karma does not execute the webpack config function by default
|
||||
const webpackConfig = webpackConfigFunc(
|
||||
{},
|
||||
{
|
||||
mode: "testing",
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
basePath: "../../src",
|
||||
browsers: ["ChromeHeadlessNoSandbox"],
|
||||
client: {
|
||||
captureConsole: true,
|
||||
},
|
||||
failOnEmptyTestSuite: false,
|
||||
singleRun: true,
|
||||
webpack: webpackConfig,
|
||||
webpackMiddleware: {
|
||||
noInfo: true,
|
||||
},
|
||||
customLaunchers: {
|
||||
ChromeHeadlessNoSandbox: {
|
||||
base: "ChromeHeadless",
|
||||
flags: ["--no-sandbox"],
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Qunit Tests
|
||||
*
|
||||
* These legacy QUnit tests are interdependent and only execute as a single
|
||||
* package. A flaw in the previous node environment parameter-checking in the
|
||||
* old karma configs gave the illusion that they ran individually, but they do
|
||||
* not and probably never have. Keeping them around for now, but we should get
|
||||
* rid of them by rewriting the tests or preferrably by removing the code to
|
||||
* which they apply.
|
||||
*/
|
||||
|
||||
const baseKarmaConfig = require("./karma.config.base");
|
||||
const testFiles = ["polyfills.js", "../tests/qunit/testBundle.js"];
|
||||
const preprocessors = testFiles.reduce((result, path) => {
|
||||
result[path] = ["webpack"];
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
module.exports = function (config) {
|
||||
const baseConfig = baseKarmaConfig(config);
|
||||
|
||||
const settings = Object.assign({}, baseConfig, {
|
||||
files: testFiles,
|
||||
preprocessors: preprocessors,
|
||||
frameworks: ["polyfill", "qunit"],
|
||||
singleRun: true,
|
||||
});
|
||||
|
||||
config.set(settings);
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* So the legacy QUnit tests have to perform some gymastics that should not be
|
||||
* required because thse tests apparently care about assets like the CSS and images.
|
||||
* TODO: Replace these tests with like... actual unit tests.
|
||||
*/
|
||||
|
||||
const baseConfig = require("../../webpack.config");
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
// load base config
|
||||
const wpConfig = baseConfig(env, argv);
|
||||
wpConfig.mode = "production";
|
||||
wpConfig.entry = () => ({});
|
||||
|
||||
const switchPlugin = (reMatcher, replacement) => {
|
||||
const scrubLoader = (obj) =>
|
||||
typeof obj == "string" && obj.match(reMatcher) ? Object.assign({}, replacement) : obj;
|
||||
|
||||
return (rule) => {
|
||||
if (rule.use && rule.use.length) {
|
||||
rule.use = rule.use.map(scrubLoader);
|
||||
}
|
||||
return rule;
|
||||
};
|
||||
};
|
||||
|
||||
// Remove MiniCssExtractPlugin loader references
|
||||
// replace mini-css-extract plugin with basic style loader
|
||||
// Honestly I'm not clear on why we process css at all for unit tests
|
||||
const scrubLoaderRules = (module) => {
|
||||
const rePluginMatch = /mini-css-extract-plugin/;
|
||||
const styleLoader = { loader: "style-loader" };
|
||||
const processor = switchPlugin(rePluginMatch, styleLoader);
|
||||
module.rules = module.rules.map(processor);
|
||||
};
|
||||
|
||||
// Remove mini-css-extract loader references
|
||||
scrubLoaderRules(wpConfig.module);
|
||||
|
||||
// remove MiniCSSExtract Plugin
|
||||
wpConfig.plugins = wpConfig.plugins.filter((p) => {
|
||||
return p.constructor.name != "MiniCssExtractPlugin";
|
||||
});
|
||||
|
||||
return wpConfig;
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Unit tests should not require css or images, so replace all those things with
|
||||
* the ignore-loader for speedier testing.
|
||||
*/
|
||||
|
||||
const merge = require("webpack-merge");
|
||||
const baseConfig = require("../../webpack.config");
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const wpConfig = baseConfig(env, argv);
|
||||
wpConfig.mode = "development";
|
||||
wpConfig.entry = () => ({});
|
||||
|
||||
// Don't need any assets for unit testing
|
||||
const ignoreAssetLoaders = {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?.*$|$)/,
|
||||
loader: "ignore-loader",
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: "ignore-loader",
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
loader: "ignore-loader",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
wpConfig.module = merge.merge(wpConfig.module, ignoreAssetLoaders);
|
||||
|
||||
return wpConfig;
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
/** Creates a generic/global Galaxy environment, loads shared libraries and a
|
||||
* fake server */
|
||||
|
||||
// jQuery.fn.tooltip lives on one of these 2 libs
|
||||
import "bootstrap";
|
||||
|
||||
import sinon from "sinon";
|
||||
import Backbone from "backbone";
|
||||
import { setGalaxyInstance } from "app";
|
||||
import { getAppRoot } from "onload";
|
||||
import galaxyOptions from "./test-data/bootstrapped";
|
||||
import serverdata from "./test-data/fakeserver";
|
||||
|
||||
export function setupTestGalaxy(galaxyOptions_ = null) {
|
||||
galaxyOptions_ = galaxyOptions_ || galaxyOptions;
|
||||
setGalaxyInstance((GalaxyApp) => {
|
||||
const galaxy = new GalaxyApp(galaxyOptions_);
|
||||
galaxy.currHistoryPanel = {
|
||||
model: new Backbone.Model(),
|
||||
};
|
||||
galaxy.emit = {
|
||||
debug: function () {},
|
||||
error: function (v) {
|
||||
window.console.error(v);
|
||||
},
|
||||
};
|
||||
return galaxy;
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
create() {
|
||||
setupTestGalaxy(galaxyOptions);
|
||||
window.WAIT_FADE = 300;
|
||||
window.fakeserver = sinon.fakeServer.create();
|
||||
for (var route in serverdata) {
|
||||
window.fakeserver.respondWith("GET", getAppRoot() + route, [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
serverdata[route].data,
|
||||
]);
|
||||
}
|
||||
},
|
||||
|
||||
destroy() {
|
||||
if (window.fakeserver) {
|
||||
window.fakeserver.restore();
|
||||
delete window.fakeserver;
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
import dataTypesMapping from "./json/datatypes.mapping.json";
|
||||
import dataTypes from "./json/datatypes.json";
|
||||
|
||||
export default {
|
||||
"api/datatypes/mapping": {
|
||||
data: JSON.stringify(dataTypesMapping),
|
||||
},
|
||||
"api/datatypes": {
|
||||
data: JSON.stringify(dataTypes),
|
||||
},
|
||||
};
|
||||
@@ -1,529 +0,0 @@
|
||||
// ============================================================================
|
||||
var tools = {
|
||||
upload1: {},
|
||||
"Show beginning1": {},
|
||||
"Show tail1": {},
|
||||
random_lines1: {},
|
||||
__SET_METADATA__: {},
|
||||
cat1: {},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// plain 3 step job chain
|
||||
var jobs1 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-03T15:12:25.904033",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:12:22.589152",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "8a81cf6f989c4467",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-03T15:14:04.328484",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "132016f833b57406",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:14:01.060662",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "6505e875ddb66fd2",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "Show tail1",
|
||||
update_time: "2014-10-03T15:14:21.596871",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "132016f833b57406",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "846fb0a2a64137c0",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:14:18.425681",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "77f74776fd03cbc5",
|
||||
tool: null,
|
||||
},
|
||||
];
|
||||
|
||||
var historyContents1 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "8c959c9304a2bc4b",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/8c959c9304a2bc4b",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "132016f833b57406",
|
||||
name: "Select first on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/132016f833b57406",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "846fb0a2a64137c0",
|
||||
name: "Select last on data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/846fb0a2a64137c0",
|
||||
visible: true,
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// single job chain with a __SET_METADATA__ job
|
||||
var jobs2 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-03T16:09:49.590769",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:09:45.190023",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "bf60fd5f5f7f44bf",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "random_lines1",
|
||||
update_time: "2014-10-03T16:10:44.743610",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "6fc9fbb81c497f69",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:10:41.446413",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "90240358ebde1489",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "__SET_METADATA__",
|
||||
update_time: "2014-10-03T16:14:44.196697",
|
||||
inputs: {
|
||||
input1: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c",
|
||||
},
|
||||
},
|
||||
outputs: {},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:14:37.901222",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "86cf1d3beeec9f1c",
|
||||
tool: null,
|
||||
},
|
||||
];
|
||||
|
||||
var historyContents2 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "ff5476bcf6c921fa",
|
||||
id: "eca0af6fb47bf90c",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/ff5476bcf6c921fa/contents/datasets/eca0af6fb47bf90c",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "ff5476bcf6c921fa",
|
||||
id: "6fc9fbb81c497f69",
|
||||
name: "Select random lines on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/ff5476bcf6c921fa/contents/datasets/6fc9fbb81c497f69",
|
||||
visible: true,
|
||||
},
|
||||
];
|
||||
|
||||
var jobs3 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-13T20:28:58.549844",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "6fb17d0cc6e8fae5",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:28:43.162803",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "8c959c9304a2bc4b",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-13T20:28:58.932152",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "5114a2a207b7caff",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:28:47.421452",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "132016f833b57406",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-13T20:29:31.424058",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "6fb17d0cc6e8fae5",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "06ec17aefa2d49dd",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:29:28.769495",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "846fb0a2a64137c0",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-13T20:29:55.851096",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "5114a2a207b7caff",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "b8a0d6158b9961df",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:29:53.291703",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "eca0af6fb47bf90c",
|
||||
tool: null,
|
||||
},
|
||||
{
|
||||
tool_id: "Show tail1",
|
||||
update_time: "2014-10-13T20:30:16.225937",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "b8a0d6158b9961df",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "24d84bcf64116fe7",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:30:13.789842",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "6fc9fbb81c497f69",
|
||||
tool: null,
|
||||
},
|
||||
];
|
||||
|
||||
var historyContents3 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "bed",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "6fb17d0cc6e8fae5",
|
||||
name: "1.bed",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/6fb17d0cc6e8fae5",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "5114a2a207b7caff",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/5114a2a207b7caff",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "bed",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "06ec17aefa2d49dd",
|
||||
name: "Select first on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/06ec17aefa2d49dd",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 4,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "b8a0d6158b9961df",
|
||||
name: "Select first on data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/b8a0d6158b9961df",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 5,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "24d84bcf64116fe7",
|
||||
name: "Select last on data 4",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/24d84bcf64116fe7",
|
||||
visible: true,
|
||||
},
|
||||
];
|
||||
|
||||
var jobs4 = [
|
||||
{
|
||||
tool_id: "cat1",
|
||||
update_time: "2014-10-21T17:33:36.960857",
|
||||
inputs: {
|
||||
input1: {
|
||||
src: "hda",
|
||||
id: "422eef6b1b545329",
|
||||
name: "input1",
|
||||
},
|
||||
"queries_0|input2": {
|
||||
src: "hda",
|
||||
id: "c86c1b73aa7102dd",
|
||||
name: "queries_0|input2",
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "52d6bdfafedbb5e5",
|
||||
name: "out_file1",
|
||||
},
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-21T17:33:34.302245",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "92b83968e0b52980",
|
||||
},
|
||||
];
|
||||
|
||||
var historyContents4 = [
|
||||
{
|
||||
dataset_id: 29,
|
||||
deleted: false,
|
||||
extension: "vcf",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "422eef6b1b545329",
|
||||
name: "1.vcf",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/422eef6b1b545329",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
dataset_id: 56,
|
||||
deleted: false,
|
||||
extension: "maf",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "c86c1b73aa7102dd",
|
||||
name: "3.maf",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/c86c1b73aa7102dd",
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
dataset_id: 131,
|
||||
deleted: false,
|
||||
extension: "maf",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "52d6bdfafedbb5e5",
|
||||
name: "Concatenate datasets on data 1 and data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/52d6bdfafedbb5e5",
|
||||
visible: true,
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
export default {
|
||||
tools: tools,
|
||||
jobs1: jobs1,
|
||||
historyContents1: historyContents1,
|
||||
jobs2: jobs2,
|
||||
historyContents2: historyContents2,
|
||||
jobs3: jobs3,
|
||||
historyContents3: historyContents3,
|
||||
jobs4: jobs4,
|
||||
historyContents4: historyContents4,
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
// Load all qunit tests into a single bundle.
|
||||
//var testsContext = require.context(".", true, /_tests$/);
|
||||
//testsContext.keys().forEach(testsContext);
|
||||
|
||||
import "./tests/galaxy_app_base_tests";
|
||||
import "./tests/jquery_plugin_tests";
|
||||
import "./tests/metrics_logger_tests";
|
||||
import "./tests/graph_tests";
|
||||
import "./tests/modal_tests";
|
||||
import "./tests/utils_tests";
|
||||
import "./tests/ui_tests";
|
||||
@@ -1,76 +0,0 @@
|
||||
/* global QUnit */
|
||||
import testApp from "../test-app";
|
||||
import { getGalaxyInstance, setGalaxyInstance } from "app";
|
||||
|
||||
QUnit.module("Galaxy client app tests", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("App base construction/initializiation defaults", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
assert.ok(app.hasOwnProperty("options") && typeof app.options === "object");
|
||||
assert.ok(app.hasOwnProperty("logger") && typeof app.logger === "object");
|
||||
assert.ok(app.hasOwnProperty("localize") && typeof app.localize === "function");
|
||||
assert.ok(app.hasOwnProperty("config") && typeof app.config === "object");
|
||||
assert.ok(app.hasOwnProperty("user") && typeof app.config === "object");
|
||||
assert.equal(app.localize, window._l);
|
||||
});
|
||||
|
||||
QUnit.test("App base default options", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
assert.ok(app.hasOwnProperty("options") && typeof app.options === "object");
|
||||
assert.equal(app.options.root, "/");
|
||||
assert.equal(app.options.patchExisting, true);
|
||||
});
|
||||
|
||||
QUnit.test("App base extends from Backbone.Events", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
["on", "off", "trigger", "listenTo", "stopListening"].forEach(function (fn) {
|
||||
assert.ok(app.hasOwnProperty(fn) && typeof app[fn] === "function");
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("App base has logging methods from utils/add-logging.js", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
["debug", "info", "warn", "error", "metric"].forEach(function (fn) {
|
||||
assert.ok(typeof app[fn] === "function");
|
||||
});
|
||||
assert.ok(app._logNamespace === "GalaxyApp");
|
||||
});
|
||||
|
||||
// We no longer want this behavior
|
||||
QUnit.test("App base will patch in attributes from existing Galaxy objects", function (assert) {
|
||||
var existingApp = getGalaxyInstance();
|
||||
existingApp.foo = 123;
|
||||
|
||||
var newApp = setGalaxyInstance((GalaxyApp) => {
|
||||
return new GalaxyApp();
|
||||
});
|
||||
|
||||
assert.ok(newApp.foo === 123);
|
||||
});
|
||||
|
||||
QUnit.test("App base logger", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
assert.ok(app.hasOwnProperty("logger") && typeof app.config === "object");
|
||||
});
|
||||
|
||||
QUnit.test("App base config", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
assert.ok(app.hasOwnProperty("config") && typeof app.config === "object");
|
||||
assert.equal(app.config.allow_user_deletion, false);
|
||||
assert.equal(app.config.allow_user_creation, true);
|
||||
assert.equal(app.config.wiki_url, "https://galaxyproject.org/");
|
||||
assert.equal(app.config.ftp_upload_site, null);
|
||||
});
|
||||
|
||||
QUnit.test("App base user", function (assert) {
|
||||
var app = getGalaxyInstance();
|
||||
assert.ok(app.hasOwnProperty("user") && typeof app.user === "object");
|
||||
assert.ok(app.user.isAdmin() === false);
|
||||
});
|
||||
@@ -1,563 +0,0 @@
|
||||
/* global QUnit */
|
||||
import testApp from "../test-app";
|
||||
import GRAPH from "utils/graph";
|
||||
|
||||
QUnit.module("utils/graph.js library tests", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
///*
|
||||
function testEmptyObject(assert, o) {
|
||||
assert.ok(typeof o === "object");
|
||||
assert.ok(Object.keys(o).length === 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ vertices
|
||||
QUnit.test("Empty vertex construction", function (assert) {
|
||||
var vert = new GRAPH.Vertex();
|
||||
assert.ok(vert instanceof GRAPH.Vertex);
|
||||
assert.ok(vert.name === "(unnamed)");
|
||||
assert.ok(vert.data === null);
|
||||
testEmptyObject(assert, vert.edges);
|
||||
assert.ok(vert.degree === 0);
|
||||
assert.ok(vert + "" === "Vertex((unnamed))");
|
||||
assert.deepEqual(vert.toJSON(), { name: "(unnamed)", data: null });
|
||||
});
|
||||
|
||||
QUnit.test("Vertex construction", function (assert) {
|
||||
var vert = new GRAPH.Vertex("blah", { blorp: 1, bleep: 2 });
|
||||
assert.ok(vert instanceof GRAPH.Vertex);
|
||||
assert.ok(vert.name === "blah");
|
||||
assert.deepEqual(vert.data, { blorp: 1, bleep: 2 });
|
||||
testEmptyObject(assert, vert.edges);
|
||||
assert.ok(vert.degree === 0);
|
||||
assert.ok(vert + "" === "Vertex(blah)");
|
||||
assert.deepEqual(vert.toJSON(), { name: "blah", data: { blorp: 1, bleep: 2 } });
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ edges
|
||||
QUnit.test("Empty edge construction", function (assert) {
|
||||
var edge = new GRAPH.Edge();
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(edge.source === null);
|
||||
assert.ok(edge.target === null);
|
||||
assert.ok(edge.data === null);
|
||||
assert.ok(edge + "" === "null->null");
|
||||
assert.deepEqual(edge.toJSON(), { source: null, target: null });
|
||||
});
|
||||
|
||||
QUnit.test("Edge construction", function (assert) {
|
||||
var edge = new GRAPH.Edge("A", "B", { one: 1, two: 2 });
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(edge.source === "A");
|
||||
assert.ok(edge.target === "B");
|
||||
assert.deepEqual(edge.data, { one: 1, two: 2 });
|
||||
assert.ok(edge + "" === "A->B");
|
||||
assert.deepEqual(edge.toJSON(), { source: "A", target: "B", data: { one: 1, two: 2 } });
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ graphs
|
||||
function testEmptyGraph(assert, graph) {
|
||||
assert.ok(graph instanceof GRAPH.Graph);
|
||||
testEmptyObject(assert, graph.vertices);
|
||||
assert.ok(graph.numEdges === 0);
|
||||
}
|
||||
|
||||
QUnit.test("Empty graph construction", function (assert) {
|
||||
var graph = new GRAPH.Graph();
|
||||
|
||||
assert.ok(graph.directed === false);
|
||||
assert.ok(graph.allowReflexiveEdges === false);
|
||||
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Bad data graph construction", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, {});
|
||||
testEmptyGraph(assert, graph);
|
||||
|
||||
graph = new GRAPH.Graph(false, null);
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test directed and options", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, {}, { allowReflexiveEdges: true });
|
||||
|
||||
assert.ok(graph.directed);
|
||||
assert.ok(graph.allowReflexiveEdges);
|
||||
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
function testSampleDirectedGraph(assert, graph) {
|
||||
assert.ok(!graph.directed);
|
||||
|
||||
assert.ok(Object.keys(graph.vertices).length === 3);
|
||||
assert.ok(graph.vertices.A instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.B instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.C instanceof GRAPH.Vertex);
|
||||
|
||||
assert.deepEqual(Object.keys(graph.vertices.A.edges), ["B", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.B.edges), ["A", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.C.edges), ["A", "B"]);
|
||||
|
||||
assert.ok(graph.vertices.A.degree === 2);
|
||||
assert.ok(graph.vertices.B.degree === 2);
|
||||
assert.ok(graph.vertices.C.degree === 2);
|
||||
|
||||
assert.deepEqual(graph.vertices.A.edges.B.toJSON(), { source: "A", target: "B" });
|
||||
assert.deepEqual(graph.vertices.A.edges.C.toJSON(), { source: "A", target: "C" });
|
||||
assert.deepEqual(graph.vertices.B.edges.A.toJSON(), { source: "B", target: "A" });
|
||||
assert.deepEqual(graph.vertices.B.edges.C.toJSON(), { source: "B", target: "C" });
|
||||
assert.deepEqual(graph.vertices.C.edges.A.toJSON(), { source: "C", target: "A" });
|
||||
assert.deepEqual(graph.vertices.C.edges.B.toJSON(), { source: "C", target: "B" });
|
||||
|
||||
assert.ok(graph.numEdges === 6);
|
||||
}
|
||||
|
||||
function testSampleNonDirectedGraph(assert, graph) {
|
||||
assert.ok(graph.directed);
|
||||
|
||||
assert.ok(Object.keys(graph.vertices).length === 3);
|
||||
assert.ok(graph.vertices.A instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.B instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.C instanceof GRAPH.Vertex);
|
||||
|
||||
assert.deepEqual(Object.keys(graph.vertices.A.edges), ["B", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.B.edges), ["C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.C.edges), []);
|
||||
|
||||
assert.ok(graph.vertices.A.degree === 2);
|
||||
assert.ok(graph.vertices.B.degree === 1);
|
||||
assert.ok(graph.vertices.C.degree === 0);
|
||||
|
||||
assert.deepEqual(graph.vertices.A.edges.B.toJSON(), { source: "A", target: "B" });
|
||||
assert.deepEqual(graph.vertices.A.edges.C.toJSON(), { source: "A", target: "C" });
|
||||
assert.deepEqual(graph.vertices.B.edges.C.toJSON(), { source: "B", target: "C" });
|
||||
|
||||
assert.ok(graph.numEdges === 3);
|
||||
}
|
||||
|
||||
var nodeLinkData = {
|
||||
nodes: [
|
||||
{ name: "A", data: 100 },
|
||||
{ name: "B", data: 200 },
|
||||
{ name: "C", data: 300 },
|
||||
],
|
||||
links: [
|
||||
{ source: 0, target: 1 },
|
||||
{ source: 0, target: 2 },
|
||||
{ source: 1, target: 2 },
|
||||
],
|
||||
};
|
||||
|
||||
QUnit.test("Test nodes and links data input on *non-directed* graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
testSampleDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test nodes and links data input on *directed* graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
testSampleNonDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
var vertexEdgeData = {
|
||||
vertices: [
|
||||
{ name: "A", data: 100 },
|
||||
{ name: "B", data: 200 },
|
||||
{ name: "C", data: 300 },
|
||||
],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "A", target: "C" },
|
||||
{ source: "B", target: "C" },
|
||||
],
|
||||
};
|
||||
|
||||
QUnit.test("Test vertex and edge data input on *non-directed* graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, vertexEdgeData);
|
||||
testSampleDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test vertex and edge data input on *directed* graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, vertexEdgeData);
|
||||
testSampleNonDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test vertex eachEdge", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
assert.ok(typeof graph.vertices.A.eachEdge === "function");
|
||||
assert.deepEqual(
|
||||
graph.vertices.A.eachEdge(function (e) {
|
||||
return e.target;
|
||||
}),
|
||||
["B", "C"]
|
||||
);
|
||||
assert.ok(graph.vertices.A.eachEdge({ target: "B" }).length === 1);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph eachVertex", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.ok(typeof graph.eachVertex === "function");
|
||||
assert.deepEqual(
|
||||
graph.eachVertex(function (v) {
|
||||
return { n: v.name, d: v.degree };
|
||||
}),
|
||||
[
|
||||
{ n: "A", d: 2 },
|
||||
{ n: "B", d: 1 },
|
||||
{ n: "C", d: 0 },
|
||||
]
|
||||
);
|
||||
assert.ok(graph.eachVertex({ degree: 2 })[0] === graph.vertices.A);
|
||||
});
|
||||
|
||||
QUnit.test("Test createVertex", function (assert) {
|
||||
var graph = new GRAPH.Graph();
|
||||
var vert1 = graph.createVertex("A", { blah: 1 });
|
||||
assert.ok(vert1 instanceof GRAPH.Vertex);
|
||||
assert.ok(vert1 === graph.vertices.A);
|
||||
assert.ok(graph.createVertex("A", { blah: 1 }) === vert1);
|
||||
});
|
||||
|
||||
QUnit.test("Test createEdge", function (assert) {
|
||||
var graph, A, B, edge;
|
||||
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "B");
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(A.degree === 1);
|
||||
assert.ok(B.degree === 1);
|
||||
assert.ok(A.edges.B);
|
||||
assert.ok(B.edges.A);
|
||||
assert.ok(graph.numEdges === 2);
|
||||
|
||||
// bad target
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "C");
|
||||
assert.ok(edge === null);
|
||||
assert.ok(A.degree === 0);
|
||||
assert.ok(B.degree === 0);
|
||||
assert.ok(!A.edges.B);
|
||||
assert.ok(!B.edges.A);
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// bad source
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("C", "A");
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// reflexive
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "A");
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// reflexive (allowed)
|
||||
graph = new GRAPH.Graph(false, {}, { allowReflexiveEdges: true });
|
||||
A = graph.createVertex("A");
|
||||
edge = graph.createEdge("A", "A");
|
||||
// reflexive edges shouldn't mirror
|
||||
assert.ok(graph.numEdges === 1);
|
||||
assert.ok(A.edges.A);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.edges", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
assert.ok(graph.edges().length === 6);
|
||||
assert.deepEqual(
|
||||
graph.edges(function (e) {
|
||||
return e.source;
|
||||
}),
|
||||
["A", "A", "B", "B", "C", "C"]
|
||||
);
|
||||
assert.deepEqual(graph.edges({ source: "A" }), [graph.vertices.A.edges.B, graph.vertices.A.edges.C]);
|
||||
|
||||
graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.ok(graph.edges().length === 3);
|
||||
assert.deepEqual(
|
||||
graph.edges(function (e) {
|
||||
return e.source;
|
||||
}),
|
||||
["A", "A", "B"]
|
||||
);
|
||||
assert.deepEqual(graph.edges({ source: "A" }), [graph.vertices.A.edges.B, graph.vertices.A.edges.C]);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.adjacent", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.A), [graph.vertices.B, graph.vertices.C]);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.B), [graph.vertices.C]);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.C), []);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.eachAdjacent", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.deepEqual(
|
||||
graph.eachAdjacent(graph.vertices.A, function (v, e) {
|
||||
return v;
|
||||
}),
|
||||
[graph.vertices.B, graph.vertices.C]
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ breadth first search
|
||||
QUnit.test("Empty BreadthFirstSearch", function (assert) {
|
||||
var search = new GRAPH.BreadthFirstSearch();
|
||||
assert.ok(search instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(search.graph === undefined);
|
||||
assert.ok(typeof search.processFns === "object");
|
||||
assert.ok(typeof search.processFns.vertexEarly === "function");
|
||||
assert.ok(typeof search.processFns.edge === "function");
|
||||
assert.ok(typeof search.processFns.vertexLate === "function");
|
||||
assert.ok(typeof search._cache === "object");
|
||||
});
|
||||
|
||||
QUnit.test("BreadthFirstSearch on undirected graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData),
|
||||
bfs = new GRAPH.BreadthFirstSearch(graph);
|
||||
assert.ok(bfs instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(bfs.graph === graph);
|
||||
|
||||
var search = bfs.search("A"),
|
||||
tree = bfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "A", target: "C" },
|
||||
],
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function (v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 0, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(bfs.search("B").edges, [
|
||||
{ source: "B", target: "A" },
|
||||
{ source: "B", target: "C" },
|
||||
]);
|
||||
assert.deepEqual(bfs.search("C").edges, [
|
||||
{ source: "C", target: "A" },
|
||||
{ source: "C", target: "B" },
|
||||
]);
|
||||
assert.ok(typeof bfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(bfs._cache), ["A", "B", "C"]);
|
||||
});
|
||||
|
||||
QUnit.test("BreadthFirstSearch on directed graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData),
|
||||
bfs = new GRAPH.BreadthFirstSearch(graph);
|
||||
assert.ok(bfs instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(bfs.graph === graph);
|
||||
|
||||
var search = bfs.search("A"),
|
||||
tree = bfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "A", target: "C" },
|
||||
],
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function (v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 0, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(bfs.search("B").edges, [{ source: "B", target: "C" }]);
|
||||
assert.deepEqual(bfs.search("C").edges, []);
|
||||
assert.ok(typeof bfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(bfs._cache), ["A", "B", "C"]);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ depth first search
|
||||
var DFSData = {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }, { name: "F" }],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
// confound it
|
||||
{ source: "A", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" },
|
||||
// confound it
|
||||
{ source: "F", target: "A" },
|
||||
],
|
||||
};
|
||||
|
||||
QUnit.test("Empty DepthFirstSearch", function (assert) {
|
||||
var search = new GRAPH.DepthFirstSearch();
|
||||
assert.ok(search instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(search.graph === undefined);
|
||||
assert.ok(typeof search.processFns === "object");
|
||||
assert.ok(typeof search.processFns.vertexEarly === "function");
|
||||
assert.ok(typeof search.processFns.edge === "function");
|
||||
assert.ok(typeof search.processFns.vertexLate === "function");
|
||||
assert.ok(typeof search._cache === "object");
|
||||
});
|
||||
|
||||
QUnit.test("DepthFirstSearch on undirected graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, DFSData),
|
||||
dfs = new GRAPH.DepthFirstSearch(graph);
|
||||
assert.ok(dfs instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(dfs.graph === graph);
|
||||
|
||||
var search = dfs.search("A"),
|
||||
tree = dfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true, D: true, E: true, F: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" },
|
||||
],
|
||||
entryTimes: { A: 0, B: 1, C: 2, D: 3, E: 7, F: 8 },
|
||||
exitTimes: { A: 11, B: 6, C: 5, D: 4, E: 10, F: 9 },
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function (v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 1, 1, 0, 1, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(dfs.search("B").edges, [
|
||||
{ source: "B", target: "A" },
|
||||
{ source: "A", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" },
|
||||
]);
|
||||
|
||||
assert.ok(typeof dfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(dfs._cache), ["A", "B"]);
|
||||
});
|
||||
|
||||
QUnit.test("DepthFirstSearch on directed graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(true, DFSData),
|
||||
dfs = new GRAPH.DepthFirstSearch(graph);
|
||||
assert.ok(dfs instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(dfs.graph === graph);
|
||||
|
||||
var search = dfs.search("A"),
|
||||
tree = dfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true, D: true, E: true, F: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" },
|
||||
],
|
||||
entryTimes: { A: 0, B: 1, C: 2, D: 3, E: 7, F: 8 },
|
||||
exitTimes: { A: 11, B: 6, C: 5, D: 4, E: 10, F: 9 },
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function (v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 1, 1, 0, 1, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(dfs.search("B").edges, [
|
||||
{ source: "B", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
]);
|
||||
|
||||
assert.ok(typeof dfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(dfs._cache), ["A", "B"]);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ components
|
||||
//*/
|
||||
QUnit.test("weakComponents on undirected graph", function (assert) {
|
||||
var graph = new GRAPH.Graph(false, {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "C", target: "D" },
|
||||
],
|
||||
});
|
||||
assert.equal(graph.numEdges, 4);
|
||||
var components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
});
|
||||
|
||||
QUnit.test("weakComponents on directed graph", function (assert) {
|
||||
var graph, components;
|
||||
graph = new GRAPH.Graph(true, {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "D", target: "C" },
|
||||
],
|
||||
});
|
||||
assert.equal(graph.numEdges, 2);
|
||||
|
||||
components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
|
||||
graph = new GRAPH.Graph(true, {
|
||||
vertices: [
|
||||
{ name: "A", data: 100 },
|
||||
{ name: "B", data: 200 },
|
||||
{ name: "C", data: 30 },
|
||||
{ name: "D", data: 40 },
|
||||
{ name: "E", data: 500 },
|
||||
{ name: "F", data: 600 },
|
||||
{ name: "G", data: 7 },
|
||||
],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "D", target: "C" },
|
||||
{ source: "E", target: "A" },
|
||||
{ source: "F", target: "E" },
|
||||
],
|
||||
});
|
||||
components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
// data retained
|
||||
assert.equal(components[0].vertices[0].data, 100);
|
||||
|
||||
assert.equal(components[0].vertices.length, 4);
|
||||
assert.deepEqual(components[0].edges, [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "E", target: "A" },
|
||||
{ source: "F", target: "E" },
|
||||
]);
|
||||
|
||||
assert.equal(components[1].vertices.length, 2);
|
||||
assert.deepEqual(components[1].edges, [{ source: "D", target: "C" }]);
|
||||
|
||||
assert.deepEqual(components[2].vertices, [{ name: "G", data: 7 }]);
|
||||
assert.deepEqual(components[2].edges.length, 0);
|
||||
});
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/* global QUnit */
|
||||
import $ from "jquery";
|
||||
import testApp from "../test-app";
|
||||
|
||||
QUnit.module("Galaxy jquery plugin test", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("Check jquery for tooltip and select2", function (assert) {
|
||||
assert.ok($.fn.tooltip);
|
||||
assert.ok($.fn.select2);
|
||||
});
|
||||
@@ -1,379 +0,0 @@
|
||||
// This file isn't really testing anything useful yet, it is just testing
|
||||
// (or demonstrating) qunit+backbone interactions.
|
||||
|
||||
/* global QUnit */
|
||||
import jQuery from "jquery";
|
||||
import sinon from "sinon";
|
||||
import metrics from "utils/metrics-logger";
|
||||
import testApp from "../test-app";
|
||||
|
||||
var MockConsole = function () {
|
||||
var self = this;
|
||||
self.lastMessage = null;
|
||||
["log", "debug", "info", "warn", "error"].forEach(function (fnName) {
|
||||
self[fnName] = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
self.lastMessage = { level: fnName, args: args };
|
||||
};
|
||||
});
|
||||
return self;
|
||||
};
|
||||
|
||||
(window.bootstrapped = {}).user = {
|
||||
id: "test",
|
||||
};
|
||||
|
||||
QUnit.module("Metrics logger tests", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
// ======================================================================== MetricsLogger
|
||||
QUnit.test("logger construction/initializiation defaults", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({});
|
||||
assert.equal(logger.consoleLogger, null);
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger.options.consoleLevel, metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger.options.defaultNamespace, "Galaxy");
|
||||
assert.equal(logger.options.clientPrefix, "client.");
|
||||
assert.equal(logger.options.postSize, 1000);
|
||||
assert.equal(logger.options.maxCacheSize, 3000);
|
||||
assert.equal(logger.options.addTime, true);
|
||||
assert.equal(logger.options.postUrl, "/api/metrics");
|
||||
assert.equal(logger.options.getPingData, undefined);
|
||||
assert.equal(logger.options.onServerResponse, undefined);
|
||||
|
||||
assert.equal(logger._postSize, 1000);
|
||||
assert.equal(logger.cache.constructor, metrics.LoggingCache);
|
||||
});
|
||||
|
||||
QUnit.test("_parseLevel", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({});
|
||||
assert.equal(logger._parseLevel("all"), metrics.MetricsLogger.ALL);
|
||||
assert.equal(logger._parseLevel("debug"), metrics.MetricsLogger.DEBUG);
|
||||
assert.equal(logger._parseLevel("info"), metrics.MetricsLogger.INFO);
|
||||
assert.equal(logger._parseLevel("warn"), metrics.MetricsLogger.WARN);
|
||||
assert.equal(logger._parseLevel("error"), metrics.MetricsLogger.ERROR);
|
||||
assert.equal(logger._parseLevel("metric"), metrics.MetricsLogger.METRIC);
|
||||
assert.equal(logger._parseLevel("none"), metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger._parseLevel(15), 15);
|
||||
|
||||
assert.throws(
|
||||
function () {
|
||||
logger._parseLevel(undefined);
|
||||
},
|
||||
/Unknown log level/,
|
||||
"Unknown log level throws error"
|
||||
);
|
||||
assert.throws(
|
||||
function () {
|
||||
logger._parseLevel("nope");
|
||||
},
|
||||
/Unknown log level/,
|
||||
"Unknown log level throws error"
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Emit to cache
|
||||
QUnit.test("emit to cache at level", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.METRIC);
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 1);
|
||||
|
||||
var cached = logger.cache.get(1)[0];
|
||||
//console.debug( 'cached:', JSON.stringify( cached ) );
|
||||
assert.equal(cached.level, metrics.MetricsLogger.METRIC);
|
||||
assert.equal(cached.namespace, "client.test");
|
||||
assert.equal(cached.args.length, 3);
|
||||
assert.equal(cached.args[2].three, 3);
|
||||
assert.ok(typeof cached.time === "string");
|
||||
assert.ok(cached.time === new Date(cached.time).toISOString());
|
||||
});
|
||||
|
||||
QUnit.test("emit to cache below does not cache", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
logger.emit("error", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 0);
|
||||
});
|
||||
|
||||
QUnit.test("emit to cache (silently) drops non-parsable", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
logger.emit("metric", "test", [{ window: window }]);
|
||||
assert.equal(logger.cache.length(), 0);
|
||||
});
|
||||
|
||||
function metricsFromRequestBody(request) {
|
||||
// assumes 'metrics' is only entry in requestBody
|
||||
return JSON.parse(decodeURIComponent(request.requestBody.replace("metrics=", "")));
|
||||
}
|
||||
|
||||
QUnit.test("_postCache success", function (assert) {
|
||||
var callback = sinon.spy(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
onServerResponse: function (response) {
|
||||
callback();
|
||||
},
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
var server = sinon.fakeServer.create(),
|
||||
metricsOnServer;
|
||||
server.respondWith("POST", "/api/metrics", function (request) {
|
||||
metricsOnServer = metricsFromRequestBody(request);
|
||||
//console.debug( 'requestBody:', request.requestBody );
|
||||
//console.debug( 'metricsOnServer:', JSON.stringify( metricsOnServer, null, ' ' ) );
|
||||
request.respond(
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify({
|
||||
fakeResponse: "yes",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
logger._postCache();
|
||||
server.respond();
|
||||
|
||||
assert.ok(callback.calledOnce, "onServerResponse was called");
|
||||
assert.equal(logger.cache.length(), 0, "should have emptied cache (on success)");
|
||||
assert.equal(logger._postSize, 1000, "_postSize still at default");
|
||||
|
||||
// metrics were in proper form on server
|
||||
assert.equal(metricsOnServer.length, 1);
|
||||
var metric = metricsOnServer[0];
|
||||
assert.equal(metric.level, metrics.MetricsLogger.METRIC);
|
||||
assert.equal(metric.namespace, "client.test");
|
||||
assert.equal(metric.args.length, 3);
|
||||
assert.equal(metric.args[2].three, 3);
|
||||
assert.ok(typeof metric.time === "string");
|
||||
assert.ok(metric.time === new Date(metric.time).toISOString());
|
||||
|
||||
server.restore();
|
||||
});
|
||||
|
||||
QUnit.test("_postCache failure", function (assert) {
|
||||
var callback = sinon.spy(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
onServerResponse: function (response) {
|
||||
callback();
|
||||
},
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
var server = sinon.fakeServer.create();
|
||||
server.respondWith("POST", "/api/metrics", function (request) {
|
||||
request.respond(
|
||||
500,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify({
|
||||
err_msg: "NoooOPE!",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
logger._postCache();
|
||||
server.respond();
|
||||
//TODO: is the following what we want?
|
||||
assert.ok(!callback.calledOnce, "onServerResponse was NOT called");
|
||||
assert.equal(logger.cache.length(), 1, "should NOT have emptied cache");
|
||||
assert.equal(logger._postSize, logger.options.maxCacheSize, "_postSize changed to max");
|
||||
|
||||
server.restore();
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Emit to console
|
||||
QUnit.test("emit to console at level", function (assert) {
|
||||
var mockConsole = new MockConsole(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
consoleLevel: "debug",
|
||||
consoleLogger: mockConsole,
|
||||
});
|
||||
assert.equal(logger.options.consoleLevel, metrics.MetricsLogger.DEBUG);
|
||||
assert.equal(logger.consoleLogger.constructor, MockConsole);
|
||||
|
||||
logger.emit("debug", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 1);
|
||||
//console.debug( JSON.stringify( mockConsole.lastMessage ) );
|
||||
assert.equal(mockConsole.lastMessage.level, "debug");
|
||||
assert.equal(mockConsole.lastMessage.args.length, 4);
|
||||
assert.equal(mockConsole.lastMessage.args[0], "test");
|
||||
assert.equal(mockConsole.lastMessage.args[3].three, 3);
|
||||
});
|
||||
|
||||
QUnit.test("emit to console below does not output", function (assert) {
|
||||
var mockConsole = new MockConsole(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
consoleLevel: "error",
|
||||
consoleLogger: mockConsole,
|
||||
});
|
||||
logger.emit("debug", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(mockConsole.lastMessage, null);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Shortcuts
|
||||
QUnit.test("logger shortcuts emit to default namespace properly", function (assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "all",
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.ALL);
|
||||
logger.log(0);
|
||||
logger.debug(1);
|
||||
logger.info(2);
|
||||
logger.warn(3);
|
||||
logger.error(4);
|
||||
logger.metric(5);
|
||||
|
||||
assert.equal(logger.cache.length(), 6);
|
||||
var cached = logger.cache.remove(6),
|
||||
entry;
|
||||
|
||||
cached.forEach(function (entry) {
|
||||
assert.ok(entry.namespace === logger.options.clientPrefix + logger.options.defaultNamespace);
|
||||
assert.ok(jQuery.type(entry.args) === "array");
|
||||
assert.ok(typeof entry.time === "string");
|
||||
});
|
||||
|
||||
// log is different
|
||||
entry = cached[0];
|
||||
assert.ok(entry.level === 1);
|
||||
assert.ok(entry.args[0] === 0);
|
||||
|
||||
["debug", "info", "warn", "error", "metric"].forEach(function (level, i) {
|
||||
entry = cached[i + 1];
|
||||
assert.ok(entry.level === logger._parseLevel(level));
|
||||
assert.ok(entry.args[0] === i + 1);
|
||||
});
|
||||
});
|
||||
|
||||
// ======================================================================== LoggingCache
|
||||
QUnit.test("cache construction/initializiation defaults", function (assert) {
|
||||
// use empty to prevent tests stepping on one another due to persistence
|
||||
var cache = new metrics.LoggingCache({ key: "logs-test" }).empty();
|
||||
assert.equal(cache.maxSize, 5000);
|
||||
assert.equal(window.localStorage.getItem("logs-test"), "[]");
|
||||
});
|
||||
|
||||
QUnit.test("cache construction/initializiation failure", function (assert) {
|
||||
////TODO: doesn't work - readonly
|
||||
//window.localStorage = null;
|
||||
//console.debug( 'localStorage:', window.localStorage );
|
||||
var oldFn = metrics.LoggingCache.prototype._hasStorage;
|
||||
metrics.LoggingCache.prototype._hasStorage = function () {
|
||||
return false;
|
||||
};
|
||||
assert.throws(
|
||||
function () {
|
||||
return new metrics.LoggingCache({ key: "logs-test" });
|
||||
},
|
||||
/LoggingCache needs localStorage/,
|
||||
"lack of localStorage throws error"
|
||||
);
|
||||
metrics.LoggingCache.prototype._hasStorage = oldFn;
|
||||
|
||||
assert.throws(
|
||||
function () {
|
||||
return new metrics.LoggingCache();
|
||||
},
|
||||
/LoggingCache needs key for localStorage/,
|
||||
"lack of key throws error"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("cache construction/initializiation setting max cache size", function (assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5,
|
||||
}).empty();
|
||||
assert.equal(cache.maxSize, 5);
|
||||
});
|
||||
|
||||
QUnit.test("cache plays well with no data", function (assert) {
|
||||
var cache = new metrics.LoggingCache({ key: "logs-test" }).empty();
|
||||
|
||||
assert.equal(cache.length(), 0);
|
||||
var get = cache.get(10);
|
||||
assert.ok(jQuery.type(get) === "array" && get.length === 0);
|
||||
var remove = cache.remove(10);
|
||||
assert.ok(jQuery.type(remove) === "array" && remove.length === 0);
|
||||
assert.equal(cache.length(), 0);
|
||||
});
|
||||
|
||||
QUnit.test("cache add properly adds and removes data", function (assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5,
|
||||
}).empty();
|
||||
|
||||
var entry1 = [{ one: 1 }, "two"];
|
||||
cache.add(entry1);
|
||||
|
||||
assert.equal(cache.length(), 1);
|
||||
assert.equal(JSON.stringify(cache.get(1)[0]), JSON.stringify(entry1));
|
||||
|
||||
var entry2 = { blah: { one: 1 }, bler: ["three", { two: 2 }] };
|
||||
cache.add(entry2);
|
||||
assert.equal(cache.length(), 2);
|
||||
assert.equal(cache.stringify(2), "[" + JSON.stringify(entry1) + "," + JSON.stringify(entry2) + "]");
|
||||
|
||||
// FIFO
|
||||
var returned = cache.remove(1);
|
||||
assert.equal(cache.length(), 1);
|
||||
assert.ok(jQuery.type(returned) === "array" && returned.length === 1);
|
||||
var returned0 = returned[0];
|
||||
assert.ok(jQuery.type(returned0) === "array" && JSON.stringify(returned0) === JSON.stringify(entry1));
|
||||
});
|
||||
|
||||
QUnit.test("cache past max loses oldest", function (assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5,
|
||||
}).empty();
|
||||
|
||||
for (var i = 0; i < 10; i += 1) {
|
||||
cache.add({ index: i });
|
||||
}
|
||||
assert.equal(cache.length(), 5);
|
||||
var get = cache.get(5);
|
||||
assert.ok(get[0].index === 5);
|
||||
assert.ok(get[1].index === 6);
|
||||
assert.ok(get[2].index === 7);
|
||||
assert.ok(get[3].index === 8);
|
||||
assert.ok(get[4].index === 9);
|
||||
});
|
||||
|
||||
QUnit.test("cache is properly persistent", function (assert) {
|
||||
var cache1 = new metrics.LoggingCache({ key: "logs-test" }).empty(),
|
||||
entry = [{ one: 1 }, "two"];
|
||||
cache1.add(entry);
|
||||
assert.equal(cache1.length(), 1);
|
||||
|
||||
var cache2 = new metrics.LoggingCache({ key: "logs-test" });
|
||||
assert.equal(cache2.length(), 1, "old key gets previously stored");
|
||||
assert.equal(JSON.stringify(cache2.get(1)[0]), JSON.stringify(entry));
|
||||
|
||||
var cache3 = new metrics.LoggingCache({ key: "logs-bler" });
|
||||
assert.equal(cache3.length(), 0, "new key causes new storage");
|
||||
});
|
||||
@@ -1,86 +0,0 @@
|
||||
/* global QUnit */
|
||||
import $ from "jquery";
|
||||
import testApp from "../test-app";
|
||||
import GalaxyModal from "mvc/ui/ui-modal";
|
||||
|
||||
QUnit.module("Modal dialog test", {
|
||||
beforeEach: function () {
|
||||
$.fx.off = true;
|
||||
testApp.create();
|
||||
var self = this;
|
||||
this.app = new GalaxyModal.View({
|
||||
title: "Test title",
|
||||
body: "Test body",
|
||||
buttons: {
|
||||
Ok: function () {},
|
||||
Cancel: function () {
|
||||
self.app.hide();
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
afterEach: function () {
|
||||
$.fx.off = false;
|
||||
testApp.destroy();
|
||||
this.app.$el.remove();
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("test dialog attributes", function (assert) {
|
||||
assert.ok(this.app.$header.find(".title").html() == "Test title", "Modal header has correct title.");
|
||||
assert.ok(this.app.$body.html() == "Test body", "Modal header has correct body.");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog visibility", function (assert) {
|
||||
this.app.hide();
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden manually");
|
||||
this.app.show();
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown manually");
|
||||
this.app.getButton("Ok").trigger("click");
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal still visible after clicking Ok");
|
||||
this.app.getButton("Cancel").trigger("click");
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden after clicking Cancel");
|
||||
this.app.show();
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal manually shown again");
|
||||
assert.ok(!this.app.$header.hasClass("no-separator"), "Title separator tagged as visible.");
|
||||
this.app.show({ title_separator: false });
|
||||
assert.ok(this.app.$header.hasClass("no-separator"), "Title separator tagged as hidden.");
|
||||
assert.ok(this.app.$backdrop.hasClass("in"), "Backdrop tagged as shown.");
|
||||
this.app.show({ backdrop: false });
|
||||
assert.ok(!this.app.$backdrop.hasClass("in"), "Backdrop tagged as hidden.");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog closing events", function (assert) {
|
||||
this.app.show();
|
||||
this.app.$backdrop.trigger("click");
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown after backdrop click");
|
||||
this.app.hide();
|
||||
this.app.show({ closing_events: true });
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown with closing events");
|
||||
this.app.$backdrop.trigger("click");
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden after backdrop click");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog rendering", function (assert) {
|
||||
var before = this.app.$el.html();
|
||||
this.app.render();
|
||||
assert.ok(before == this.app.$el.html(), "Re-rendering successful");
|
||||
this.app.options.title = "New Title";
|
||||
this.app.render();
|
||||
assert.ok(this.app.$header.find(".title").html() == "New Title", "Modal header has correct new title.");
|
||||
});
|
||||
|
||||
QUnit.test("test button states", function (assert) {
|
||||
assert.ok(this.app.getButton("Ok").html() === "Ok", "Ok has correct label");
|
||||
assert.ok(!this.app.getButton("Ok").prop("disabled"), "Ok is active");
|
||||
assert.ok(!this.app.getButton("Cancel").prop("disabled"), "Cancel is active");
|
||||
this.app.disableButton("Ok");
|
||||
assert.ok(this.app.getButton("Ok").prop("disabled"), "Ok is disabled");
|
||||
assert.ok(!this.app.getButton("Cancel").prop("disabled"), "Cancel is still active");
|
||||
this.app.disableButton("Cancel");
|
||||
assert.ok(this.app.getButton("Cancel").prop("disabled"), "Cancel is also disabled");
|
||||
assert.ok(this.app.getButton("Ok").prop("disabled"), "Ok is still disabled");
|
||||
this.app.enableButton("Ok");
|
||||
assert.ok(this.app.getButton("Cancel").prop("disabled"), "Cancel is still disabled");
|
||||
assert.ok(!this.app.getButton("Ok").prop("disabled"), "Ok is active again");
|
||||
});
|
||||
@@ -1,896 +0,0 @@
|
||||
/* global QUnit */
|
||||
import $ from "jquery";
|
||||
import testApp from "../test-app";
|
||||
import sinon from "sinon";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import SelectContent from "mvc/ui/ui-select-content";
|
||||
import Drilldown from "mvc/ui/ui-drilldown";
|
||||
import Tabs from "mvc/ui/ui-tabs";
|
||||
|
||||
QUnit.module("Ui test", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
this.clock = sinon.useFakeTimers();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
this.clock.restore();
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("tabs", function (assert) {
|
||||
assert.ok($.fn);
|
||||
var self = this;
|
||||
var tabs = new Tabs.View({});
|
||||
var collection = tabs.collection;
|
||||
collection.add({ id: "id_a", title: "title_a", icon: "icon_a", $el: "el_a" });
|
||||
var _test = function () {
|
||||
self.clock.tick(window.WAIT_FADE);
|
||||
collection.each(function (model, index) {
|
||||
var $tab_element = tabs.$("#tab-" + model.id + " .nav-link");
|
||||
var $tab_content = tabs.$("#" + model.id);
|
||||
var is_current = model.id == tabs.model.get("current");
|
||||
assert.ok($tab_content.hasClass("active") == is_current, "Active state of content.");
|
||||
assert.ok($tab_element.hasClass("active") == is_current, "Active state of element.");
|
||||
});
|
||||
};
|
||||
$("body").prepend(tabs.$el);
|
||||
_test();
|
||||
collection.add({ id: "id_b", title: "title_b", icon: "icon_b", $el: "el_b" });
|
||||
_test();
|
||||
tabs.collection.get("id_b").set("hidden", true);
|
||||
_test();
|
||||
collection.add({ id: "id_c", title: "title_c", icon: "icon_c", $el: "el_c" });
|
||||
tabs.model.set("current", "id_c");
|
||||
_test();
|
||||
tabs.collection.get("id_b").set("hidden", false);
|
||||
_test();
|
||||
tabs.model.set("current", "id_b");
|
||||
_test();
|
||||
tabs.model.set("visible", false);
|
||||
tabs.collection.reset();
|
||||
self.clock.tick(window.WAIT_FADE);
|
||||
assert.ok(tabs.$el.css("display", "none"), "Everything hidden.");
|
||||
tabs.model.set("visible", true);
|
||||
self.clock.tick(window.WAIT_FADE);
|
||||
assert.ok(tabs.$el.css("display", "block"), "Everything shown.");
|
||||
collection.add({ id: "id_c", title: "title_c", icon: "icon_c", $el: "el_c" });
|
||||
tabs.model.set("current", "id_c");
|
||||
_test();
|
||||
});
|
||||
|
||||
QUnit.test("button-default", function (assert) {
|
||||
var button = new Ui.Button({ title: "title" });
|
||||
var model = button.model;
|
||||
$("body").prepend(button.$el);
|
||||
assert.ok(button.$title.html() == "title", "Has correct title");
|
||||
model.set("title", "_title");
|
||||
assert.ok(button.$title.html() == "_title", "Has correct new title");
|
||||
assert.ok(!button.$el.attr("disabled"), "Button active");
|
||||
model.set("disabled", true);
|
||||
assert.ok(button.$el.attr("disabled"), "Button disabled");
|
||||
model.set("disabled", false);
|
||||
assert.ok(!button.$el.attr("disabled"), "Button active, again");
|
||||
model.set("wait", true);
|
||||
assert.ok(button.$title.html() == model.get("wait_text"), "Shows correct wait text");
|
||||
model.set("wait_text", "wait_text");
|
||||
assert.ok(button.$title.html() == "wait_text", "Shows correct new wait text");
|
||||
model.set("wait", false);
|
||||
assert.ok(button.$title.html() == model.get("title"), "Shows correct regular title");
|
||||
});
|
||||
|
||||
QUnit.test("button-default", function (assert) {
|
||||
var button = new Ui.Button({ title: "title" });
|
||||
var model = button.model;
|
||||
$("body").prepend(button.$el);
|
||||
assert.ok(button.$title.html() == "title", "Has correct title");
|
||||
model.set("title", "_title");
|
||||
assert.ok(button.$title.html() == "_title", "Has correct new title");
|
||||
assert.ok(!button.$el.attr("disabled"), "Button active");
|
||||
model.set("disabled", true);
|
||||
assert.ok(button.$el.attr("disabled"), "Button disabled");
|
||||
model.set("disabled", false);
|
||||
assert.ok(!button.$el.attr("disabled"), "Button active, again");
|
||||
model.set("wait", true);
|
||||
assert.ok(button.$title.html() == model.get("wait_text"), "Shows correct wait text");
|
||||
model.set("wait_text", "wait_text");
|
||||
assert.ok(button.$title.html() == "wait_text", "Shows correct new wait text");
|
||||
model.set("wait", false);
|
||||
assert.ok(button.$title.html() == model.get("title"), "Shows correct regular title");
|
||||
});
|
||||
|
||||
QUnit.test("button-check", function (assert) {
|
||||
var button = new Ui.ButtonCheck({ title: "title" });
|
||||
var model = button.model;
|
||||
$("body").prepend(button.$el);
|
||||
assert.ok(button.$title.html() == "title", "Has correct title");
|
||||
model.set("title", "_title");
|
||||
assert.ok(button.$title.html() == "_title", "Has correct new title");
|
||||
assert.ok(button.$icon.hasClass(button.model.get("icons")[0]), "Has correct " + model.get("value") + " value");
|
||||
button.value(1);
|
||||
assert.ok(button.$icon.hasClass(button.model.get("icons")[1]), "Has correct " + model.get("value") + " value");
|
||||
button.value(2);
|
||||
assert.ok(button.$icon.hasClass(button.model.get("icons")[2]), "Has correct " + model.get("value") + " value");
|
||||
button.value(0, 100);
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[0]),
|
||||
"Has correct " + model.get("value") + " value after fraction"
|
||||
);
|
||||
button.value(10, 100);
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[1]),
|
||||
"Has correct " + model.get("value") + " value after fraction"
|
||||
);
|
||||
button.value(100, 100);
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[2]),
|
||||
"Has correct " + model.get("value") + " value after fraction"
|
||||
);
|
||||
button.$el.trigger("click");
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[0]),
|
||||
"Has correct " + model.get("value") + " value after click"
|
||||
);
|
||||
button.$el.trigger("click");
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[2]),
|
||||
"Has correct " + model.get("value") + " value after click"
|
||||
);
|
||||
button.$el.trigger("click");
|
||||
assert.ok(
|
||||
button.$icon.hasClass(button.model.get("icons")[0]),
|
||||
"Has correct " + model.get("value") + " value after click"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("options", function (assert) {
|
||||
function _test(obj, options) {
|
||||
assert.ok(JSON.stringify(obj.value()) == JSON.stringify(options.value), "Selected value is " + options.value);
|
||||
assert.ok(
|
||||
obj.$menu.css("display") == (options.menu_visible ? "block" : "none"),
|
||||
"Menu visibility: " + options.menu_visible
|
||||
);
|
||||
assert.ok(
|
||||
obj.$message.css("display") == (options.message_visible ? "block" : "none"),
|
||||
"Message visibility: " + options.message_visible
|
||||
);
|
||||
assert.ok(
|
||||
obj.$options.css("display") == (options.options_visible ? "inline-block" : "none"),
|
||||
"Options visibility: " + options.options_visible
|
||||
);
|
||||
options.message_cls &&
|
||||
assert.ok(obj.$message.hasClass(options.message_cls), "Message has class: " + options.message_cls);
|
||||
assert.ok(obj.length() === options.length, "Number of options: " + options.length);
|
||||
options.message_text &&
|
||||
assert.ok(obj.$message.html() === options.message_text, "Message text is: " + options.message_text);
|
||||
options.first && assert.ok(obj.first() === options.first, "First value is: " + options.first);
|
||||
options.all_icon &&
|
||||
assert.ok(
|
||||
obj.all_button.$(".icon").hasClass(options.all_icon),
|
||||
"All button in correct state: " + options.all_icon
|
||||
);
|
||||
assert.ok(
|
||||
obj.$menu.find(".ui-button-check").length === (options.all_icon ? 1 : 0),
|
||||
"All button available: " + Boolean(options.all_active)
|
||||
);
|
||||
}
|
||||
|
||||
var radio = new Ui.Radio.View({});
|
||||
$("body").prepend(radio.$el);
|
||||
radio.model.set("visible", false);
|
||||
assert.ok(radio.value() === null, "Initial value is `null`.");
|
||||
assert.ok(radio.$el.css("display") === "none", "Options hidden.");
|
||||
radio.model.set("visible", true);
|
||||
assert.ok(radio.$el.css("display") === "block", "Options shown.");
|
||||
radio.model.set("value", "Unavailable.");
|
||||
assert.ok(radio.value() === null, "Unavailable value ignored.");
|
||||
_test(radio, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
message_text: "No options available.",
|
||||
message_cls: "alert-danger",
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
});
|
||||
radio.model.set("wait", true);
|
||||
_test(radio, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
message_text: "Please wait...",
|
||||
message_cls: "alert-info",
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
});
|
||||
radio.model.set("wait", false);
|
||||
_test(radio, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
message_text: "No options available.",
|
||||
message_cls: "alert-danger",
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
});
|
||||
radio.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
]);
|
||||
_test(radio, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valuea",
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
});
|
||||
radio.model.set("value", "valueb");
|
||||
_test(radio, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valueb",
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
});
|
||||
radio.model.set("data", null);
|
||||
_test(radio, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
message_text: "No options available.",
|
||||
message_cls: "alert-danger",
|
||||
options_visible: false,
|
||||
value: null,
|
||||
first: null,
|
||||
length: 0,
|
||||
});
|
||||
radio.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
{ value: "valuec", label: "labelc" },
|
||||
]);
|
||||
_test(radio, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valueb",
|
||||
first: "valuea",
|
||||
length: 3,
|
||||
});
|
||||
radio.$("input").last().click();
|
||||
_test(radio, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valuec",
|
||||
first: "valuea",
|
||||
length: 3,
|
||||
});
|
||||
|
||||
var check = new Ui.Checkbox.View({});
|
||||
$("body").prepend(check.$el);
|
||||
_test(check, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
message_text: "No options available.",
|
||||
message_cls: "alert-danger",
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
check.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
{ value: "valuec", label: "labelc" },
|
||||
]);
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: null,
|
||||
length: 3,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
check.model.set("value", ["valuea", "valuec"]);
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea", "valuec"],
|
||||
length: 3,
|
||||
all_icon: "fa-minus-square-o",
|
||||
});
|
||||
check.model.set("value", ["valuea", "valueb", "valuec"]);
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea", "valueb", "valuec"],
|
||||
length: 3,
|
||||
all_icon: "fa-check-square-o",
|
||||
});
|
||||
check.model.set("data", []);
|
||||
_test(check, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
check.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
]);
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea", "valueb"],
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
all_icon: "fa-check-square-o",
|
||||
});
|
||||
check.all_button.$el.click();
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: null,
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
check.all_button.$el.click();
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea", "valueb"],
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
all_icon: "fa-check-square-o",
|
||||
});
|
||||
check.$("input").last().click();
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea"],
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
all_icon: "fa-minus-square-o",
|
||||
});
|
||||
check.$("input").last().click();
|
||||
_test(check, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuea", "valueb"],
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
all_icon: "fa-check-square-o",
|
||||
});
|
||||
|
||||
var radiobutton = new Ui.RadioButton.View({});
|
||||
$("body").prepend(radiobutton.$el);
|
||||
radiobutton.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
]);
|
||||
_test(radiobutton, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valuea",
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
});
|
||||
radiobutton.$("input").last().click();
|
||||
_test(radiobutton, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valueb",
|
||||
first: "valuea",
|
||||
length: 2,
|
||||
});
|
||||
|
||||
var drilldown = new Drilldown.View({});
|
||||
$("body").prepend(drilldown.$el);
|
||||
drilldown.model.set("data", [
|
||||
{
|
||||
value: "valuea",
|
||||
name: "labela",
|
||||
options: [
|
||||
{ value: "valueb", name: "labelb" },
|
||||
{ value: "valuec", name: "labelc" },
|
||||
{
|
||||
value: "valued",
|
||||
name: "labeld",
|
||||
options: [
|
||||
{ value: "valuee", name: "labele" },
|
||||
{ value: "valuef", name: "labelf" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "valueg",
|
||||
name: "labelg",
|
||||
options: [
|
||||
{ value: "valueh", name: "labelh" },
|
||||
{ value: "valuei", name: "labeli" },
|
||||
{
|
||||
value: "valuej",
|
||||
name: "labelj",
|
||||
options: [
|
||||
{ value: "valuek", name: "labelk" },
|
||||
{ value: "valuel", name: "labell" },
|
||||
{ value: "valuem", name: "labelm" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ value: "valuen", name: "labeln" },
|
||||
]);
|
||||
_test(drilldown, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: null,
|
||||
first: "valuea",
|
||||
length: 14,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
drilldown.model.set("value", ["valuek", "valuen"]);
|
||||
_test(drilldown, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: ["valuek", "valuen"],
|
||||
first: "valuea",
|
||||
length: 14,
|
||||
all_icon: "fa-minus-square-o",
|
||||
});
|
||||
var drillradio = new Drilldown.View({ display: "radio" });
|
||||
$("body").prepend(drillradio.$el);
|
||||
_test(drillradio, {
|
||||
menu_visible: false,
|
||||
message_visible: true,
|
||||
options_visible: false,
|
||||
value: null,
|
||||
length: 0,
|
||||
});
|
||||
drillradio.model.set("data", drilldown.model.get("data"));
|
||||
_test(drillradio, {
|
||||
menu_visible: true,
|
||||
message_visible: false,
|
||||
options_visible: true,
|
||||
value: "valuea",
|
||||
first: "valuea",
|
||||
length: 14,
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("select-default", function (assert) {
|
||||
function _test(options) {
|
||||
assert.ok(
|
||||
JSON.stringify(select.value()) == JSON.stringify(options.value),
|
||||
"Selected value is " + options.value
|
||||
);
|
||||
assert.ok(select.text() == options.label, "Selected label is " + options.label);
|
||||
assert.ok(select.$el.display === options.visible ? "block" : "none", options.visible ? "Visible" : "Hidden");
|
||||
assert.ok(select.data.length === options.count && select.length(), "Found " + options.count + " option");
|
||||
options.exists && assert.ok(select.exists(options.exists), "Found value: " + options.exists);
|
||||
assert.ok(
|
||||
select.$select.prop("multiple") === Boolean(options.multiple),
|
||||
"Multiple state set to: " + options.multiple
|
||||
);
|
||||
assert.ok(Boolean(select.all_button) === Boolean(options.multiple), "Visiblity of select all button correct.");
|
||||
options.multiple &&
|
||||
assert.ok(
|
||||
select.all_button.$(".icon").hasClass(options.all_icon),
|
||||
"All button in correct state: " + options.all_icon
|
||||
);
|
||||
}
|
||||
var select = new Ui.Select.View({});
|
||||
$("body").prepend(select.$el);
|
||||
assert.ok(select.first() === "__null__", "First select is '__null__'");
|
||||
assert.ok(select.$dropdown.hasClass("fa-caret-down"), "Caret down shown.");
|
||||
select.model.set("data", [{ value: "value", label: "label" }]);
|
||||
_test({
|
||||
value: "value",
|
||||
label: "label",
|
||||
visible: true,
|
||||
count: 1,
|
||||
});
|
||||
select.model.set("data", [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
]);
|
||||
_test({
|
||||
value: "valuea",
|
||||
label: "labela",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valueb",
|
||||
});
|
||||
select.value("valueb");
|
||||
_test({
|
||||
value: "valueb",
|
||||
label: "labelb",
|
||||
visible: true,
|
||||
count: 2,
|
||||
});
|
||||
select.model.set("data", [{ value: "value", label: "label" }]);
|
||||
_test({
|
||||
value: "value",
|
||||
label: "label",
|
||||
visible: true,
|
||||
count: 1,
|
||||
});
|
||||
select.model.set({ visible: false, value: "unavailable" });
|
||||
_test({
|
||||
value: "value",
|
||||
label: "label",
|
||||
visible: false,
|
||||
count: 1,
|
||||
});
|
||||
select.model.set({
|
||||
visible: true,
|
||||
value: "valueb",
|
||||
data: [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
],
|
||||
});
|
||||
_test({
|
||||
value: "valueb",
|
||||
label: "labelb",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valuea",
|
||||
});
|
||||
select.model.set({ multiple: true });
|
||||
_test({
|
||||
value: ["valueb"],
|
||||
label: "labelb",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valuea",
|
||||
multiple: true,
|
||||
all_icon: "fa-minus-square-o",
|
||||
});
|
||||
select.model.set("value", ["valueb", "valuea"]);
|
||||
_test({
|
||||
value: ["valuea", "valueb"],
|
||||
label: "labela",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valueb",
|
||||
multiple: true,
|
||||
all_icon: "fa-check-square-o",
|
||||
});
|
||||
select.model.set("value", []);
|
||||
_test({
|
||||
value: null,
|
||||
label: "",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valuea",
|
||||
multiple: true,
|
||||
all_icon: "fa-square-o",
|
||||
});
|
||||
select.model.set({ multiple: false });
|
||||
_test({
|
||||
value: "valuea",
|
||||
label: "labela",
|
||||
visible: true,
|
||||
count: 2,
|
||||
exists: "valuea",
|
||||
});
|
||||
select.model.set({ visible: false });
|
||||
_test({
|
||||
value: "valuea",
|
||||
label: "labela",
|
||||
visible: false,
|
||||
count: 2,
|
||||
exists: "valuea",
|
||||
});
|
||||
select.model.set({
|
||||
multiple: true,
|
||||
visible: true,
|
||||
value: ["valueb", "valuec"],
|
||||
data: [
|
||||
{ value: "valuea", label: "labela" },
|
||||
{ value: "valueb", label: "labelb" },
|
||||
{ value: "valuec", label: "labelc" },
|
||||
],
|
||||
});
|
||||
_test({
|
||||
value: ["valueb", "valuec"],
|
||||
label: "labelb",
|
||||
visible: true,
|
||||
count: 3,
|
||||
exists: "valuea",
|
||||
multiple: true,
|
||||
all_icon: "fa-minus-square-o",
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("input", function (assert) {
|
||||
var input = new Ui.Input();
|
||||
$("body").prepend(input.$el);
|
||||
assert.ok(input.tagName === "input", "Created input.");
|
||||
assert.ok(input.value() === undefined, "Input empty.");
|
||||
input.model.set("value", "_value");
|
||||
assert.ok(input.$el.val() === "_value", "Input with value.");
|
||||
assert.ok(!input.$el.hasClass("_cls"), "Has no custom class.");
|
||||
input.model.set("cls", "_cls");
|
||||
assert.ok(input.$el.hasClass("_cls"), "Has custom class.");
|
||||
assert.ok(!input.$el.attr("placeholder"), "Has no placeholder");
|
||||
input.model.set("placeholder", "_placeholder");
|
||||
assert.ok(input.$el.attr("placeholder") === "_placeholder", "Has correct placeholder");
|
||||
input.model.set("disabled", true);
|
||||
assert.ok(input.$el.attr("disabled"), "Disabled");
|
||||
input.model.set("disabled", false);
|
||||
assert.ok(!input.$el.attr("disabled"), "Enabled");
|
||||
input.model.set("visible", false);
|
||||
assert.ok(input.$el.css("display") === "none", "Hidden");
|
||||
input.model.set("visible", true);
|
||||
assert.ok(input.$el.css("display") === "inline-block", "Shown");
|
||||
});
|
||||
|
||||
QUnit.test("textarea", function (assert) {
|
||||
var input = new Ui.Input({ area: true });
|
||||
$("body").prepend(input.$el);
|
||||
assert.ok(input.tagName === "textarea", "Created textarea.");
|
||||
assert.ok(input.value() === undefined, "Unavailable value.");
|
||||
input.model.set("value", "_value");
|
||||
assert.ok(input.value() === "_value", "Correct new value.");
|
||||
assert.ok(!input.$el.hasClass("_cls"), "Has no custom class.");
|
||||
input.model.set("cls", "_cls");
|
||||
assert.ok(input.$el.hasClass("_cls"), "Has custom class.");
|
||||
});
|
||||
|
||||
QUnit.test("nullableText", function (assert) {
|
||||
// Start with null value, optional button should be off
|
||||
var input = new Ui.NullableText({ area: false, value: null });
|
||||
$("body").prepend(input.$el);
|
||||
assert.ok(input.text_input.tagName === "input", "input tag");
|
||||
assert.ok(input.value() === null, "null value");
|
||||
assert.ok(input.optional_button.model.get("value") === "false");
|
||||
// toggle button, will set value to `""`
|
||||
input.optional_button.model.set("value", "true");
|
||||
assert.ok(input.value() === "", "Correct new value.");
|
||||
// set value
|
||||
input.text_input.model.set("value", "_value");
|
||||
assert.ok(input.value() === "_value", "Correct new value.");
|
||||
assert.ok(input.optional_button.model.get("value") === "true");
|
||||
// toggle button to false, will reset value to null
|
||||
input.optional_button.model.set("value", "false");
|
||||
assert.ok(input.value() === null, "Correct new value.");
|
||||
assert.ok(input.optional_button.model.get("value") === "false");
|
||||
// New input, start with value, optional button should be on
|
||||
var definedInput = new Ui.NullableText({ area: false, value: "123" });
|
||||
assert.ok(definedInput.value() === "123");
|
||||
assert.ok(definedInput.optional_button.model.get("value") === "true");
|
||||
});
|
||||
|
||||
QUnit.test("message", function (assert) {
|
||||
var message = new Ui.Message({
|
||||
persistent: true,
|
||||
message: "_message",
|
||||
status: "danger",
|
||||
});
|
||||
$("body").prepend(message.$el);
|
||||
assert.ok(message.$el.hasClass("alert-danger"), "Alert danger.");
|
||||
message.model.set("status", "info");
|
||||
assert.ok(!message.$el.hasClass("alert-danger"), "Alert danger (disabled).");
|
||||
assert.ok(message.$el.hasClass("alert-info"), "Alert info.");
|
||||
assert.ok(message.$el.html() === "_message", "Correct message.");
|
||||
message.model.set("message", "_new_message");
|
||||
assert.ok(message.$el.html() === "_new_message", "Correct new message.");
|
||||
});
|
||||
|
||||
QUnit.test("select-content", function (assert) {
|
||||
var select = new SelectContent.View({});
|
||||
$("body").prepend(select.$el);
|
||||
var _testSelect = function (tag, options) {
|
||||
var field = select.fields[tag == "first" ? 0 : select.fields.length - 1];
|
||||
var $select = select.$(".ui-select:" + tag);
|
||||
var $button = select.$(".ui-radiobutton").find("label:" + tag);
|
||||
assert.ok(field.length() == options[tag + "length"], tag + " one has " + options[tag + "length"] + " options");
|
||||
assert.ok(field.data[0].value == options[tag + "value"], tag + " option has correct value");
|
||||
assert.ok(field.data[0].label == options[tag + "label"], tag + " option has correct label");
|
||||
assert.ok($select.hasClass("ui-select-multiple") == options[tag + "multiple"], "Check multiple option");
|
||||
$button.trigger("mouseover");
|
||||
var tooltip = $(".tooltip-inner:last").text();
|
||||
$button.trigger("mouseleave");
|
||||
assert.ok(tooltip.indexOf("dataset") != -1 || tooltip.indexOf("collection") != -1, "Basic tooltip check");
|
||||
};
|
||||
var _test = function (options) {
|
||||
assert.ok(select.button_type.$(".ui-option:first").hasClass("active"), "First one is toggled");
|
||||
assert.ok(
|
||||
select.$(".ui-select").length == options.selectfields,
|
||||
"Found " + options.selectfields + " select fields"
|
||||
);
|
||||
assert.ok(
|
||||
select.button_type.$(".ui-option").length == options.selectfields,
|
||||
"Found " + options.selectfields + " radio button options"
|
||||
);
|
||||
assert.ok(
|
||||
select.$(".ui-select-multiple").length == options.totalmultiple,
|
||||
"Contains " + options.totalmultiple + " multiselect fields"
|
||||
);
|
||||
assert.ok(
|
||||
select.$el.find(".ui-options:first .ui-option").length === options.selectfields,
|
||||
"Radio button count, expected " + options.selectfields
|
||||
);
|
||||
assert.ok(select.$(".ui-select:first").css("display") == "block", "Check select visibility");
|
||||
assert.ok(
|
||||
select.$(".ui-select:last").css("display") == (options.selectfields == 1 ? "block" : "none"),
|
||||
"Last select visibility"
|
||||
);
|
||||
assert.ok(
|
||||
(select.button_dialog.$el.css("display") != "none") === options.showdialog,
|
||||
"Data dialog button visible"
|
||||
);
|
||||
_testSelect("first", options);
|
||||
_testSelect("last", options);
|
||||
};
|
||||
|
||||
assert.ok(select.button_type.value() == 0, "Initial mode selected by default.");
|
||||
select.model.set("data", {
|
||||
hda: [
|
||||
{ id: "id0", name: "name0", hid: "hid0" },
|
||||
{ id: "id1", name: "name1", hid: "hid1" },
|
||||
],
|
||||
hdca: [
|
||||
{ id: "id2", name: "name2", hid: "hid2" },
|
||||
{ id: "id3", name: "name3", hid: "hid3" },
|
||||
{ id: "id4", name: "name4", hid: "hid4" },
|
||||
],
|
||||
});
|
||||
|
||||
var initial = {
|
||||
selectfields: 3,
|
||||
firstlength: 2,
|
||||
firstvalue: "id0",
|
||||
firstlabel: "hid0: name0",
|
||||
firstmultiple: false,
|
||||
totalmultiple: 1,
|
||||
lastvalue: "id2",
|
||||
lastlabel: "hid2: name2",
|
||||
lastlength: 3,
|
||||
lastmultiple: false,
|
||||
showdialog: true,
|
||||
};
|
||||
_test(initial);
|
||||
|
||||
select.model.set("multiple", true);
|
||||
select.model.set("type", "data");
|
||||
_test({
|
||||
selectfields: 2,
|
||||
firstlength: 2,
|
||||
firstvalue: "id0",
|
||||
firstlabel: "hid0: name0",
|
||||
firstmultiple: true,
|
||||
totalmultiple: 2,
|
||||
lastvalue: "id2",
|
||||
lastlabel: "hid2: name2",
|
||||
lastlength: 3,
|
||||
lastmultiple: true,
|
||||
showdialog: true,
|
||||
});
|
||||
|
||||
select.model.set("multiple", false);
|
||||
select.model.set("type", "data_collection");
|
||||
_test({
|
||||
selectfields: 1,
|
||||
firstlength: 3,
|
||||
firstvalue: "id2",
|
||||
firstlabel: "hid2: name2",
|
||||
firstmultiple: false,
|
||||
totalmultiple: 0,
|
||||
lastvalue: "id2",
|
||||
lastlabel: "hid2: name2",
|
||||
lastlength: 3,
|
||||
lastmultiple: false,
|
||||
showdialog: false,
|
||||
});
|
||||
|
||||
select.model.set("type", "module_data_collection");
|
||||
_test({
|
||||
selectfields: 2,
|
||||
firstlength: 3,
|
||||
firstvalue: "id2",
|
||||
firstlabel: "hid2: name2",
|
||||
firstmultiple: false,
|
||||
totalmultiple: 1,
|
||||
lastvalue: "id2",
|
||||
lastlabel: "hid2: name2",
|
||||
lastlength: 3,
|
||||
lastmultiple: true,
|
||||
showdialog: false,
|
||||
});
|
||||
|
||||
select.model.set("type", "module_data");
|
||||
_test({
|
||||
selectfields: 2,
|
||||
firstlength: 2,
|
||||
firstvalue: "id0",
|
||||
firstlabel: "hid0: name0",
|
||||
firstmultiple: false,
|
||||
totalmultiple: 1,
|
||||
lastvalue: "id0",
|
||||
lastlabel: "hid0: name0",
|
||||
lastlength: 2,
|
||||
lastmultiple: true,
|
||||
showdialog: true,
|
||||
});
|
||||
|
||||
select.model.set("type", "data");
|
||||
_test(initial);
|
||||
|
||||
select.model.set("wait", true);
|
||||
assert.ok(select.$(".icon-dropdown").hasClass("fa-spinner"), "Shows spinner");
|
||||
select.model.set("wait", false);
|
||||
assert.ok(select.$(".icon-dropdown").hasClass("fa-caret-down"), "Shows caret");
|
||||
select.model.set("optional", true);
|
||||
assert.ok(select.fields[0].data[0].value == "__null__", "First option is optional value");
|
||||
select.model.set("optional", false);
|
||||
assert.ok(select.fields[0].data[0].value != "__null__", "First option is not optional value");
|
||||
|
||||
select.model.set("value", { values: [{ id: "id1", src: "hda" }] });
|
||||
assert.ok(
|
||||
JSON.stringify(select.value()) == '{"values":[{"id":"id1","name":"name1","hid":"hid1"}],"batch":false}',
|
||||
"Checking single value"
|
||||
);
|
||||
|
||||
assert.ok(select.config[select.model.get("current")].src == "hda", "Matched dataset field");
|
||||
assert.ok(!select.config[select.model.get("current")].multiple, "Matched single select field");
|
||||
select.model.set("value", {
|
||||
values: [
|
||||
{ id: "id0", src: "hda" },
|
||||
{ id: "id1", src: "hda" },
|
||||
],
|
||||
});
|
||||
assert.ok(select.config[select.model.get("current")].multiple, "Matched multiple field");
|
||||
assert.ok(
|
||||
JSON.stringify(select.value()) ==
|
||||
'{"values":[{"id":"id0","name":"name0","hid":"hid0"},{"id":"id1","name":"name1","hid":"hid1"}],"batch":true}',
|
||||
"Checking multiple values"
|
||||
);
|
||||
select.model.set("value", { values: [{ id: "id2", src: "hdca" }] });
|
||||
assert.ok(select.config[select.model.get("current")].src == "hdca", "Matched collection field");
|
||||
assert.ok(
|
||||
JSON.stringify(select.value()) == '{"values":[{"id":"id2","name":"name2","hid":"hid2"}],"batch":true}',
|
||||
"Checking collection value"
|
||||
);
|
||||
|
||||
select = new SelectContent.View({});
|
||||
$("body").prepend(select.$el);
|
||||
var _testEmptySelect = function (tag, txt_extension, txt_label) {
|
||||
var field = select.fields[tag == "first" ? 0 : select.fields.length - 1];
|
||||
select.$(".ui-select:" + tag);
|
||||
assert.ok(field.data[0].value == "__null__", tag + " option has correct empty value.");
|
||||
assert.ok(
|
||||
field.data[0].label == "No " + txt_extension + txt_label + " available.",
|
||||
tag + " option has correct empty label."
|
||||
);
|
||||
};
|
||||
|
||||
var labels = select.model.get("src_labels");
|
||||
_testEmptySelect("first", "", labels.hda);
|
||||
_testEmptySelect("last", "", labels.hdca);
|
||||
select.model.set("extensions", ["txt", "bam"]);
|
||||
_testEmptySelect("first", "txt or bam ", labels.hda);
|
||||
_testEmptySelect("last", "txt or bam ", labels.hdca);
|
||||
select.model.set("extensions", ["txt"]);
|
||||
_testEmptySelect("first", "txt ", labels.hda);
|
||||
_testEmptySelect("last", "txt ", labels.hdca);
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
/* global QUnit */
|
||||
import testApp from "../test-app";
|
||||
import Utils from "utils/utils";
|
||||
|
||||
QUnit.module("Utils test", {
|
||||
beforeEach: function () {
|
||||
testApp.create();
|
||||
},
|
||||
afterEach: function () {
|
||||
testApp.destroy();
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("isEmpty", function (assert) {
|
||||
assert.ok(Utils.isEmpty([]), "Empty array");
|
||||
assert.ok(Utils.isEmpty(["data", undefined]), "Array contains `undefined`");
|
||||
assert.ok(Utils.isEmpty(["data", null]), "Array contains `null`");
|
||||
assert.ok(Utils.isEmpty(["data", "__null__"]), "Array contains `__null__`");
|
||||
assert.ok(Utils.isEmpty(["data", "__undefined__"]), "Array contains `__undefined__`");
|
||||
assert.ok(Utils.isEmpty(null), "Array is null");
|
||||
assert.ok(Utils.isEmpty("__null__"), "Array is __null__");
|
||||
assert.ok(Utils.isEmpty("__undefined__"), "Array is __undefined__");
|
||||
assert.ok(!Utils.isEmpty(["data"]), "Array contains `data`");
|
||||
assert.ok(!Utils.isEmpty(1), "Value is int");
|
||||
assert.ok(!Utils.isEmpty(0), "Value is zero");
|
||||
});
|
||||
@@ -7,6 +7,7 @@ const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
||||
const DuplicatePackageCheckerPlugin = require("@cerner/duplicate-package-checker-webpack-plugin");
|
||||
const { DumpMetaPlugin } = require("dumpmeta-webpack-plugin");
|
||||
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
|
||||
const scriptsBase = path.join(__dirname, "src");
|
||||
const testsBase = path.join(__dirname, "tests");
|
||||
@@ -32,6 +33,27 @@ module.exports = (env = {}, argv = {}) => {
|
||||
// environment name based on -d, -p, webpack flag
|
||||
const targetEnv = process.env.NODE_ENV == "production" || argv.mode == "production" ? "production" : "development";
|
||||
|
||||
let minimizations = {};
|
||||
if (targetEnv == "production") {
|
||||
minimizations = {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
};
|
||||
} else {
|
||||
minimizations = {
|
||||
minimize: false,
|
||||
};
|
||||
}
|
||||
|
||||
const buildconfig = {
|
||||
mode: targetEnv,
|
||||
entry: {
|
||||
@@ -84,8 +106,7 @@ module.exports = (env = {}, argv = {}) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
minimize: true,
|
||||
minimizer: [`...`, new CssMinimizerPlugin()],
|
||||
...minimizations,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
@@ -272,8 +293,8 @@ module.exports = (env = {}, argv = {}) => {
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.GXY_BUILD_SOURCEMAPS || buildconfig.mode == "development") {
|
||||
buildconfig.devtool = "eval-cheap-source-map";
|
||||
if (process.env.GXY_BUILD_SOURCEMAPS) {
|
||||
buildconfig.devtool = "source-map";
|
||||
}
|
||||
|
||||
return buildconfig;
|
||||
|
||||
+18
-380
@@ -1405,11 +1405,6 @@
|
||||
"@citation-js/name" "^0.4.2"
|
||||
wikidata-sdk "^8.0.0"
|
||||
|
||||
"@colors/colors@1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@discoveryjs/json-ext@^0.5.0":
|
||||
version "0.5.7"
|
||||
resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz"
|
||||
@@ -2023,11 +2018,6 @@
|
||||
resolved "https://registry.npmjs.org/@types/circular-json/-/circular-json-0.4.0.tgz"
|
||||
integrity sha512-7+kYB7x5a7nFWW1YPBh3KxhwKfiaI4PbZ1RvzBU91LZy7lWJO822CI+pqzSre/DZ7KsCuMKdHnLHHFu8AyXbQg==
|
||||
|
||||
"@types/component-emitter@^1.2.10":
|
||||
version "1.2.11"
|
||||
resolved "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz"
|
||||
integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==
|
||||
|
||||
"@types/connect-history-api-fallback@^1.3.5":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz"
|
||||
@@ -2043,16 +2033,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookie@^0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz"
|
||||
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
|
||||
|
||||
"@types/cors@^2.8.12":
|
||||
version "2.8.12"
|
||||
resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz"
|
||||
integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==
|
||||
|
||||
"@types/d3-array@*":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.3.tgz#87d990bf504d14ad6b16766979d04e943c046dac"
|
||||
@@ -2378,7 +2358,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
|
||||
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
|
||||
|
||||
"@types/node@*", "@types/node@>=10.0.0":
|
||||
"@types/node@*":
|
||||
version "18.6.5"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz"
|
||||
integrity sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==
|
||||
@@ -3356,11 +3336,6 @@ base64-js@^1.3.1:
|
||||
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
base64id@2.0.0, base64id@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz"
|
||||
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz"
|
||||
@@ -3408,7 +3383,7 @@ bluebird@^3.1.1:
|
||||
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
body-parser@1.20.0, body-parser@^1.19.0:
|
||||
body-parser@1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz"
|
||||
integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==
|
||||
@@ -3645,15 +3620,10 @@ caniuse-api@^3.0.0:
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001304, caniuse-lite@^1.0.30001370:
|
||||
version "1.0.30001375"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001375.tgz"
|
||||
integrity sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==
|
||||
|
||||
caniuse-lite@^1.0.30001400:
|
||||
version "1.0.30001439"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb"
|
||||
integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001304, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001400:
|
||||
version "1.0.30001450"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz"
|
||||
integrity sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==
|
||||
|
||||
caniuse-lite@^1.0.30001426:
|
||||
version "1.0.30001451"
|
||||
@@ -3709,7 +3679,7 @@ char-regex@^1.0.2:
|
||||
resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
|
||||
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
||||
|
||||
chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^2.0.0, chokidar@^3.5.1, chokidar@^3.5.3:
|
||||
chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^2.0.0, chokidar@^3.5.3:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
@@ -3797,15 +3767,6 @@ cliui@^3.2.0:
|
||||
strip-ansi "^3.0.1"
|
||||
wrap-ansi "^2.0.0"
|
||||
|
||||
cliui@^7.0.2:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz"
|
||||
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
|
||||
dependencies:
|
||||
string-width "^4.2.0"
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
cliui@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
|
||||
@@ -3946,7 +3907,7 @@ combined-stream@^1.0.8:
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@7, commander@7.2.0, commander@^7.2.0:
|
||||
commander@7, commander@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
|
||||
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
|
||||
@@ -3966,7 +3927,7 @@ commander@^9.4.1:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
|
||||
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
|
||||
|
||||
component-emitter@^1.2.1, component-emitter@~1.3.0:
|
||||
component-emitter@^1.2.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
@@ -4028,16 +3989,6 @@ connect-history-api-fallback@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz"
|
||||
integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
|
||||
|
||||
connect@^3.7.0:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz"
|
||||
integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
finalhandler "1.1.2"
|
||||
parseurl "~1.3.3"
|
||||
utils-merge "1.0.1"
|
||||
|
||||
consola@^2.15.0:
|
||||
version "2.15.3"
|
||||
resolved "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz"
|
||||
@@ -4084,11 +4035,6 @@ cookie@0.5.0:
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
cookie@~0.4.1:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz"
|
||||
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
||||
|
||||
copy-descriptor@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz"
|
||||
@@ -4129,14 +4075,6 @@ core-util-is@~1.0.0:
|
||||
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz"
|
||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
||||
|
||||
cors@~2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cosmiconfig@^7.0.0:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz"
|
||||
@@ -4357,11 +4295,6 @@ custom-error-instance@2.1.1:
|
||||
resolved "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz"
|
||||
integrity sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==
|
||||
|
||||
custom-event@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz"
|
||||
integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==
|
||||
|
||||
"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.1.tgz#39331ea706f5709417d31bbb6ec152e0328b39b3"
|
||||
@@ -4638,11 +4571,6 @@ date-fns@^2.28.0:
|
||||
resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz"
|
||||
integrity sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==
|
||||
|
||||
date-format@^4.0.13:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.npmjs.org/date-format/-/date-format-4.0.13.tgz"
|
||||
integrity sha512-bnYCwf8Emc3pTD8pXnre+wfnjGtfi5ncMDKy7+cWZXbmRAsdWkOQHrfC1yz/KiwP5thDp2kCHWYWKBX4HP1hoQ==
|
||||
|
||||
de-indent@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz"
|
||||
@@ -4655,7 +4583,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
|
||||
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
@@ -4841,11 +4769,6 @@ detect-node@^2.0.4:
|
||||
resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz"
|
||||
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
||||
|
||||
di@^0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/di/-/di-0.0.1.tgz"
|
||||
integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==
|
||||
|
||||
diff-sequences@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz"
|
||||
@@ -4902,16 +4825,6 @@ dom-event-types@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.1.0.tgz"
|
||||
integrity sha512-jNCX+uNJ3v38BKvPbpki6j5ItVlnSqVV6vDWGS6rExzCMjsc39frLjm1n91o6YaKK6AZl0wLloItW6C6mr61BQ==
|
||||
|
||||
dom-serialize@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz"
|
||||
integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==
|
||||
dependencies:
|
||||
custom-event "~1.0.0"
|
||||
ent "~2.2.0"
|
||||
extend "^3.0.0"
|
||||
void-elements "^2.0.0"
|
||||
|
||||
dom-serializer@^1.0.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz"
|
||||
@@ -5054,27 +4967,6 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
engine.io-parser@~5.0.3:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz"
|
||||
integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==
|
||||
|
||||
engine.io@~6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz"
|
||||
integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==
|
||||
dependencies:
|
||||
"@types/cookie" "^0.4.1"
|
||||
"@types/cors" "^2.8.12"
|
||||
"@types/node" ">=10.0.0"
|
||||
accepts "~1.3.4"
|
||||
base64id "2.0.0"
|
||||
cookie "~0.4.1"
|
||||
cors "~2.8.5"
|
||||
debug "~4.3.1"
|
||||
engine.io-parser "~5.0.3"
|
||||
ws "~8.2.3"
|
||||
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz"
|
||||
@@ -5091,11 +4983,6 @@ enhanced-resolve@^5.7.0:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.2.0"
|
||||
|
||||
ent@~2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz"
|
||||
integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==
|
||||
|
||||
entities@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
|
||||
@@ -5704,19 +5591,6 @@ fill-range@^7.0.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
finalhandler@1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz"
|
||||
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
on-finished "~2.3.0"
|
||||
parseurl "~1.3.3"
|
||||
statuses "~1.5.0"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
finalhandler@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz"
|
||||
@@ -5808,7 +5682,7 @@ flatted@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz"
|
||||
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
|
||||
|
||||
flatted@^3.1.0, flatted@^3.2.6:
|
||||
flatted@^3.1.0:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz"
|
||||
integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
|
||||
@@ -5881,15 +5755,6 @@ fresh@0.5.2:
|
||||
resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
|
||||
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
|
||||
|
||||
fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz"
|
||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-mkdirp-stream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz"
|
||||
@@ -6045,7 +5910,7 @@ glob-watcher@^5.0.3:
|
||||
normalize-path "^3.0.0"
|
||||
object.defaults "^1.1.0"
|
||||
|
||||
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.7, glob@^7.2.0, glob@~7.2.0:
|
||||
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0, glob@~7.2.0:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
@@ -6100,11 +5965,6 @@ globals@^13.15.0:
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globalyzer@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz"
|
||||
integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==
|
||||
|
||||
globby@^11.0.1, globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
|
||||
@@ -6128,11 +5988,6 @@ globby@^13.1.1:
|
||||
merge2 "^1.4.1"
|
||||
slash "^4.0.0"
|
||||
|
||||
globrex@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz"
|
||||
integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==
|
||||
|
||||
glogg@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz"
|
||||
@@ -6147,7 +6002,7 @@ gopd@^1.0.1:
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
|
||||
graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
|
||||
version "4.2.10"
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz"
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
@@ -6987,11 +6842,6 @@ isarray@^2.0.5:
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
|
||||
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
|
||||
|
||||
isbinaryfile@^4.0.8:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz"
|
||||
integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
|
||||
@@ -7639,13 +7489,6 @@ json5@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz"
|
||||
integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jspdf@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz"
|
||||
@@ -7676,62 +7519,6 @@ just-extend@^4.0.2:
|
||||
resolved "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz"
|
||||
integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==
|
||||
|
||||
karma-chrome-launcher@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz"
|
||||
integrity sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==
|
||||
dependencies:
|
||||
which "^1.2.1"
|
||||
|
||||
karma-polyfill@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/karma-polyfill/-/karma-polyfill-1.1.0.tgz"
|
||||
integrity sha512-TGWOIeTa4VBU2Af6jp4IYbROlTH6EXqpQZt15r0TRv7AYMt03BIagj5eljZgC64Uqg11QDh09j9megr6Vmzm6g==
|
||||
|
||||
karma-qunit@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/karma-qunit/-/karma-qunit-4.1.2.tgz"
|
||||
integrity sha512-taTPqBeHCOlkeKTSzQgIKzAUb79vw3rfbCph+xwwh63tyGjNtljwx91VArhIM9DzIIR3gB9G214wQg+oXI9ycw==
|
||||
|
||||
karma-webpack@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/karma-webpack/-/karma-webpack-5.0.0.tgz"
|
||||
integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
minimatch "^3.0.4"
|
||||
webpack-merge "^4.1.5"
|
||||
|
||||
karma@^6.3.16:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.npmjs.org/karma/-/karma-6.4.0.tgz"
|
||||
integrity sha512-s8m7z0IF5g/bS5ONT7wsOavhW4i4aFkzD4u4wgzAQWT4HGUeWI3i21cK2Yz6jndMAeHETp5XuNsRoyGJZXVd4w==
|
||||
dependencies:
|
||||
"@colors/colors" "1.5.0"
|
||||
body-parser "^1.19.0"
|
||||
braces "^3.0.2"
|
||||
chokidar "^3.5.1"
|
||||
connect "^3.7.0"
|
||||
di "^0.0.1"
|
||||
dom-serialize "^2.2.1"
|
||||
glob "^7.1.7"
|
||||
graceful-fs "^4.2.6"
|
||||
http-proxy "^1.18.1"
|
||||
isbinaryfile "^4.0.8"
|
||||
lodash "^4.17.21"
|
||||
log4js "^6.4.1"
|
||||
mime "^2.5.2"
|
||||
minimatch "^3.0.4"
|
||||
mkdirp "^0.5.5"
|
||||
qjobs "^1.2.0"
|
||||
range-parser "^1.2.1"
|
||||
rimraf "^3.0.2"
|
||||
socket.io "^4.4.1"
|
||||
source-map "^0.6.1"
|
||||
tmp "^0.2.1"
|
||||
ua-parser-js "^0.7.30"
|
||||
yargs "^16.1.1"
|
||||
|
||||
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
|
||||
@@ -8009,17 +7796,6 @@ lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21:
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
log4js@^6.4.1:
|
||||
version "6.6.1"
|
||||
resolved "https://registry.npmjs.org/log4js/-/log4js-6.6.1.tgz"
|
||||
integrity sha512-J8VYFH2UQq/xucdNu71io4Fo+purYYudyErgBbswWKO0MC6QVOERRomt5su/z6d3RJSmLyTGmXl3Q/XjKCf+/A==
|
||||
dependencies:
|
||||
date-format "^4.0.13"
|
||||
debug "^4.3.4"
|
||||
flatted "^3.2.6"
|
||||
rfdc "^1.3.0"
|
||||
streamroller "^3.1.2"
|
||||
|
||||
lower-case@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz"
|
||||
@@ -8239,11 +8015,6 @@ mime@1.6.0:
|
||||
resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
mime@^2.5.2:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz"
|
||||
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
|
||||
@@ -8302,13 +8073,6 @@ mixin-deep@^1.2.0:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mkdirp@^0.5.5:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz"
|
||||
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
|
||||
dependencies:
|
||||
minimist "^1.2.6"
|
||||
|
||||
moment@2.20.1:
|
||||
version "2.20.1"
|
||||
resolved "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz"
|
||||
@@ -8445,11 +8209,6 @@ node-releases@^2.0.6:
|
||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz"
|
||||
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
|
||||
|
||||
node-watch@0.7.3:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz"
|
||||
integrity sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==
|
||||
|
||||
nopt@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz"
|
||||
@@ -8537,11 +8296,6 @@ nwsapi@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0"
|
||||
integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==
|
||||
|
||||
object-assign@^4:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
object-copy@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz"
|
||||
@@ -8646,13 +8400,6 @@ on-finished@2.4.1:
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
on-finished@~2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
|
||||
integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
on-headers@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz"
|
||||
@@ -9452,11 +9199,6 @@ pyre-to-regexp@^0.0.5:
|
||||
resolved "https://registry.npmjs.org/pyre-to-regexp/-/pyre-to-regexp-0.0.5.tgz"
|
||||
integrity sha512-AYoI8bSYhCbElpcj/Z7FyP0rrpuuw96GAYCqdrX3fDH+vRXh8lXWeRRZtyJgRO4LgBlb5fK2o2odkaoSGQ6gIQ==
|
||||
|
||||
qjobs@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz"
|
||||
integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==
|
||||
|
||||
qs@6.10.3:
|
||||
version "6.10.3"
|
||||
resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz"
|
||||
@@ -9484,15 +9226,6 @@ quick-lru@^5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||
|
||||
qunit@^2.17.2:
|
||||
version "2.19.1"
|
||||
resolved "https://registry.npmjs.org/qunit/-/qunit-2.19.1.tgz"
|
||||
integrity sha512-gSGuw0vErE/rNjnlBW/JmE7NNubBlGrDPQvsug32ejYhcVFuZec9yoU0+C30+UgeCGwq6Ap89K65dMGo+kDGZQ==
|
||||
dependencies:
|
||||
commander "7.2.0"
|
||||
node-watch "0.7.3"
|
||||
tiny-glob "0.2.9"
|
||||
|
||||
raf@^3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"
|
||||
@@ -9883,17 +9616,12 @@ reusify@^1.0.4:
|
||||
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
rfdc@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz"
|
||||
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
|
||||
|
||||
rgbcolor@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz"
|
||||
integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==
|
||||
|
||||
rimraf@^3.0.0, rimraf@^3.0.2:
|
||||
rimraf@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
@@ -10278,32 +10006,6 @@ snapdragon@^0.8.1:
|
||||
source-map-resolve "^0.5.0"
|
||||
use "^3.1.0"
|
||||
|
||||
socket.io-adapter@~2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz"
|
||||
integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==
|
||||
|
||||
socket.io-parser@~4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz"
|
||||
integrity sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==
|
||||
dependencies:
|
||||
"@types/component-emitter" "^1.2.10"
|
||||
component-emitter "~1.3.0"
|
||||
debug "~4.3.1"
|
||||
|
||||
socket.io@^4.4.1:
|
||||
version "4.5.1"
|
||||
resolved "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz"
|
||||
integrity sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==
|
||||
dependencies:
|
||||
accepts "~1.3.4"
|
||||
base64id "~2.0.0"
|
||||
debug "~4.3.2"
|
||||
engine.io "~6.2.0"
|
||||
socket.io-adapter "~2.4.0"
|
||||
socket.io-parser "~4.0.4"
|
||||
|
||||
sockjs@^0.3.24:
|
||||
version "0.3.24"
|
||||
resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz"
|
||||
@@ -10489,7 +10191,7 @@ statuses@2.0.1:
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
"statuses@>= 1.4.0 < 2", statuses@~1.5.0:
|
||||
"statuses@>= 1.4.0 < 2":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
|
||||
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
|
||||
@@ -10517,15 +10219,6 @@ stream-shift@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz"
|
||||
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
|
||||
|
||||
streamroller@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/streamroller/-/streamroller-3.1.2.tgz"
|
||||
integrity sha512-wZswqzbgGGsXYIrBYhOE0yP+nQ6XRk7xDcYwuQAGTYXdyAUmvgVFE0YU1g5pvQT0m7GBaQfYcSnlHbapuK0H0A==
|
||||
dependencies:
|
||||
date-format "^4.0.13"
|
||||
debug "^4.3.4"
|
||||
fs-extra "^8.1.0"
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
@@ -10817,21 +10510,6 @@ timers-browserify@^2.0.12:
|
||||
dependencies:
|
||||
setimmediate "^1.0.4"
|
||||
|
||||
tiny-glob@0.2.9:
|
||||
version "0.2.9"
|
||||
resolved "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz"
|
||||
integrity sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==
|
||||
dependencies:
|
||||
globalyzer "0.1.0"
|
||||
globrex "^0.1.2"
|
||||
|
||||
tmp@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz"
|
||||
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
|
||||
dependencies:
|
||||
rimraf "^3.0.0"
|
||||
|
||||
tmpl@1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
|
||||
@@ -11077,11 +10755,6 @@ typescript@^4.9.5:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
|
||||
ua-parser-js@^0.7.30:
|
||||
version "0.7.33"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"
|
||||
integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==
|
||||
|
||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz"
|
||||
@@ -11181,11 +10854,6 @@ unique-stream@^2.0.2:
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
through2-filter "^3.0.0"
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
|
||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||
|
||||
universalify@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
|
||||
@@ -11308,7 +10976,7 @@ value-or-function@^3.0.0:
|
||||
resolved "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz"
|
||||
integrity sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
@@ -11361,11 +11029,6 @@ vinyl@^2.0.0:
|
||||
remove-trailing-separator "^1.0.1"
|
||||
replace-ext "^1.0.0"
|
||||
|
||||
void-elements@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz"
|
||||
integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==
|
||||
|
||||
vue-demi@*:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
|
||||
@@ -11611,13 +11274,6 @@ webpack-dev-server@^4.11.1:
|
||||
webpack-dev-middleware "^5.3.1"
|
||||
ws "^8.4.2"
|
||||
|
||||
webpack-merge@^4.1.5:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz"
|
||||
integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==
|
||||
dependencies:
|
||||
lodash "^4.17.15"
|
||||
|
||||
webpack-merge@^5.7.3, webpack-merge@^5.8.0:
|
||||
version "5.8.0"
|
||||
resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz"
|
||||
@@ -11783,7 +11439,7 @@ which-typed-array@^1.1.8:
|
||||
has-tostringtag "^1.0.0"
|
||||
is-typed-array "^1.1.10"
|
||||
|
||||
which@^1.2.1, which@^1.2.14:
|
||||
which@^1.2.14:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
@@ -11864,11 +11520,6 @@ ws@^8.4.2:
|
||||
resolved "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz"
|
||||
integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==
|
||||
|
||||
ws@~8.2.3:
|
||||
version "8.2.3"
|
||||
resolved "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz"
|
||||
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||
|
||||
xml-beautifier@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.npmjs.org/xml-beautifier/-/xml-beautifier-0.5.0.tgz"
|
||||
@@ -11942,7 +11593,7 @@ yaml@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz"
|
||||
integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
|
||||
|
||||
yargs-parser@^20.2.2, yargs-parser@^20.2.9:
|
||||
yargs-parser@^20.2.9:
|
||||
version "20.2.9"
|
||||
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"
|
||||
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
|
||||
@@ -11960,19 +11611,6 @@ yargs-parser@^5.0.1:
|
||||
camelcase "^3.0.0"
|
||||
object.assign "^4.1.0"
|
||||
|
||||
yargs@^16.1.1:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
|
||||
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
|
||||
dependencies:
|
||||
cliui "^7.0.2"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
string-width "^4.2.0"
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yargs@^17.3.1:
|
||||
version "17.6.2"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541"
|
||||
|
||||
Reference in New Issue
Block a user