Comparar commits

..

1 Commits

Autor SHA1 Mensagem Data
Brian Broll 3676d4c340 WIP Added istanbul 2016-10-02 09:04:17 -05:00
142 arquivos alterados com 2085 adições e 20755 exclusões
-2
Ver Arquivo
@@ -31,8 +31,6 @@ exclude_paths:
- test/
- src/common/lua.js
- src/common/js-yaml.min.js
- src/visualizers/widgets/Sidebar/lib/
- src/visualizers/widgets/TextEditor/lib/
- src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
- src/visualizers/widgets/LineGraph/lib/
- src/visualizers/widgets/PipelineEditor/klay.js
-40
Ver Arquivo
@@ -1,40 +0,0 @@
src/worker/tmp
.env
*.swp
*.swo
**.sass-cache
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
tmp/
test-tmp/
blob-local-storage/
src/seeds/nn/hash.txt
src/seeds/pipeline/hash.txt
# docs
images/
+4 -10
Ver Arquivo
@@ -4,22 +4,16 @@
[![Join the chat at https://gitter.im/dfst/deepforge](https://badges.gitter.im/dfst/deepforge.svg)](https://gitter.im/dfst/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Stories in Ready](https://badge.waffle.io/dfst/deepforge.png?label=ready&title=Ready)](https://waffle.io/dfst/deepforge)
**Notice**: DeepForge is still a work in progress and in beta! That being said, any contributions and/or feedback is greatly appreciated. If you have any questions, check out the [wiki](https://github.com/dfst/deepforge/wiki/) or drop me a line on the gitter!
**Notice**: DeepForge is still a work in progress and is also lacking significant documentation! That being said, any contributions and/or feedback is greatly appreciated (and feel free to always ask any questions on the gitter)!
# DeepForge
DeepForge is an open-source visual development environment for deep learning providing end-to-end support for creating deep learning models. This is achieved through providing the ability to design **architectures**, create training **pipelines**, and then execute these pipelines over a cluster. Using a notebook-esque api, users can get real-time feedback about the status of any of their **executions** including compare them side-by-side in real-time.
![overview](images/overview.png "")
Additional features include:
DeepForge is an open-source visual development environment for deep learning. Currently, it supports Convolutional Neural Networks, RNNs and LSTMs as well as the creation of custom layers. Additional features include:
- Graphical architecture editor
- Training/testing pipeline creation
- Distributed pipeline execution
- Real-time pipeline feedback
- Collaborative editing
- Automatic version control.
- Facilitates defining custom layers
## Quick Start
Simply run the following command to install deepforge with its dependencies:
@@ -34,9 +28,9 @@ Or, if you already have NodeJS (v6) installed, simply run
npm install -g deepforge
```
Finally, start deepforge with `deepforge start`and navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions, check out the [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
Next, start deepforge with `deepforge start`!
**Note**: running deepforge w/ `deepforge start` will also require [MongoDB](https://www.mongodb.com/download-center?jmp=nav#community) to be installed locally.
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions, check out the [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
Also, be sure to check out the other available features of the `deepforge` cli; it can be used to update, manage your torch installation, uninstall deepforge and run individual components!
+4 -19
Ver Arquivo
@@ -2,19 +2,10 @@
"AutoViz": {
"preloadIds": [
"ArchEditor",
"ArchIndex",
"PipelineIndex",
"PipelineEditor",
"OperationEditor",
"ExecutionView"
],
"visualizerOverrides": {
"": "ForwardViz",
"MyArtifacts": "ArtifactIndex",
"MyArchitectures": "ArchIndex",
"MyExecutions": "ExecutionIndex",
"MyPipelines": "PipelineIndex"
}
]
},
"ArchEditor": {
"hotkeys": "none",
@@ -52,11 +43,11 @@
"rootMenuClass": "deepforge-logo",
"rootDisplayName": "DeepForge"
},
"SidebarLayout": {
"CHFLayout": {
"panels": [
{
"id": "WorkerHeader",
"panel": "WorkerHeader/WorkerHeaderPanel",
"id": "Header",
"panel": "BreadcrumbHeader/BreadcrumbHeaderPanel",
"container": "header",
"DEBUG_ONLY": false
},
@@ -72,12 +63,6 @@
"container": "center",
"DEBUG_ONLY": false
},
{
"id": "Sidebar",
"panel": "Sidebar/SidebarPanel",
"container": "sidebar",
"DEBUG_ONLY": false
},
{
"id": "ForgeActionButton",
"panel": "ForgeActionButton/ForgeActionButton",
+1 -4
Ver Arquivo
@@ -9,7 +9,6 @@ var config = require('webgme/config/config.default'),
// The paths can be loaded from the webgme-setup.json
config.plugin.basePaths.push(__dirname + '/../src/plugins');
config.plugin.basePaths.push(__dirname + '/../node_modules/webgme-simple-nodes/src/plugins');
config.visualization.layout.basePaths.push(__dirname + '/../src/layouts');
config.visualization.layout.basePaths.push(__dirname + '/../node_modules/webgme-chflayout/src/layouts');
config.visualization.decoratorPaths.push(__dirname + '/../src/decorators');
config.visualization.decoratorPaths.push(__dirname + '/../node_modules/webgme-easydag/src/decorators');
@@ -33,8 +32,6 @@ config.visualization.panelPaths.push(__dirname + '/../src/visualizers/panels');
config.rest.components['execution/logs'] = __dirname + '/../src/routers/JobLogsAPI/JobLogsAPI.js';
config.rest.components['job/origins'] = __dirname + '/../src/routers/JobOriginAPI/JobOriginAPI.js';
config.rest.components['execution/pulse'] = __dirname + '/../src/routers/ExecPulse/ExecPulse.js';
// Visualizer descriptors
config.visualization.visualizerDescriptors.push(__dirname + '/../src/visualizers/Visualizers.json');
@@ -59,7 +56,7 @@ config.requirejsPaths = {
'widgets/FloatingActionButton': './node_modules/webgme-fab/src/visualizers/widgets/FloatingActionButton'
};
config.visualization.layout.default = 'SidebarLayout';
config.visualization.layout.default = 'CHFLayout';
config.mongo.uri = 'mongodb://127.0.0.1:27017/deepforge';
validateConfig(config);
module.exports = config;
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 681 KiB

+4 -4
Ver Arquivo
@@ -42,10 +42,10 @@ detect_profile() {
detect_profile
set_node_version() {
# Install nodejs v6.2.1
echo "Installing NodeJS v6.2.1"
nvm install v6.2.1
nvm alias default v6.2.1
# Install nodejs v6.2.0
echo "Installing NodeJS v6.2.0"
nvm install v6.2.0
nvm alias default v6.2.0
# Install npm@2
npm install npm@2 -g
+5 -4
Ver Arquivo
@@ -9,10 +9,11 @@
"local": "node ./bin/start-local.js",
"worker": "node ./bin/start-worker.js",
"test": "mkdir ./test-tmp; node ./node_modules/mocha/bin/mocha --recursive test",
"test-cover": "node node_modules/istanbul/lib/cli.js --hook-run-in-context cover node_modules/mocha/bin/_mocha -- -R spec test/**/*",
"watch-test": "./node_modules/nodemon/bin/nodemon.js --exec 'node ./node_modules/mocha/bin/mocha --recursive test'",
"build-nn": "node ./utils/nn-parser.js"
},
"version": "0.19.0",
"version": "0.16.0",
"dependencies": {
"commander": "^2.9.0",
"dotenv": "^2.0.0",
@@ -20,12 +21,11 @@
"express": "^4.14.0",
"lodash.difference": "^4.1.2",
"lodash.merge": "^4.5.1",
"mongodb": "^2.2.10",
"nodemon": "^1.9.2",
"q": "1.4.1",
"rimraf": "^2.4.0",
"webgme": "^2.6.0",
"webgme-autoviz": "^2.2.0",
"webgme": "^2.0.0",
"webgme-autoviz": "dfst/webgme-autoviz",
"webgme-breadcrumbheader": "^2.1.1",
"webgme-chflayout": "^2.0.0",
"webgme-easydag": "dfst/webgme-easydag",
@@ -36,6 +36,7 @@
"chai": "^3.0.0",
"jszip": "^2.5.0",
"mocha": "^2.2.5",
"istanbul": "^0.4.5",
"mockery": "^1.7.0"
}
}
+24 -42
Ver Arquivo
@@ -1,49 +1,31 @@
/* globals define */
(function(root, factory){
if(typeof define === 'function' && define.amd) {
define([], function(){
return factory();
});
} else if(typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.CONSTANTS = factory();
}
}(this, function() {
return {
LINE_OFFSET: 'lineOffset',
define({
LINE_OFFSET: 'lineOffset',
// DeepForge metadata creation in dist execution
START_CMD: 'deepforge-cmd',
// DeepForge metadata creation in dist execution
START_CMD: 'deepforge-cmd',
IMAGE: { // all prefixed w/ 'IMG' for simple upload detection
PREFIX: 'IMG',
BASIC: 'IMG-B',
CREATE: 'IMG-C',
UPDATE: 'IMG-U',
NAME: 'IMAGE-N' // No upload required
},
IMAGE: { // all prefixed w/ 'IMG' for simple upload detection
PREFIX: 'IMG',
BASIC: 'IMG-B',
CREATE: 'IMG-C',
UPDATE: 'IMG-U',
NAME: 'IMAGE-N' // No upload required
},
GRAPH_CREATE: 'GRAPH',
GRAPH_PLOT: 'PLOT',
GRAPH_CREATE_LINE: 'LINE',
GRAPH_CREATE: 'GRAPH',
GRAPH_PLOT: 'PLOT',
GRAPH_CREATE_LINE: 'LINE',
// Code Generation Constants
CTOR_ARGS_ATTR: 'ctor_arg_order',
// Code Generation Constants
CTOR_ARGS_ATTR: 'ctor_arg_order',
// Operation types
OP: {
INPUT: 'Input',
OUTPUT: 'Output'
},
// Operation types
OP: {
INPUT: 'Input',
OUTPUT: 'Output'
},
PULSE: {
DEAD: 0,
ALIVE: 1,
DOESNT_EXIST: 2
},
// Job stdout update
STDOUT_UPDATE: 'stdout_update'
};
}));
// Job stdout update
STDOUT_UPDATE: 'stdout_update'
});
@@ -1,38 +1,51 @@
/* globals define */
define([
'./APIClient',
'q',
'superagent'
], function(
APIClient,
Q,
superagent
) {
'use strict';
// Wrap the ability to read, update, and delete logs using the JobLogsAPI
var METADATA_FIELDS = [
'lineCount'
];
var JobLogsClient = function(params) {
params = params || {};
this.relativeUrl = '/execution/logs';
this.logger = params.logger.fork('JobLogsClient');
APIClient.call(this, params);
// Get the server url
this.token = params.token;
this.origin = this._getServerUrl(params);
this.relativeUrl = '/execution/logs';
this.url = this.origin + this.relativeUrl;
this.logger.debug(`Setting url to ${this.url}`);
// Get the project, branch name
if (!(params.branchName && params.projectId)) {
throw Error('"branchName" and "projectId" required');
}
this.branch = params.branchName;
this.project = params.projectId;
this._modifiedJobs = [];
this.logger.debug(`Using <project>:<branch>: "${this.project}"/"${this.branch}"`);
this.logger.info('ctor finished');
};
JobLogsClient.prototype = Object.create(APIClient.prototype);
JobLogsClient.prototype._getServerUrl = function(params) {
if (typeof window !== 'undefined') {
return window.location.origin;
}
// If not in browser, set using the params
var server = params.server || '127.0.0.1',
port = params.port || '80',
protocol = params.httpsecure ? 'https' : 'http'; // default is http
return params.origin || `${protocol}://${server}:${port}`;
};
// This method could be optimized - it could make a log of requests
JobLogsClient.prototype.fork = function(forkName) {
@@ -66,54 +79,53 @@ define([
};
JobLogsClient.prototype.getUrl = function(jobId) {
var url = this.url;
if (typeof jobId !== 'string') {
url = this.url + jobId.route;
jobId = jobId.jobId;
}
return [
url,
this.url,
encodeURIComponent(this.project),
encodeURIComponent(this.branch),
encodeURIComponent(jobId)
].join('/');
};
var hasRequiredFields = function(md) {
return METADATA_FIELDS.reduce((passing, nextField) => {
return passing && md.hasOwnProperty(nextField);
}, true);
JobLogsClient.prototype._logRequest = function(method, jobId, content) {
var deferred = Q.defer(),
req = superagent[method](this.getUrl(jobId));
this.logger.info(`sending ${method} request to ${this.getUrl(jobId)}`);
if (this.token) {
req.set('Authorization', 'Bearer ' + this.token);
}
if (content) {
req = req.send(content);
}
req.end((err, res) => {
if (err || res.status > 399) {
return deferred.reject(err || res.status);
}
return deferred.resolve(res);
});
return deferred.promise;
};
JobLogsClient.prototype.appendTo = function(jobId, text, metadata) {
JobLogsClient.prototype.appendTo = function(jobId, text) {
this._modifiedJobs.push(jobId);
this.logger.info(`Appending logs to ${jobId}`);
if (metadata && !hasRequiredFields(metadata)) {
throw Error(`Required metadata fields: ${METADATA_FIELDS.join(', ')}`);
}
metadata = metadata || {};
metadata.patch = text;
return this._request('patch', jobId, metadata);
return this._logRequest('patch', jobId, {patch: text});
};
JobLogsClient.prototype.getLog = function(jobId) {
this.logger.info(`Getting logs for ${jobId}`);
return this._request('get', jobId)
return this._logRequest('get', jobId)
.then(res => res.text);
};
JobLogsClient.prototype.deleteLog = function(jobId) {
this.logger.info(`Deleting logs for ${jobId}`);
return this._request('delete', jobId);
};
JobLogsClient.prototype.getMetadata = function(jobId) {
this.logger.info(`Getting line count for ${jobId}`);
return this._request('get', {jobId: jobId, route: '/metadata'})
.then(res => JSON.parse(res.text));
return this._logRequest('delete', jobId);
};
return JobLogsClient;
+2 -4
Ver Arquivo
@@ -265,7 +265,6 @@
var findTorchClass = function(ast){
var torchClassArgs, // args for `torch.class(...)`
name = '',
alias,
baseType,
params,
setters = {},
@@ -284,7 +283,6 @@
name = torchClassArgs[0];
if(name !== ''){
name = name.replace('nn.', '');
alias = func.names[0] || name;
if (torchClassArgs.length > 1) {
baseType = torchClassArgs[1].replace('nn.', '');
}
@@ -304,7 +302,7 @@
attrName;
// Record the setter functions
if (isSetterMethod(curr, parent, alias)) {
if (isSetterMethod(curr, parent, name)) {
firstLine = curr.block.stats[0];
// just use the attribute attrName for now...
attrName = getSettingAttrName(firstLine);
@@ -318,7 +316,7 @@
} else {
setters[attrName] = schema;
}
} else if (isInitFn(curr, alias)) { // Record the defaults
} else if (isInitFn(curr, name)) { // Record the defaults
paramDefs = getAttrsAndVals(curr);
attrDefs = getClassAttrDefs(curr);
types = inferParamTypes(curr, paramDefs);
-75
Ver Arquivo
@@ -1,75 +0,0 @@
/*globals define*/
define([
'q',
'superagent'
], function(
Q,
superagent
) {
'use strict';
// Wrap the ability to read, update, and delete logs using the JobLogsAPI
var APIClient = function(params) {
params = params || {};
this.logger = this.logger || params.logger.fork('APIClient');
// Get the server url
this.token = params.token;
this.origin = this._getServerUrl(params);
this.relativeUrl = this.relativeUrl || '';
this.url = this.origin + this.relativeUrl;
this.logger.debug(`Setting url to ${this.url}`);
this.branch = params.branchName;
this.project = params.projectId;
this._modifiedJobs = [];
this.logger.debug(`Using <project>:<branch>: "${this.project}"/"${this.branch}"`);
this.logger.info('ctor finished');
};
APIClient.prototype._getServerUrl = function(params) {
if (typeof window !== 'undefined') {
return window.location.origin;
}
// If not in browser, set using the params
var server = params.server || '127.0.0.1',
port = params.port || '80',
protocol = params.httpsecure ? 'https' : 'http'; // default is http
return params.origin || `${protocol}://${server}:${port}`;
};
APIClient.prototype.getUrl = function() {
return this.url;
};
APIClient.prototype._request = function(method, jobId, content) {
var deferred = Q.defer(),
req = superagent[method](this.getUrl(jobId));
this.logger.debug(`sending ${method} request to ${this.getUrl(jobId)}`);
if (this.token) {
req.set('Authorization', 'Bearer ' + this.token);
}
if (content) {
req = req.send(content);
}
req.end((err, res) => {
if (err || res.status > 399) {
return deferred.reject(res || err);
}
return deferred.resolve(res);
});
return deferred.promise;
};
return APIClient;
});
-44
Ver Arquivo
@@ -1,44 +0,0 @@
/* globals define */
define([
'./APIClient'
], function(
APIClient
) {
'use strict';
var ExecPulseClient = function(params) {
this.relativeUrl = '/execution/pulse/';
this.logger = params.logger.fork('ExecPulseClient');
APIClient.call(this, params);
};
ExecPulseClient.prototype = Object.create(APIClient.prototype);
ExecPulseClient.prototype.getUrl = function(hash) {
return this.url + hash;
};
// - update the heartbeat
// - check the heartbeat
// - delete the heartbeat
ExecPulseClient.prototype.update = function(hash) {
return this._request('post', hash)
.catch(err => {
throw err.text || err;
});
};
ExecPulseClient.prototype.check = function(hash) {
return this._request('get', hash)
.then(res => JSON.parse(res.text))
.catch(err => {
throw err.text || err;
});
};
ExecPulseClient.prototype.clear = function(hash) {
return this._request('delete', hash);
};
return ExecPulseClient;
});
-60
Ver Arquivo
@@ -1,60 +0,0 @@
/* globals define */
define([
'./APIClient'
], function(
APIClient
) {
'use strict';
var JobOriginClient = function(params) {
this.relativeUrl = '/job/origins/';
this.logger = params.logger.fork('JobOriginClient');
APIClient.call(this, params);
};
JobOriginClient.prototype = Object.create(APIClient.prototype);
// - Record the origin
// - Look up the origin
// - Delete record
JobOriginClient.prototype.getUrl = function(hash) {
return this.url + hash;
};
JobOriginClient.prototype.record = function(hash, info) {
var jobInfo = {
hash: hash,
nodeId: info.nodeId,
job: info.job,
project: info.project || this.project,
branch: info.branch || this.branch,
execution: info.execution
};
return this._request('post', hash, jobInfo)
.catch(err => {
throw err.text || err;
});
};
JobOriginClient.prototype.getOrigin = function(hash) {
return this._request('get', hash)
.then(res => JSON.parse(res.text))
.catch(res => {
if (res.status && res.status === 404) {
return null;
}
throw res;
});
};
JobOriginClient.prototype.fork = function(hash, forkName) {
return this._request('patch', hash, {branch: forkName});
};
JobOriginClient.prototype.deleteRecord = function(hash) {
return this._request('delete', hash);
};
return JobOriginClient;
});
+3 -3
Ver Arquivo
@@ -57,7 +57,7 @@ define([
};
var createNamedNode = function(baseId, parentId, isMeta) {
var newId = client.createNode({parentId, baseId}),
var newId = client.createChild({parentId, baseId}),
baseNode = client.getNode(baseId),
basename = 'New' + baseNode.getAttribute('name'),
newName = getUniqueName(parentId, basename);
@@ -72,7 +72,7 @@ define([
client.setRegistry(newId, 'isAbstract', false);
}
client.setAttribute(newId, 'name', newName);
client.setAttributes(newId, 'name', newName);
return newId;
};
@@ -265,7 +265,7 @@ define([
}
dataBaseId = dataBase.getId();
dataTypes = metanodes.filter(n => n.isTypeOf(dataBaseId))
dataTypes = metanodes.filter(n => client.isTypeOf(n.getId(), dataBaseId))
.filter(n => !n.getRegistry('isAbstract'))
.map(node => node.getAttribute('name'));
+4 -7
Ver Arquivo
@@ -148,14 +148,11 @@ define([
// get the input node
if (dataNodes.length !== 0) {
var newNodes = this.core.copyNodes(dataNodes, parentNode),
newName = this.core.getOwnAttribute(node, 'saveName'),
createdAt = Date.now();
newName = this.core.getOwnAttribute(node, 'saveName');
if (newName) {
newNodes.forEach(node => {
this.setAttribute(node, 'name', newName);
this.setAttribute(node, 'createdAt', createdAt);
});
newNodes.forEach(node =>
this.setAttribute(node, 'name', newName)
);
}
var hashes = dataNodes.map(n => this.getAttribute(n, 'data'));
this.logger.info(`saving hashes: ${hashes.map(h => `"${h}"`)}`);
+19 -113
Ver Arquivo
@@ -3,31 +3,21 @@
define([
'q',
'executor/ExecutorClient',
'deepforge/api/ExecPulseClient',
'deepforge/api/JobOriginClient',
'deepforge/Constants',
'panel/FloatingActionButton/styles/Materialize'
], function(
Q,
ExecutorClient,
ExecPulseClient,
JobOriginClient,
CONSTANTS,
Materialize
) {
var Execute = function(client, logger) {
this.client = this.client || client;
this.logger = this.logger || logger;
this.pulseClient = new ExecPulseClient({
logger: this.logger
});
this._executor = new ExecutorClient({
logger: this.logger.fork('ExecutorClient'),
serverPort: WebGMEGlobal.gmeConfig.server.port,
httpsecure: window.location.protocol === 'https:'
});
this.originManager = new JobOriginClient({logger: this.logger});
};
Execute.prototype.executeJob = function(node) {
@@ -112,21 +102,6 @@ define([
.fail(err => this.logger.error(`Job cancel failed: ${err}`));
};
Execute.prototype._setJobStopped = function(jobId, silent) {
if (!silent) {
var name = this.client.getNode(jobId).getAttribute('name');
this.client.startTransaction(`Stopping "${name}" job`);
}
this.client.delAttribute(jobId, 'jobId');
this.client.delAttribute(jobId, 'secret');
this.client.setAttribute(jobId, 'status', 'canceled');
if (!silent) {
this.client.completeTransaction();
}
};
Execute.prototype.stopJob = function(job, silent) {
var jobId;
@@ -134,7 +109,18 @@ define([
jobId = job.getId();
this.silentStopJob(job);
this._setJobStopped(jobId, silent);
if (!silent) {
this.client.startTransaction(`Stopping "${name}" job`);
}
this.client.delAttributes(jobId, 'jobId');
this.client.delAttributes(jobId, 'secret');
this.client.setAttributes(jobId, 'status', 'canceled');
if (!silent) {
this.client.completeTransaction();
}
};
@@ -179,17 +165,14 @@ define([
};
Execute.prototype._stopExecution = function(execNode, inTransaction) {
var msg = `Canceling ${execNode.getAttribute('name')} execution`,
jobIds;
var msg = `Canceling ${execNode.getAttribute('name')} execution`;
if (!inTransaction) {
this.client.startTransaction(msg);
}
jobIds = this._silentStopExecution(execNode);
this.client.setAttribute(execNode.getId(), 'status', 'canceled');
jobIds.forEach(jobId => this._setJobStopped(jobId, true));
this._silentStopExecution(execNode);
this.client.setAttributes(execNode.getId(), 'status', 'canceled');
if (!inTransaction) {
this.client.completeTransaction();
@@ -197,88 +180,11 @@ define([
};
Execute.prototype._silentStopExecution = function(execNode) {
var runningJobIds = execNode.getChildrenIds()
.map(id => this.client.getNode(id))
.filter(job => this.isRunning(job)); // get running jobs
var jobIds = execNode.getChildrenIds();
runningJobIds.forEach(job => this.silentStopJob(job)); // stop them
return runningJobIds;
};
// Resuming Executions
Execute.prototype.checkJobExecution= function (job) {
var pipelineId = job.getParentId(),
pipeline = this.client.getNode(pipelineId);
// First check the parent execution. If it doesn't exist, then check the job
return this.checkPipelineExecution(pipeline)
.then(tryToStartJob => {
if (tryToStartJob) {
return this._checkJobExecution(job);
}
});
};
Execute.prototype._checkJobExecution = function (job) {
var jobId = job.getAttribute('jobId'),
status = job.getAttribute('status');
if (status === 'running' && jobId) {
return this.pulseClient.check(jobId)
.then(status => {
if (status !== CONSTANTS.PULSE.DOESNT_EXIST) {
return this._onOriginBranch(jobId).then(onBranch => {
if (onBranch) {
this.runExecutionPlugin('ExecuteJob', {
node: job
});
}
});
} else {
this.logger.warn(`Could not restart job: ${job.getId()}`);
}
});
}
return Q();
};
Execute.prototype._onOriginBranch = function (hash) {
return this.originManager.getOrigin(hash)
.then(origin => {
var currentBranch = this.client.getActiveBranchName();
if (origin && origin.branch) {
return origin.branch === currentBranch;
}
return false;
});
};
Execute.prototype.checkPipelineExecution = function (pipeline) {
var runId = pipeline.getAttribute('runId'),
status = pipeline.getAttribute('status'),
tryToStartJob = true;
if (status === 'running' && runId) {
return this.pulseClient.check(runId)
.then(status => {
if (status === CONSTANTS.PULSE.DEAD) {
// Check the origin branch
return this._onOriginBranch(runId).then(onBranch => {
if (onBranch) {
this.runExecutionPlugin('ExecutePipeline', {
node: pipeline
});
}
});
}
// only try to start if the pulse info doesn't exist
tryToStartJob = status === CONSTANTS.PULSE.DOESNT_EXIST;
return tryToStartJob;
});
} else {
return Q().then(() => tryToStartJob);
}
jobIds.map(id => this.client.getNode(id))
.filter(job => this.isRunning(job)) // get running jobs
.forEach(job => this.silentStopJob(job)); // stop them
};
return Execute;
+1 -1
Ver Arquivo
@@ -65,7 +65,7 @@ define([
PipelineControl.prototype.createNode = function(baseId) {
var parentId = this._currentNodeId,
newNodeId = this._client.createNode({parentId, baseId});
newNodeId = this._client.createChild({parentId, baseId});
return newNodeId;
};
+1 -1
Ver Arquivo
@@ -49,7 +49,7 @@ define([
if (!/^\s*$/.test(newValue)) {
this._client.startTransaction(msg);
this._client.setAttribute(nodeId, 'name', newValue);
this._client.setAttributes(nodeId, 'name', newValue);
this._client.completeTransaction();
}
}
-41
Ver Arquivo
@@ -1,41 +0,0 @@
/* globals define */
define([
'panels/EasyDAG/EasyDAGControl'
], function(
EasyDAGControl
) {
var ThumbnailControl = function() {
EasyDAGControl.apply(this, arguments);
};
ThumbnailControl.prototype = Object.create(EasyDAGControl.prototype);
ThumbnailControl.prototype._initWidgetEventHandlers = function () {
EasyDAGControl.prototype._initWidgetEventHandlers.call(this);
this._widget.updateThumbnail = this.updateThumbnail.bind(this);
};
ThumbnailControl.prototype.updateThumbnail = function (svg) {
var node = this._client.getNode(this._currentNodeId),
name,
attrs,
currentThumbnail,
attrName = 'thumbnail',
msg;
if (node) { // may have been deleted
name = node.getAttribute('name');
attrs = node.getValidAttributeNames();
currentThumbnail = node.getAttribute(attrName);
msg = `Updating pipeline thumbnail for "${name}"`;
if (attrs.indexOf(attrName) > -1 && currentThumbnail !== svg) {
this._client.startTransaction(msg);
this._client.setAttribute(this._currentNodeId, attrName, svg);
this._client.completeTransaction();
}
}
};
return ThumbnailControl;
});
-84
Ver Arquivo
@@ -1,84 +0,0 @@
/* globals define, $, _ */
define([
'widgets/EasyDAG/EasyDAGWidget'
], function(
EasyDAGWidget
) {
var ThumbnailWidget = function() {
EasyDAGWidget.apply(this, arguments);
};
ThumbnailWidget.prototype = Object.create(EasyDAGWidget.prototype);
ThumbnailWidget.prototype.addNode = function() {
var result = EasyDAGWidget.prototype.addNode.apply(this, arguments);
this.refreshThumbnail();
return result;
};
ThumbnailWidget.prototype.removeNode = function() {
var result = EasyDAGWidget.prototype.removeNode.apply(this, arguments);
this.refreshThumbnail();
return result;
};
ThumbnailWidget.prototype._removeConnection = function() {
var result = EasyDAGWidget.prototype._removeConnection.apply(this, arguments);
this.refreshThumbnail();
return result;
};
ThumbnailWidget.prototype.addConnection = function() {
var result = EasyDAGWidget.prototype.addConnection.apply(this, arguments);
this.refreshThumbnail();
return result;
};
////////////////////////// Thumbnail updates //////////////////////////
ThumbnailWidget.prototype.getSvgDistanceDim = function(dim) {
var maxValue = this._getMaxAlongAxis(dim),
nodes,
minValue;
nodes = this.graph.nodes().map(id => this.graph.node(id));
minValue = Math.min.apply(null, nodes.map(node => node[dim]));
return maxValue-minValue;
};
ThumbnailWidget.prototype.getSvgWidth = function() {
return this.getSvgDistanceDim('x');
};
ThumbnailWidget.prototype.getSvgHeight = function() {
return this.getSvgDistanceDim('y');
};
ThumbnailWidget.prototype.getViewBox = function() {
var maxX = this.getSvgWidth('x'),
maxY = this.getSvgHeight('y');
return `0 0 ${maxX} ${maxY}`;
};
ThumbnailWidget.prototype.refreshThumbnail = _.debounce(function() {
// Get the svg...
var svg = document.createElement('svg'),
group = this.$svg.node(),
child;
svg.setAttribute('viewBox', this.getViewBox());
for (var i = 0; i < group.children.length; i++) {
child = $(group.children[i]);
svg.appendChild(child.clone()[0]);
}
this.updateThumbnail(svg.outerHTML);
}, 1000);
return ThumbnailWidget;
});
@@ -57,13 +57,13 @@ define([
this.client.startTransaction(`Removing output of ${this.name}`);
this.client.delPointer(this._node.id, name);
if (outputId) {
this.client.delAttribute(outputId, 'data');
this.client.delAttributes(outputId, 'data');
}
this.client.completeTransaction();
} else if (name === this.castOpts.ptr) { // set the casted value
this.client.startTransaction(`Setting output of ${this.name} to ${to}`);
this.castOutputType(to);
this.client.setPointer(this._node.id, name, to);
this.client.makePointer(this._node.id, name, to);
this.client.completeTransaction();
} else {
DecoratorBase.prototype.savePointer.call(this, name, to);
@@ -47,11 +47,11 @@ define([
// create the outputId node
outputId = this._createOutputNode(baseId);
} else {
this.client.setPointer(outputId, CONSTANTS.POINTER_BASE, baseId);
this.client.makePointer(outputId, CONSTANTS.POINTER_BASE, baseId);
}
// Copy the data content to the output node
hash = target.getAttribute('data');
this.client.setAttribute(outputId, 'data', hash);
this.client.setAttributes(outputId, 'data', hash);
};
DcOpDecorator.prototype._createOutputNode = function(baseId) {
@@ -69,7 +69,7 @@ define([
return metaType.getAttribute('name') === 'Outputs';
});
return this.client.createNode({
return this.client.createChild({
baseId: baseId,
parentId: outputCntrId
});
@@ -77,11 +77,11 @@ define([
// Create a nested "architecture" node and set the ptr target to it
baseId = base.getId();
this.client.startTransaction(msg);
tgtId = this.client.createNode({
tgtId = this.client.createChild({
parentId: this._node.id,
baseId: baseId
});
this.client.setAttribute(tgtId, 'name', `${ptr} (${this._node.name})`);
this.client.setAttributes(tgtId, 'name', `${ptr} (${this._node.name})`);
this.savePointer(ptr, tgtId);
this.client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(tgtId);
@@ -95,7 +95,7 @@ define([
// If the target is contained in the current node, delete it!
if (currentId.indexOf(this._node.id) === 0) {
this.client.startTransaction(`Removing layer for ${ptr} of ${name}`);
this.client.deleteNode(currentId);
this.client.delMoreNodes([currentId]);
this.client.completeTransaction();
this.logger.info(`Removed ${ptr} and deleted target (${currentId})`);
} else {
@@ -102,8 +102,8 @@ define([
msg = `Deleting "${name}" attribute from "${opName}" operation`;
this.client.startTransaction(msg);
this.client.delAttributeMeta(this._node.id, name);
this.client.delAttribute(this._node.id, name);
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
this.client.completeTransaction();
};
@@ -129,14 +129,14 @@ define([
if (name !== desc.name) { // Renaming attribute
if (name) {
this.client.delAttributeMeta(this._node.id, name);
this.client.delAttribute(this._node.id, name);
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
}
name = desc.name;
}
this.client.setAttributeMeta(this._node.id, name, schema);
this.client.setAttribute(this._node.id, name, desc.defaultValue);
this.client.setAttributeSchema(this._node.id, name, schema);
this.client.setAttributes(this._node.id, name, desc.defaultValue);
this.client.completeTransaction();
};
@@ -73,15 +73,14 @@ define([
OperationDecorator.prototype.showPorts = function(ids, areInputs) {
var allPorts = areInputs ? this._node.inputs : this._node.outputs,
ports = ids ? allPorts.filter(port => ids.indexOf(port.id) > -1) : allPorts,
x = -this.width/2,
dx = this.width/(allPorts.length+1),
dx = this.width/(ports.length+1),
y = areInputs ? 0 : this.height; // (this.height/2);
allPorts.forEach(port => {
ports.forEach(port => {
x += dx;
if (!ids || ids.indexOf(port.id) > -1) {
this.renderPort(port, x, y, areInputs);
}
this.renderPort(port, x, y, areInputs);
});
};
@@ -118,7 +117,7 @@ define([
tooltip = new Opentip(portIcon[0][0], PORT_TOOLTIP_OPTS);
tooltip.setContent(port.name);
portIcon.on('mouseenter', () => tooltip.show());
portIcon.on('mouseleave', () => tooltip.hide());
portIcon.on('mouseout', () => tooltip.hide());
this.$portTooltips[port.id] = tooltip;
};
-12
Ver Arquivo
@@ -1,12 +0,0 @@
.ui-layout-center .layout-center {
left: 40px;
height: 100%;
width: 100%;
position: absolute;
}
.ui-layout-sidebar {
top: 64px;
width: 40px;
bottom: 27px;
}
-52
Ver Arquivo
@@ -1,52 +0,0 @@
/*globals define, */
define([
'layout/CHFLayout/CHFLayout/CHFLayout',
'text!./templates/SidebarLayout.html',
'css!./SidebarLayout.css'
], function(
CHFLayout,
SidebarTemplate
) {
'use strict';
var SidebarLayout = function(params) {
params = params || {};
params.template = SidebarTemplate;
CHFLayout.call(this, params);
};
SidebarLayout.prototype = Object.create(CHFLayout.prototype);
SidebarLayout.prototype.getComponentId = function () {
return 'SidebarLayout';
};
/**
* Initialize the html page. This example is using the jQuery Layout plugin.
*
* @return {undefined}
*/
SidebarLayout.prototype.init = function() {
CHFLayout.prototype.init.apply(this, arguments);
this._sidebarPanel = this._body.find('div.ui-layout-sidebar');
this._centerPanel = this._body.find('div.layout-center');
};
/**
* Add a panel to a given container. This is defined in the corresponding
* layout config JSON file.
*
* @param {Panel} panel
* @param {String} container
* @return {undefined}
*/
SidebarLayout.prototype.addToContainer = function(panel, container) {
if (container === 'sidebar') {
this._sidebarPanel.append(panel.$pEl);
} else {
CHFLayout.prototype.addToContainer.apply(this, arguments);
}
};
return SidebarLayout;
});
@@ -1,7 +0,0 @@
<div class="ui-layout-center" style="position: relative;">
<div class="layout-center"></div>
<div class="float"></div>
</div>
<div class="ui-layout-sidebar"></div>
<div class="ui-layout-north"></div>
<div class="ui-layout-south"></div>
+12 -274
Ver Arquivo
@@ -65,14 +65,7 @@
"affine"
],
"setters": {},
"types": {
"eps": "number",
"momentum": "number"
},
"defaults": {
"momentum": 0.1,
"eps": 0.00001
},
"defaults": {},
"type": "Misc"
},
{
@@ -89,35 +82,6 @@
"defaults": {},
"type": "Misc"
},
{
"name": "Bottle",
"baseType": "Container",
"params": [
"module",
"nInputDim",
"nOutputDim"
],
"setters": {},
"types": {
"nInputDim": "number",
"module": "nn.Module"
},
"defaults": {
"nInputDim": 2
},
"type": "Misc"
},
{
"name": "CAdd",
"baseType": "Module",
"params": [
"params"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "CAddTable",
"baseType": "Module",
@@ -138,24 +102,6 @@
"defaults": {},
"type": "Misc"
},
{
"name": "CMaxTable",
"baseType": "Module",
"params": [],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "CMinTable",
"baseType": "Module",
"params": [],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "CMul",
"baseType": "Module",
@@ -350,16 +296,13 @@
"params": [
"p",
"v1",
"inplace",
"stochasticInference"
"inplace"
],
"setters": {},
"types": {
"p": "number",
"stochasticInference": "boolean"
"p": "number"
},
"defaults": {
"stochasticInference": false,
"p": 0.5
},
"type": "Simple"
@@ -414,11 +357,8 @@
{
"name": "GradientReversal",
"baseType": "Module",
"params": [
"lambda"
],
"params": [],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
@@ -442,8 +382,7 @@
"baseType": "Module",
"params": [
"min_value",
"max_value",
"inplace"
"max_value"
],
"setters": {},
"types": {
@@ -569,7 +508,9 @@
{
"name": "Log",
"baseType": "Module",
"params": [],
"params": [
"inputSize"
],
"setters": {},
"types": {},
"defaults": {},
@@ -959,17 +900,6 @@
"defaults": {},
"type": "Misc"
},
{
"name": "PixelShuffle",
"baseType": "Module",
"params": [
"upscaleFactor"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "Power",
"baseType": "Module",
@@ -1009,17 +939,6 @@
"defaults": {},
"type": "Transfer"
},
{
"name": "ReLU6",
"baseType": "Module",
"params": [
"inplace"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Transfer"
},
{
"name": "Replicate",
"baseType": "Module",
@@ -1237,18 +1156,6 @@
"defaults": {},
"type": "Convolution"
},
{
"name": "SpatialClassNLLCriterion",
"baseType": "Criterion",
"params": [
"weights",
"sizeAverage"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Criterion"
},
{
"name": "SpatialContrastiveNormalization",
"baseType": "Module",
@@ -1372,56 +1279,6 @@
},
"type": "Convolution"
},
{
"name": "SpatialDilatedConvolution",
"baseType": "SpatialConvolution",
"params": [
"nInputPlane",
"nOutputPlane",
"kW",
"kH",
"dW",
"dH",
"padW",
"padH",
"dilationW",
"dilationH"
],
"setters": {},
"types": {
"dilationW": "number",
"dilationH": "number"
},
"defaults": {
"dilationH": 1,
"dilationW": 1
},
"type": "Convolution"
},
{
"name": "SpatialDilatedMaxPooling",
"baseType": "SpatialMaxPooling",
"params": [
"kW",
"kH",
"dW",
"dH",
"padW",
"padH",
"dilationW",
"dilationH"
],
"setters": {},
"types": {
"dilationW": "number",
"dilationH": "number"
},
"defaults": {
"dilationH": 1,
"dilationW": 1
},
"type": "Misc"
},
{
"name": "SpatialDivisiveNormalization",
"baseType": "Module",
@@ -1444,16 +1301,13 @@
"name": "SpatialDropout",
"baseType": "Module",
"params": [
"p",
"stochasticInference"
"p"
],
"setters": {},
"types": {
"p": "number",
"stochasticInference": "boolean"
"p": "number"
},
"defaults": {
"stochasticInference": false,
"p": 0.5
},
"type": "Convolution"
@@ -1533,14 +1387,6 @@
"defaults": {},
"type": "Convolution"
},
{
"name": "SpatialLogSoftMax",
"baseType": "Module",
"params": [],
"setters": {},
"defaults": {},
"type": "Misc"
},
{
"name": "SpatialMaxPooling",
"baseType": "Module",
@@ -1651,17 +1497,6 @@
},
"type": "Convolution"
},
{
"name": "SpatialUpSamplingBilinear",
"baseType": "Module",
"params": [
"params"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "SpatialUpSamplingNearest",
"baseType": "Module",
@@ -1792,22 +1627,6 @@
"defaults": {},
"type": "Convolution"
},
{
"name": "TemporalDynamicKMaxPooling",
"baseType": "Module",
"params": [
"minK",
"factor"
],
"setters": {},
"types": {
"factor": "number"
},
"defaults": {
"factor": 0
},
"type": "Misc"
},
{
"name": "TemporalMaxPooling",
"baseType": "Module",
@@ -1944,82 +1763,17 @@
},
"type": "Convolution"
},
{
"name": "VolumetricDilatedConvolution",
"baseType": "VolumetricConvolution",
"params": [
"nInputPlane",
"nOutputPlane",
"kT",
"kW",
"kH",
"dT",
"dW",
"dH",
"padT",
"padW",
"padH",
"dilationT",
"dilationW",
"dilationH"
],
"setters": {},
"types": {
"dilationT": "number",
"dilationW": "number",
"dilationH": "number"
},
"defaults": {
"dilationH": 1,
"dilationW": 1,
"dilationT": 1
},
"type": "Misc"
},
{
"name": "VolumetricDilatedMaxPooling",
"baseType": "VolumetricMaxPooling",
"params": [
"kT",
"kW",
"kH",
"dT",
"dW",
"dH",
"padT",
"padW",
"padH",
"dilationT",
"dilationW",
"dilationH"
],
"setters": {},
"types": {
"dilationT": "number",
"dilationW": "number",
"dilationH": "number"
},
"defaults": {
"dilationH": 1,
"dilationW": 1,
"dilationT": 1
},
"type": "Misc"
},
{
"name": "VolumetricDropout",
"baseType": "Module",
"params": [
"p",
"stochasticInference"
"p"
],
"setters": {},
"types": {
"p": "number",
"stochasticInference": "boolean"
"p": "number"
},
"defaults": {
"stochasticInference": false,
"p": 0.5
},
"type": "Convolution"
@@ -2110,22 +1864,6 @@
"defaults": {},
"type": "Convolution"
},
{
"name": "VolumetricReplicationPadding",
"baseType": "Module",
"params": [
"pleft",
"pright",
"ptop",
"pbottom",
"pfront",
"pback"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Misc"
},
{
"name": "WeightedEuclidean",
"baseType": "Module",
-338
Ver Arquivo
@@ -1,338 +0,0 @@
/*globals define*/
define([
'./templates/index',
'q',
'underscore',
'deepforge/Constants'
], function(
Templates,
Q,
_,
CONSTANTS
) {
var ExecuteJob = function() {
};
ExecuteJob.prototype.createOperationFiles = function (node) {
var files = {};
// For each operation, generate the output files:
// inputs/<arg-name>/init.lua (respective data deserializer)
// pointers/<name>/init.lua (result of running the main plugin on pointer target - may need a rename)
// outputs/<name>/ (make dirs for each of the outputs)
// outputs/init.lua (serializers for data outputs)
//
// attributes.lua (returns lua table of operation attributes)
// init.lua (main file -> calls main and serializes outputs)
// <name>.lua (entry point -> calls main operation code)
// add the given files
this.logger.info('About to create dist execution files');
files['start.js'] = _.template(Templates.START)(CONSTANTS);
return this.createEntryFile(node, files)
.then(() => this.createClasses(node, files))
.then(() => this.createCustomLayers(node, files))
.then(() => this.createInputs(node, files))
.then(() => this.createOutputs(node, files))
.then(() => this.createMainFile(node, files))
.then(() => {
this.createAttributeFile(node, files);
return Q.ninvoke(this, 'createPointers', node, files);
});
};
ExecuteJob.prototype.createEntryFile = function (node, files) {
this.logger.info('Creating entry files...');
return this.getOutputs(node)
.then(outputs => {
var name = this.getAttribute(node, 'name'),
content = {};
// inputs and outputs
content.name = name;
content.outputs = outputs;
files['init.lua'] = _.template(Templates.ENTRY)(content);
// Create the deepforge file
files['deepforge.lua'] = _.template(Templates.DEEPFORGE)(CONSTANTS);
});
};
ExecuteJob.prototype.createClasses = function (node, files) {
var metaDict = this.core.getAllMetaNodes(this.rootNode),
isClass,
metanodes,
classNodes,
inheritanceLvl = {},
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
isClass = this.getTypeDictFor('Complex', metanodes);
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base),
count = 1;
// Count the sets back to a class node
while (base) {
if (isClass[baseId]) {
inheritanceLvl[this.core.getPath(node)] = count;
return true;
}
base = this.core.getBase(base);
baseId = this.core.getPath(base);
count++;
}
return false;
});
// Get the code definitions for each
// Sort by levels of inheritance...
code = classNodes.sort((a, b) => {
var aId = this.core.getPath(a),
bId = this.core.getPath(b);
return inheritanceLvl[aId] > inheritanceLvl[bId];
}).map(node =>
`require './${this.getAttribute(node, 'name')}.lua'`
).join('\n');
// Create the class files
classNodes.forEach(node => {
var name = this.getAttribute(node, 'name');
files[`classes/${name}.lua`] = this.getAttribute(node, 'code');
});
// Create the custom layers file
files['classes/init.lua'] = code;
};
ExecuteJob.prototype.getTypeDictFor = function (name, metanodes) {
var isType = {};
// Get all the custom layers
for (var i = metanodes.length; i--;) {
if (this.getAttribute(metanodes[i], 'name') === name) {
isType[this.core.getPath(metanodes[i])] = true;
}
}
return isType;
};
ExecuteJob.prototype.createCustomLayers = function (node, files) {
var metaDict = this.core.getAllMetaNodes(this.rootNode),
isCustomLayer,
metanodes,
customLayers,
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
isCustomLayer = this.getTypeDictFor('CustomLayer', metanodes);
customLayers = metanodes.filter(node =>
this.core.getMixinPaths(node).some(id => isCustomLayer[id]));
// Get the code definitions for each
code = 'require \'nn\'\n\n' + customLayers
.map(node => this.getAttribute(node, 'code')).join('\n');
// Create the custom layers file
files['custom-layers.lua'] = code;
};
ExecuteJob.prototype.createInputs = function (node, files) {
var tplContents,
inputs;
this.logger.info('Retrieving inputs and deserialize fns...');
return this.getInputs(node)
.then(allInputs => {
// For each input, match the connection with the input name
// [ name, type ] => [ name, type, node ]
//
// For each input,
// - create the deserializer
// - put it in inputs/<name>/init.lua
// - copy the data asset to /inputs/<name>/init.lua
inputs = allInputs
.filter(pair => !!this.getAttribute(pair[2], 'data')); // remove empty inputs
files.inputAssets = {}; // data assets
return Q.all(inputs.map(pair => {
var name = pair[0],
node = pair[2],
nodeId = this.core.getPath(node),
fromNodeId;
// Get the deserialize function. First, try to get it from
// the source method (this guarantees that the correct
// deserialize method is used despite any auto-upcasting
fromNodeId = this.inputPortsFor[nodeId][0] || nodeId;
return this.core.loadByPath(this.rootNode, fromNodeId)
.then(fromNode => {
var deserFn,
base,
className;
deserFn = this.getAttribute(fromNode, 'deserialize');
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// (static) deserialize factory method
base = this.core.getMetaType(node);
className = this.getAttribute(base, 'name');
deserFn = `return ${className}.deserialize(path)`;
}
return {
name: name,
code: deserFn
};
});
}));
})
.then(_tplContents => {
tplContents = _tplContents;
var hashes = inputs.map(pair => {
var hash = this.getAttribute(pair[2], 'data');
files.inputAssets[pair[0]] = hash;
return {
hash: hash,
name: pair[0]
};
});
return Q.all(hashes.map(pair =>
this.blobClient.getMetadata(pair.hash)
.fail(err => this.onBlobRetrievalFail(node, pair.name, err))));
})
.then(metadatas => {
// Create the deserializer
tplContents.forEach((ctnt, i) => {
// Get the name of the given asset
ctnt.filename = metadatas[i].name;
files['inputs/' + ctnt.name + '/init.lua'] = _.template(Templates.DESERIALIZE)(ctnt);
});
return files;
});
};
ExecuteJob.prototype.createOutputs = function (node, files) {
// For each of the output types, grab their serialization functions and
// create the `outputs/init.lua` file
this.logger.info('Creating outputs/init.lua...');
return this.getOutputs(node)
.then(outputs => {
var outputTypes = outputs
// Get the serialize functions for each
.map(tuple => {
var node = tuple[2],
serFn = this.getAttribute(node, 'serialize');
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// serialize methods
serFn = 'if data ~= nil then data:serialize(path) end';
}
return [tuple[1], serFn];
});
files['outputs/init.lua'] = _.template(Templates.SERIALIZE)({types: outputTypes});
});
};
ExecuteJob.prototype.createMainFile = function (node, files) {
this.logger.info('Creating main file...');
return this.getInputs(node)
.then(inputs => {
var name = this.getAttribute(node, 'name'),
code = this.getAttribute(node, 'code'),
pointers = this.core.getPointerNames(node).filter(ptr => ptr !== 'base'),
content = {
name: name
};
// Get input data arguments
content.inputs = inputs
.map(pair => [pair[0], !this.getAttribute(pair[2], 'data')]); // remove empty inputs
// Defined variables for each pointers
content.pointers = pointers
.map(id => [id, this.core.getPointerPath(node, id) === null]);
// Add remaining code
content.code = code;
files['main.lua'] = _.template(Templates.MAIN)(content);
// Set the line offset
var lineOffset = this.getLineOffset(files['main.lua'], code);
this.setAttribute(node, CONSTANTS.LINE_OFFSET, lineOffset);
});
};
ExecuteJob.prototype.getLineOffset = function (main, snippet) {
var i = main.indexOf(snippet),
lines = main.substring(0, i).match(/\n/g);
return lines ? lines.length : 0;
};
ExecuteJob.prototype.createAttributeFile = function (node, files) {
var skip = ['code', 'stdout', 'execFiles', 'jobId', 'secret'],
numOrBool = /^(-?\d+\.?\d*((e|e-)\d+)?|(true|false))$/,
table;
this.logger.info('Creating attributes file...');
table = '{\n\t' + this.core.getAttributeNames(node)
.filter(attr => skip.indexOf(attr) === -1)
.map(name => {
var value = this.getAttribute(node, name);
if (!numOrBool.test(value)) {
value = `"${value}"`;
}
return [name, value];
})
.map(pair => pair.join(' = '))
.join(',\n\t') + '\n}';
files['attributes.lua'] = `-- attributes of ${this.getAttribute(node, 'name')}\nreturn ${table}`;
};
ExecuteJob.prototype.createPointers = function (node, files, cb) {
var pointers,
nIds;
this.logger.info('Creating pointers file...');
pointers = this.core.getPointerNames(node)
.filter(name => name !== 'base')
.filter(id => this.core.getPointerPath(node, id) !== null);
nIds = pointers.map(p => this.core.getPointerPath(node, p));
files.ptrAssets = {};
Q.all(
nIds.map(nId => this.getPtrCodeHash(nId))
)
.then(resultHashes => {
var name = this.getAttribute(node, 'name');
this.logger.info(`Pointer generation for ${name} FINISHED!`);
resultHashes.forEach((hash, index) => {
files.ptrAssets[`pointers/${pointers[index]}/init.lua`] = hash;
});
return cb(null, files);
})
.fail(e => {
this.logger.error(`Could not generate pointer files for ${this.getAttribute(node, 'name')}: ${e.toString()}`);
return cb(e);
});
};
return ExecuteJob;
});
-122
Ver Arquivo
@@ -1,122 +0,0 @@
/*globals define*/
define([
'deepforge/Constants'
], function(
CONSTANTS
) {
var ExecuteJob = function() {
};
ExecuteJob.prototype[CONSTANTS.GRAPH_CREATE] = function (job, id) {
var graph,
name = Array.prototype.slice.call(arguments, 2).join(' '),
jobId = this.core.getPath(job);
id = jobId + '/' + id;
this.logger.info(`Creating graph ${id} named ${name}`);
// Check if the graph already exists
graph = this._getExistingMetadata(jobId, 'Graph', name);
if (!graph) {
graph = this.createNode('Graph', job);
if (name) {
this.setAttribute(graph, 'name', name);
}
this.createIdToMetadataId[graph] = id;
}
this._metadata[id] = graph;
};
ExecuteJob.prototype[CONSTANTS.GRAPH_PLOT] = function (job, id, x, y) {
var jobId = this.core.getPath(job),
nonNum = /[^\d-\.]*/g,
line,
points;
id = jobId + '/' + id;
this.logger.info(`Adding point ${x}, ${y} to ${id}`);
line = this._metadata[id];
if (!line) {
this.logger.warn(`Can't add point to non-existent line: ${id}`);
return;
}
// Clean the points by removing and special characters
x = x.replace(nonNum, '');
y = y.replace(nonNum, '');
points = this.getAttribute(line, 'points');
points += `${x},${y};`;
this.setAttribute(line, 'points', points);
};
ExecuteJob.prototype[CONSTANTS.GRAPH_CREATE_LINE] = function (job, graphId, id) {
var jobId = this.core.getPath(job),
graph = this._metadata[jobId + '/' + graphId],
name = Array.prototype.slice.call(arguments, 3).join(' '),
line;
// Create a 'line' node in the given Graph metadata node
name = name.replace(/\s+$/, '');
line = this.createNode('Line', graph);
this.setAttribute(line, 'name', name);
this._metadata[jobId + '/' + id] = line;
this.createIdToMetadataId[line] = jobId + '/' + id;
};
ExecuteJob.prototype[CONSTANTS.IMAGE.BASIC] =
ExecuteJob.prototype[CONSTANTS.IMAGE.UPDATE] =
ExecuteJob.prototype[CONSTANTS.IMAGE.CREATE] = function (job, hash, imgId) {
var name = Array.prototype.slice.call(arguments, 3).join(' '),
imageNode = this._getImageNode(job, imgId, name);
this.setAttribute(imageNode, 'data', hash);
};
ExecuteJob.prototype[CONSTANTS.IMAGE.NAME] = function (job, imgId) {
var name = Array.prototype.slice.call(arguments, 2).join(' '),
imageNode = this._getImageNode(job, imgId, name);
this.setAttribute(imageNode, 'name', name);
};
ExecuteJob.prototype._getImageNode = function (job, imgId, name) {
var jobId = this.core.getPath(job),
id = jobId + '/IMAGE/' + imgId,
imageNode = this._metadata[id]; // Look for the metadata imageNode
if (!imageNode) {
// Check if the imageNode already exists
imageNode = this._getExistingMetadata(jobId, 'Image', name);
if (!imageNode) {
this.logger.info(`Creating image ${id} named ${name}`);
imageNode = this.createNode('Image', job);
this.setAttribute(imageNode, 'name', name);
this.createIdToMetadataId[imageNode] = id;
}
this._metadata[id] = imageNode;
}
return imageNode;
};
ExecuteJob.prototype._getExistingMetadata = function (jobId, type, name) {
var oldMetadata = this._oldMetadataByName[jobId] && this._oldMetadataByName[jobId][type],
node,
id;
if (oldMetadata && oldMetadata[name]) {
id = oldMetadata[name];
node = this._markForDeletion[jobId][id];
delete this._markForDeletion[jobId][id];
this.createdMetadataIds[jobId].push(id); // used for resuming jobs
}
return node || null;
};
return ExecuteJob;
});
-377
Ver Arquivo
@@ -1,377 +0,0 @@
/*globals define*/
define([
'plugin/PluginBase',
'common/storage/constants',
'q',
'common/util/assert'
], function(
PluginBase,
STORAGE_CONSTANTS,
Q,
assert
) {
var CREATE_PREFIX = 'created_node_',
INDEX = 1;
var ExecuteJob = function() {
this.forkNameBase = null;
this.runningJobHashes = [];
this._currentSave = Q();
};
ExecuteJob.prototype.getCreateId = function () {
return CREATE_PREFIX + (++INDEX);
};
ExecuteJob.prototype.isCreateId = function (id) {
return (typeof id === 'string') && (id.indexOf(CREATE_PREFIX) === 0);
};
ExecuteJob.prototype.createNode = function (baseType, parent) {
var id = this.getCreateId(),
parentId = this.isCreateId(parent) ? parent : this.core.getPath(parent);
this.logger.info(`Creating ${id} of type ${baseType} in ${parentId}`);
assert(this.META[baseType], `Cannot create node w/ unrecognized type: ${baseType}`);
this.creations[id] = {
base: baseType,
parent: parentId
};
return id;
};
ExecuteJob.prototype.deleteNode = function (nodeId) {
this.deletions.push(nodeId);
};
ExecuteJob.prototype.delAttribute = function (node, attr) {
return this.setAttribute(node, attr, null);
};
ExecuteJob.prototype.setAttribute = function (node, attr, value) {
var nodeId;
if (this.isCreateId(node)) {
nodeId = node;
} else {
nodeId = this.core.getPath(node);
assert(typeof nodeId === 'string', `Cannot set attribute of ${nodeId}`);
}
if (value !== null) {
this.logger.info(`Setting ${attr} of ${nodeId} to ${value}`);
} else {
this.logger.info(`Deleting ${attr} of ${nodeId}`);
}
if (!this.changes[nodeId]) {
this.changes[nodeId] = {};
}
this.changes[nodeId][attr] = value;
};
ExecuteJob.prototype.getAttribute = function (node, attr) {
var nodeId;
assert(this.deletions.indexOf(nodeId) === -1,
`Cannot get ${attr} from deleted node ${nodeId}`);
// Check if it was newly created
if (this.isCreateId(node)) {
nodeId = node;
assert(this.creations[nodeId], `Creation node not updated: ${nodeId}`);
node = this.META[this.creations[nodeId].base];
} else {
nodeId = this.core.getPath(node);
}
// Check the most recent changes, then the currentChanges, then the model
var value = this._getValueFrom(nodeId, attr, node, this.changes) ||
this._getValueFrom(nodeId, attr, node, this.currentChanges);
if (value) {
return value;
}
return this.core.getAttribute(node, attr);
};
ExecuteJob.prototype._getValueFrom = function (nodeId, attr, node, changes) {
var base;
if (changes[nodeId] && changes[nodeId][attr] !== undefined) {
// If deleted the attribute, get the default (inherited) value
if (changes[nodeId][attr] === null) {
base = this.isCreateId(nodeId) ? node : this.core.getBase(node);
return this.getAttribute(base, attr);
}
return changes[nodeId][attr];
}
};
ExecuteJob.prototype._applyNodeChanges = function (node, changes) {
var attr,
value;
this.logger.info(`About to apply changes for ${this.core.getPath(node)}`);
for (var i = changes.length; i--;) {
attr = changes[i][0];
value = changes[i][1];
if (value !== null) {
this.logger.info(`Setting ${attr} to ${value} (${this.core.getPath(node)})`);
this.core.setAttribute(node, attr, value);
} else {
this.core.delAttribute(node, attr);
}
}
return node;
};
ExecuteJob.prototype.applyModelChanges = function () {
return this.applyCreations()
.then(() => this.applyChanges())
.then(() => this.applyDeletions());
};
ExecuteJob.prototype.applyChanges = function () {
var nodeIds = Object.keys(this.changes),
attrs,
value,
changes,
promises = [],
changesFor = {},
id,
promise;
this.logger.info('Collecting changes to apply in commit');
for (var i = nodeIds.length; i--;) {
changes = [];
attrs = Object.keys(this.changes[nodeIds[i]]);
for (var a = attrs.length; a--;) {
value = this.changes[nodeIds[i]][attrs[a]];
changes.push([attrs[a], value]);
}
changesFor[nodeIds[i]] = changes;
assert(changes, `changes are invalid for ${nodeIds[i]}: ${changes}`);
assert(!this.isCreateId(nodeIds[i]),
`Creation id not resolved to actual id: ${nodeIds[i]}`);
promise = this.core.loadByPath(this.rootNode, nodeIds[i]);
promises.push(promise);
}
this.currentChanges = this.changes;
this.changes = {};
// Need to differentiate between read/write changes.
this.logger.info(`About to apply changes for ${promises.length} nodes`);
return Q.all(promises)
.then(nodes => {
for (var i = nodes.length; i--;) {
id = this.core.getPath(nodes[i]);
assert(nodes[i], `node is ${nodes[i]} (${nodeIds[i]})`);
this._applyNodeChanges(nodes[i], changesFor[id]);
}
// Local model is now up-to-date. No longer need currentChanges
this.currentChanges = {};
});
};
ExecuteJob.prototype.applyCreations = function () {
var nodeIds = Object.keys(this.creations),
tiers = this.createCreationTiers(nodeIds),
creations = this.creations,
newIds = {},
promise = Q(),
tier;
this.logger.info('Applying node creations');
for (var i = 0; i < tiers.length; i++) {
tier = tiers[i];
// Chain the promises, loading each tier sequentially
promise = promise.then(this.applyCreationTier.bind(this, creations, newIds, tier));
}
this.creations = {};
return promise;
};
ExecuteJob.prototype.applyCreationTier = function (creations, newIds, tier) {
var promises = [],
parentId,
node;
for (var j = tier.length; j--;) {
node = creations[tier[j]];
assert(node, `Could not find create info for ${tier[j]}`);
parentId = newIds[node.parent] || node.parent;
promises.push(this.applyCreation(tier[j], node.base, parentId));
}
return Q.all(promises).then(nodes => {
// Record the newIds so they can be used to resolve creation ids
// in subsequent tiers
for (var i = tier.length; i--;) {
newIds[tier[i]] = this.core.getPath(nodes[i]);
}
});
};
// Figure out the dependencies between nodes to create.
// eg, if newId1 is to be created in newId2, then newId2 will
// be in an earlier tier than newId1. Essentially a topo-sort
// on a tree structure
ExecuteJob.prototype.createCreationTiers = function (nodeIds) {
var tiers = [],
prevTier = {},
tier = {},
id,
prevLen,
i;
// Create first tier (created inside existing nodes)
for (i = nodeIds.length; i--;) {
id = nodeIds[i];
if (!this.isCreateId(this.creations[id].parent)) {
tier[id] = true;
nodeIds.splice(i, 1);
}
}
prevTier = tier;
tiers.push(Object.keys(tier));
// Now, each tier consists of the nodes to be created inside a
// node from the previous tier
while (nodeIds.length) {
prevLen = nodeIds.length;
tier = {};
for (i = nodeIds.length; i--;) {
id = nodeIds[i];
if (prevTier[this.creations[id].parent]) {
tier[id] = true;
nodeIds.splice(i, 1);
}
}
prevTier = tier;
tiers.push(Object.keys(tier));
// Every iteration should find at least one node
assert(prevLen > nodeIds.length,
`Created empty create tier! Remaining: ${nodeIds.join(', ')}`);
}
return tiers;
};
ExecuteJob.prototype.applyCreation = function (tmpId, baseType, parentId) {
var base = this.META[baseType],
nodeId,
id;
this.logger.info(`Applying creation of ${tmpId} (${baseType}) in ${parentId}`);
assert(!this.isCreateId(parentId),
`Did not resolve parent id: ${parentId} for ${tmpId}`);
assert(base, `Invalid base type: ${baseType}`);
return this.core.loadByPath(this.rootNode, parentId)
.then(parent => this.core.createNode({base, parent}))
.then(node => { // Update the _metadata records
id = this.createIdToMetadataId[tmpId];
delete this.createIdToMetadataId[tmpId];
this._metadata[id] = node;
// Update creations
nodeId = this.core.getPath(node);
if (this.changes[tmpId]) {
assert(!this.changes[nodeId],
`Newly created node cannot already have changes! (${nodeId})`);
this.changes[nodeId] = this.changes[tmpId];
delete this.changes[tmpId];
}
return node;
});
};
ExecuteJob.prototype.applyDeletions = function () {
var deletions = this.deletions;
this.deletions = [];
return Q.all(deletions.map(id => this.core.loadByPath(this.rootNode, id)))
.then(nodes => {
for (var i = nodes.length; i--;) {
this.core.deleteNode(nodes[i]);
}
});
};
// Override 'save' to notify the user on fork
ExecuteJob.prototype.save = function (msg) {
this._currentSave = this._currentSave
.then(() => this.updateForkName(this.forkNameBase))
.then(() => this.applyModelChanges())
.then(() => PluginBase.prototype.save.call(this, msg))
.then(result => {
this.logger.info(`Save finished w/ status: ${result.status}`);
if (result.status === STORAGE_CONSTANTS.FORKED) {
return this.onSaveForked(result.forkName);
} else if (result.status === STORAGE_CONSTANTS.MERGED) {
this.logger.debug('Merged changes. About to update plugin nodes');
return this.updateNodes();
}
});
return this._currentSave;
};
ExecuteJob.prototype.onSaveForked = function (forkName) {
var name = this.getAttribute(this.activeNode, 'name'),
msg = `"${name}" execution has forked to "${forkName}"`;
this.currentForkName = forkName;
this.logManager.fork(forkName);
this.runningJobHashes.forEach(jobId => this.originManager.fork(jobId, forkName));
this.sendNotification(msg);
};
ExecuteJob.prototype.updateNodes = function (hash) {
var activeId = this.core.getPath(this.activeNode);
hash = hash || this.currentHash;
return Q.ninvoke(this.project, 'loadObject', hash)
.then(commitObject => {
return this.core.loadRoot(commitObject.root);
})
.then(rootObject => {
this.rootNode = rootObject;
return this.core.loadByPath(rootObject,activeId);
})
.then(activeObject => this.activeNode = activeObject)
.then(() => {
var metaNames = Object.keys(this.META);
return Q.all(metaNames.map(name => this.updateMetaNode(name)));
})
.then(() => {
var mdNodes,
mdIds;
mdIds = Object.keys(this._metadata)
.filter(id => !this.isCreateId(this._metadata[id]));
mdNodes = mdIds.map(id => this.core.getPath(this._metadata[id]))
.map(nodeId => this.core.loadByPath(this.rootNode, nodeId));
return Q.all(mdNodes).then(nodes => {
for (var i = nodes.length; i--;) {
this._metadata[mdIds[i]] = nodes[i];
}
});
});
};
ExecuteJob.prototype.updateMetaNode = function (name) {
var id = this.core.getPath(this.META[name]);
return this.core.loadByPath(this.rootNode, id).then(node => this.META[name] = node);
};
return ExecuteJob;
});
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+78 -167
Ver Arquivo
@@ -4,17 +4,17 @@
define([
'plugin/CreateExecution/CreateExecution/CreateExecution',
'plugin/ExecuteJob/ExecuteJob/ExecuteJob',
'deepforge/JobLogsClient',
'common/storage/constants',
'common/core/constants',
'deepforge/Constants',
'q',
'text!./metadata.json',
'underscore'
], function (
CreateExecution,
ExecuteJob,
JobLogsClient,
STORAGE_CONSTANTS,
GME_CONSTANTS,
CONSTANTS,
Q,
pluginMetadata,
@@ -33,9 +33,9 @@ define([
var ExecutePipeline = function () {
// Call base class' constructor.
CreateExecution.call(this);
ExecuteJob.call(this);
this.pluginMetadata = pluginMetadata;
this._currentSave = Q();
this.changes = {};
this.currentChanges = {}; // read-only changes being applied
this.creations = {};
@@ -101,8 +101,7 @@ define([
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
ExecutePipeline.prototype.main = function (callback) {
var startPromise,
runId;
var startPromise;
this.initRun();
if (this.core.isTypeOf(this.activeNode, this.META.Pipeline)) {
@@ -119,133 +118,58 @@ define([
return callback('Current node is not a Pipeline or Execution!', this.result);
}
// Get the gmeConfig...
this.logManager = new JobLogsClient({
logger: this.logger,
port: this.gmeConfig.server.port,
branchName: this.branchName,
projectId: this.projectId
});
this._callback = callback;
this.currentForkName = null;
startPromise
.then(() => this.core.loadSubTree(this.activeNode))
.then(subtree => {
var children;
.then(() => this.core.loadSubTree(this.activeNode))
.then(subtree => {
var children = subtree
.filter(n => this.core.getParent(n) === this.activeNode);
children = subtree
.filter(n => this.core.getParent(n) === this.activeNode);
this.pipelineName = this.getAttribute(this.activeNode, 'name');
this.logger.debug(`Loaded subtree of ${this.pipelineName}. About to build cache`);
this.buildCache(subtree);
this.logger.debug('Parsing execution for job inter-dependencies');
this.parsePipeline(children); // record deps, etc
this.pipelineName = this.getAttribute(this.activeNode, 'name');
this.forkNameBase = this.pipelineName;
this.logger.debug(`Loaded subtree of ${this.pipelineName}. About to build cache`);
this.buildCache(subtree);
this.logger.debug('Parsing execution for job inter-dependencies');
this.parsePipeline(children); // record deps, etc
// Detect if resuming execution
runId = this.getAttribute(this.activeNode, 'runId');
return this.isResuming().then(resuming => {
if (resuming) {
this.currentRunId = runId;
this.startExecHeartBeat();
return this.resumePipeline();
}
return this.startPipeline();
});
})
.fail(e => this.logger.error(e));
this.logger.debug('Clearing old results');
return this.clearResults();
})
.then(() => this.executePipeline())
.fail(e => this.logger.error(e));
};
ExecutePipeline.prototype.isResuming = function () {
var currentlyRunning = this.getAttribute(this.activeNode, 'status') === 'running',
runId = this.getAttribute(this.activeNode, 'runId');
if (runId && currentlyRunning) {
// Verify that it is on the correct branch
return this.originManager.getOrigin(runId)
.then(origin => {
if (origin && origin.branch === this.branchName) {
return this.pulseClient.check(runId)
// If it is dead (not unknown!), then resume
.then(status => status === CONSTANTS.PULSE.DEAD);
} else {
return false;
}
});
}
return Q().then(() => false);
};
ExecutePipeline.prototype.resumePipeline = function () {
var nodes = Object.keys(this.nodes).map(id => this.nodes[id]),
allJobs = nodes.filter(node => this.core.isTypeOf(node, this.META.Job)),
status,
jobs = {
success: [],
failed: [],
running: [],
pending: []
};
this.logger.info(`Resuming pipeline execution: ${this.currentRunId}`);
// Get all completed jobs' operations and update records for these
for (var i = allJobs.length; i--;) {
status = this.getAttribute(allJobs[i], 'status');
if (!jobs[status]) {
jobs[status] = [];
}
// If any running jobs are missing jobIds, set them to pending
if (status === 'running' && !this.canResumeJob(allJobs[i])) {
jobs.pending.push(allJobs[i]);
} else {
jobs[status].push(allJobs[i]);
}
}
// Remove finished jobs from incomingCounts
jobs.success.concat(jobs.failed, jobs.running)
.map(job => this.core.getPath(job))
.forEach(id => delete this.incomingCounts[id]);
return Q.all(allJobs.map(job => this.recordOldMetadata(job, true)))
.then(() => Q.all(jobs.success.map(job => this.getOperation(job))))
.then(ops => ops.forEach(op => this.updateJobCompletionRecords(op)))
.then(() => {
if (jobs.running.length) { // Resume all running jobs
return Q.all(jobs.running.map(job => this.resumeJob(job)));
} else if (this.completedCount === this.totalCount) {
return this.onPipelineComplete();
} else {
// If none are running, try to start the next ones
return this.executeReadyOperations();
// Override 'save' to prevent race conditions while saving
ExecutePipeline.prototype.save = function (msg) {
// When 'save' is called, it should still finish any current save op
// before continuing
this._currentSave = this._currentSave
.then(() => this.updateForkName(this.pipelineName))
.then(() => this.applyModelChanges())
.then(() => CreateExecution.prototype.save.call(this, msg))
.then(result => {
var msg;
if (result.status === STORAGE_CONSTANTS.FORKED) {
this.currentForkName = result.forkName;
this.logManager.fork(result.forkName);
msg = `"${this.pipelineName}" execution has forked to "${result.forkName}"`;
this.sendNotification(msg);
} else if (result.status === STORAGE_CONSTANTS.MERGED) {
this.logger.debug('Merged changes. About to update plugin nodes');
return this.updateNodes();
}
})
.fail(err => this._callback(err));
};
ExecutePipeline.prototype.startPipeline = function () {
var rand = Math.floor(Math.random()*10000),
commit = this.commitHash.replace('#', '');
});
this.logger.debug('Clearing old results');
this.currentRunId = `Pipeline_${commit}_${Date.now()}_${rand}`;
// Record the execution origin
this.originManager.record(this.currentRunId, {
nodeId: this.core.getPath(this.activeNode),
job: 'N/A',
execution: this.getAttribute(this.activeNode, 'name')
});
this.startExecHeartBeat();
return this.clearResults()
.then(() => this.executePipeline())
.fail(e => this.logger.error(e));
};
ExecutePipeline.prototype.onSaveForked = function (forkName) {
// Update the origin on fork
this.originManager.fork(this.currentRunId, forkName);
return ExecuteJob.prototype.onSaveForked.call(this, forkName);
return this._currentSave;
};
ExecutePipeline.prototype.updateNodes = function (hash) {
@@ -296,7 +220,6 @@ define([
this.logger.info('Setting all jobs status to "pending"');
this.logger.debug(`Making a commit from ${this.currentHash}`);
this.setAttribute(this.activeNode, 'startTime', Date.now());
this.setAttribute(this.activeNode, 'runId', this.currentRunId);
this.core.delAttribute(this.activeNode, 'endTime');
return this.save(`Initializing ${this.pipelineName} for execution`);
};
@@ -374,10 +297,10 @@ define([
};
ExecutePipeline.prototype.getSiblingIdContaining = function (nodeId) {
var parentId = this.core.getPath(this.activeNode) + GME_CONSTANTS.PATH_SEP,
var parentId = this.core.getPath(this.activeNode) + CONSTANTS.PATH_SEP,
relid = nodeId.replace(parentId, '');
return parentId + relid.split(GME_CONSTANTS.PATH_SEP).shift();
return parentId + relid.split(CONSTANTS.PATH_SEP).shift();
};
ExecutePipeline.prototype.executePipeline = function() {
@@ -435,8 +358,7 @@ define([
msg += 'finished!';
}
return this.isDeleted().then(isDeleted => {
this.stopExecHeartBeat();
this.isDeleted().then(isDeleted => {
if (!isDeleted) {
this.logger.debug(`Pipeline "${name}" complete!`);
@@ -519,9 +441,10 @@ define([
ExecutePipeline.prototype.onOperationComplete = function (opNode) {
var name = this.getAttribute(opNode, 'name'),
nextPortIds = this.getOperationOutputIds(opNode),
jNode = this.core.getParent(opNode),
resultPorts,
jobId = this.core.getPath(jNode),
counts,
hasReadyOps;
// Set the operation to 'success'!
@@ -534,9 +457,35 @@ define([
this.save(`Operation "${name}" in ${this.pipelineName} completed successfully`)
.then(() => {
counts = this.updateJobCompletionRecords(opNode);
hasReadyOps = counts.indexOf(0) > -1;
// Transport the data from the outputs to any connected inputs
// - Get all the connections from each outputId
// - Get the corresponding dst outputs
// - Use these new ids for checking 'hasReadyOps'
resultPorts = nextPortIds.map(id => this.inputPortsFor[id])
.reduce((l1, l2) => l1.concat(l2), []);
resultPorts
.map((id, i) => [this.nodes[id], this.nodes[nextPortIds[i]]])
.forEach(pair => { // [ resultPort, nextPort ]
var result = pair[0],
next = pair[1],
hash = this.getAttribute(result, 'data');
this.logger.info(`forwarding data (${hash}) from ${this.core.getPath(result)} ` +
`to ${this.core.getPath(next)}`);
this.setAttribute(next, 'data', hash);
this.logger.info(`Setting ${jobId} data to ${hash}`);
});
// For all the nextPortIds, decrement the corresponding operation's incoming counts
hasReadyOps = nextPortIds.map(id => this.getSiblingIdContaining(id))
.reduce((l1, l2) => l1.concat(l2), [])
// decrement the incoming counts for each operation id
.map(opId => --this.incomingCounts[opId])
.indexOf(0) > -1;
this.completedCount++;
this.logger.debug(`Operation "${name}" completed. ` +
`${this.totalCount - this.completedCount} remaining.`);
if (hasReadyOps) {
@@ -547,47 +496,9 @@ define([
});
};
ExecutePipeline.prototype.updateJobCompletionRecords = function (opNode) {
var nextPortIds = this.getOperationOutputIds(opNode),
resultPorts,
counts;
// Transport the data from the outputs to any connected inputs
// - Get all the connections from each outputId
// - Get the corresponding dst outputs
// - Use these new ids for checking 'hasReadyOps'
resultPorts = nextPortIds.map(id => this.inputPortsFor[id]) // dst -> src port
.reduce((l1, l2) => l1.concat(l2), []);
resultPorts
.map((id, i) => [this.nodes[id], this.nodes[nextPortIds[i]]])
.forEach(pair => { // [ resultPort, nextPort ]
var result = pair[0],
next = pair[1],
hash = this.getAttribute(result, 'data');
this.logger.info(`forwarding data (${hash}) from ${this.core.getPath(result)} ` +
`to ${this.core.getPath(next)}`);
this.setAttribute(next, 'data', hash);
//this.logger.info(`Setting ${jobId} data to ${hash}`);
});
// For all the nextPortIds, decrement the corresponding operation's incoming counts
counts = nextPortIds.map(id => this.getSiblingIdContaining(id))
.reduce((l1, l2) => l1.concat(l2), [])
// decrement the incoming counts for each operation id
.map(opId => --this.incomingCounts[opId]);
this.completedCount++;
return counts;
};
ExecutePipeline.prototype.getOperationOutputIds = function(node) {
var jobId = this.getSiblingIdContaining(this.core.getPath(node));
// Map the job to it's output ports
return this.outputsOf[jobId] || [];
};
@@ -86,7 +86,6 @@ define([
});
this.core.setAttribute(dataNode, 'data', hash);
this.core.setAttribute(dataNode, 'createdAt', Date.now());
baseName = this.core.getAttribute(baseType, 'name');
var getName;
+2 -27
Ver Arquivo
@@ -41,20 +41,6 @@ define([
return '{' + strings.join(', ') + '}';
};
var getAttributeString = function(value, layerType) {
if (value instanceof lua.types.LuaTable) {
if (value.get('_node')) {
throw Error(`Detected unsupported varargs (composed of layers) for ${layerType}`);
}
return stringify(value);
} else if ((typeof value) === 'object') {
// special lua.js object
value = value.valueOf();
}
return value;
};
var allConnectedTo = function(current) {
var connectedIds = {},
node,
@@ -118,8 +104,7 @@ define([
cntr,
layer,
cntrName,
value,
i;
value;
if (this._cachedNode) {
// only generate a single node for each layer
@@ -132,17 +117,7 @@ define([
parent: parent
});
// merge all the last arguments into a single one (ie, assume the last
// attribute is varargs
if (this._attrs.length < this._values.length) {
i = this._attrs.length;
value = this._values.splice(i-1)
.map(val => getAttributeString(val, this._base)).join(', ');
this._values.push(value);
}
// Add the attributes to the layer
for (i = this._attrs.length; i--;) {
for (var i = this._attrs.length; i--;) {
name = this._attrs[i].name;
value = this._values[i];
@@ -84,27 +84,19 @@ define([
.fail(err => callback(err, this.result));
};
UpdateLibrarySeed.prototype.bumpVersion = function (rawVersion, releaseType) {
var vnames = ['major', 'minor', 'patch'],
bumpIndex = vnames.indexOf(releaseType),
version = rawVersion.split('.').map(num => parseInt(num));
version[bumpIndex]++;
// zero out the smaller numbers
while (++bumpIndex < version.length) {
version[bumpIndex] = 0;
}
return version.join('.');
};
UpdateLibrarySeed.prototype.getLibraryVersion = function () {
var version,
config = this.getCurrentConfig(),
vnames = ['major', 'minor', 'patch'],
bumpIndex,
newVersion;
version = (this.core.getAttribute(this.rootNode, 'version') || '0.0.0');
newVersion = this.bumpVersion(version, config.releaseType);
version = (this.core.getAttribute(this.rootNode, 'version') || '0.0.0')
.split('.').map(num => parseInt(num));
bumpIndex = vnames.indexOf(config.releaseType);
version[bumpIndex]++;
newVersion = version.join('.');
this.core.setAttribute(this.rootNode, 'version', newVersion);
return this.save(`Bumped version to ${newVersion}`).then(() => newVersion);
};
-131
Ver Arquivo
@@ -1,131 +0,0 @@
/*jshint node:true*/
// This is a REST endpoint keeping track of the heartbeats of each execution. This
// allows detection of "disconnected" executions (enabling the reconnection of the
// executions - issue #821)
'use strict';
var express = require('express'),
MONGO_COLLECTION = 'ExecPulse',
CONSTANTS = require('../../common/Constants').PULSE,
mongo,
storage,
router = express.Router();
/**
* Called when the server is created but before it starts to listening to incoming requests.
* N.B. gmeAuth, safeStorage and workerManager are not ready to use until the start function is called.
* (However inside an incoming request they are all ensured to have been initialized.)
*
* @param {object} middlewareOpts - Passed by the webgme server.
* @param {GmeConfig} middlewareOpts.gmeConfig - GME config parameters.
* @param {GmeLogger} middlewareOpts.logger - logger
* @param {function} middlewareOpts.ensureAuthenticated - Ensures the user is authenticated.
* @param {function} middlewareOpts.getUserId - If authenticated retrieves the userId from the request.
* @param {object} middlewareOpts.gmeAuth - Authorization module.
* @param {object} middlewareOpts.safeStorage - Accesses the storage and emits events (PROJECT_CREATED, COMMIT..).
* @param {object} middlewareOpts.workerManager - Spawns and keeps track of "worker" sub-processes.
*/
function initialize(middlewareOpts) {
var logger = middlewareOpts.logger.fork('ExecPulse'),
ensureAuthenticated = middlewareOpts.ensureAuthenticated,
STALE_THRESHOLD = 7500;
storage = require('../storage')(logger, middlewareOpts.gmeConfig);
logger.debug('initializing ...');
// Ensure authenticated can be used only after this rule.
router.use('*', function (req, res, next) {
res.setHeader('X-WebGME-Media-Type', 'webgme.v1');
next();
});
// Use ensureAuthenticated if the routes require authentication. (Can be set explicitly for each route.)
router.use('*', ensureAuthenticated);
router.get('/', function (req, res) {
mongo.find().toArray((err, all) => {
if (err) {
return res.status(500).send(err);
}
res.json(all.map(entry => {
delete entry._id;
return entry;
}));
});
});
router.get('/:hash', function (req, res) {
// Check if the given job is alive (has a valid heartbeat).
// If the data doesn't exist, then it is considered alive
if (!req.params.hash) {
return res.status(400).send('Missing hash');
}
logger.debug('getting pulse of ', req.params.hash);
mongo.findOne({hash: req.params.hash})
.then(job => {
var current = Date.now(),
result = CONSTANTS.DOESNT_EXIST;
if (job) {
result = (current - job.timestamp) < STALE_THRESHOLD ?
CONSTANTS.ALIVE : CONSTANTS.DEAD;
}
return res.status(200).send(result.toString());
});
});
router.post('/:hash', function (req, res) {
var timestamp = Date.now(),
job = {
hash: req.params.hash,
timestamp: timestamp
};
// Validate the input
logger.debug('Received heartbeat for ', job.hash);
if (!job.hash) {
return res.status(400).send('Missing hash');
}
// Delete the given job from the database
mongo.update({hash: job.hash}, job, {upsert: true})
.then(() => res.sendStatus(201));
});
router.delete('/:hash', function (req, res) {
// Delete the given job from the database
return mongo.findOneAndDelete({hash: req.params.hash})
.then(() => res.sendStatus(204));
});
logger.debug('ready');
}
/**
* Called before the server starts listening.
* @param {function} callback
*/
function start(callback) {
storage.then(db => {
mongo = db.collection(MONGO_COLLECTION);
callback();
});
}
/**
* Called after the server stopped listening.
* @param {function} callback
*/
function stop(callback) {
callback();
}
module.exports = {
initialize: initialize,
router: router,
start: start,
stop: stop
};
+3 -3
Ver Arquivo
@@ -71,7 +71,7 @@ JobLogManager.prototype.migrate = function(migrationInfo, jobIds) {
}
// Copy the job files and evaluate each of the finish functions
this.logger.debug('migrating from ' + migrationInfo.srcBranch + ' to '+ migrationInfo.dstBranch);
this.logger.info('migrating from ' + migrationInfo.srcBranch + ' to '+ migrationInfo.dstBranch);
return Q.all(jobIds.map(jobId => {
src = this._getFilePath({
project: migrationInfo.project,
@@ -112,7 +112,7 @@ JobLogManager.prototype.appendTo = function(jobInfo, logs) {
branchDirname = path.dirname(filename),
projDirname = path.dirname(branchDirname);
this.logger.debug(`Appending content to ${filename}`);
this.logger.info(`Appending content to ${filename}`);
// Make directory if needed
return this.mkdirIfNeeded(this.rootDir)
.then(() => this.mkdirIfNeeded(projDirname))
@@ -142,7 +142,7 @@ JobLogManager.prototype.delete = function(jobInfo) {
this.logger.debug(`Removing file ${filename}`);
return Q.nfcall(fs.unlink, filename);
}
this.logger.debug(`${filename} doesn't exist. No need to delete...`);
this.logger.info(`${filename} doesn't exist. No need to delete...`);
});
};
+5 -42
Ver Arquivo
@@ -4,10 +4,7 @@
var express = require('express'),
JobLogManager = require('./JobLogManager'),
MONGO_COLLECTION = 'JobLogsMetadata',
mongo,
router = express.Router(),
storage;
router = express.Router();
/**
* Called when the server is created but before it starts to listening to incoming requests.
@@ -30,7 +27,6 @@ function initialize(middlewareOpts) {
logManager = new JobLogManager(logger, gmeConfig);
logger.debug('initializing ...');
storage = require('../storage')(logger, gmeConfig);
// Ensure authenticated can be used only after this rule.
router.use('*', function (req, res, next) {
@@ -50,45 +46,16 @@ function initialize(middlewareOpts) {
});
});
router.get('/metadata/:project/:branch/:job', function (req, res/*, next*/) {
return mongo.findOne(req.params)
.then(info => {
var lineCount = info ? info.lineCount : -1;
return res.json({
lineCount: lineCount
});
});
});
router.patch('/:project/:branch/:job', function (req, res/*, next*/) {
var logs = req.body.patch;
logger.info(`Received append request for ${req.params.job} in ${req.params.project}`);
return logManager.appendTo(req.params, logs)
.then(() => {
if (req.body.lineCount || req.body.cmdCount || req.body.createdIds) {
var info = {
project: req.params.project,
branch: req.params.branch,
job: req.params.job,
lineCount: req.body.lineCount || -1,
createdIds: req.body.createdIds || [],
cmdCount: req.body.cmdCount || 0
};
logger.debug('metadata is', info);
return mongo.update(req.params, info, {upsert: true})
.then(() => res.send('Append successful'));
} else {
res.send('Append successful');
}
})
logManager.appendTo(req.params, logs)
.then(() => res.send('Append successful'))
.catch(err => logger.error(`Append failed: ${err}`));
});
router.delete('/:project/:branch/:job', function (req, res/*, next*/) {
logManager.delete(req.params)
.then(() => mongo.findOneAndDelete(req.params))
.then(() => res.status(204).send('delete successful'));
logManager.delete(req.params).then(() => res.send('delete successful'));
});
router.post('/migrate/:project/:srcBranch/:dstBranch', function (req, res/*, next*/) {
@@ -106,11 +73,7 @@ function initialize(middlewareOpts) {
* @param {function} callback
*/
function start(callback) {
storage.then(db => {
mongo = db.collection(MONGO_COLLECTION);
callback();
});
callback();
}
/**
-162
Ver Arquivo
@@ -1,162 +0,0 @@
/*jshint node:true*/
'use strict';
var express = require('express'),
MONGO_COLLECTION = 'JobOrigins',
utils = require('../utils'),
mongo,
router = express.Router(),
storage;
/**
* Called when the server is created but before it starts to listening to incoming requests.
* N.B. gmeAuth, safeStorage and workerManager are not ready to use until the start function is called.
* (However inside an incoming request they are all ensured to have been initialized.)
*
* @param {object} middlewareOpts - Passed by the webgme server.
* @param {GmeConfig} middlewareOpts.gmeConfig - GME config parameters.
* @param {GmeLogger} middlewareOpts.logger - logger
* @param {function} middlewareOpts.ensureAuthenticated - Ensures the user is authenticated.
* @param {function} middlewareOpts.getUserId - If authenticated retrieves the userId from the request.
* @param {object} middlewareOpts.gmeAuth - Authorization module.
* @param {object} middlewareOpts.safeStorage - Accesses the storage and emits events (PROJECT_CREATED, COMMIT..).
* @param {object} middlewareOpts.workerManager - Spawns and keeps track of "worker" sub-processes.
*/
// When testing, use in memory storage...
function initialize(middlewareOpts) {
var logger = middlewareOpts.logger.fork('JobOriginAPI'),
gmeConfig = middlewareOpts.gmeConfig,
ensureAuthenticated = middlewareOpts.ensureAuthenticated,
REQUIRED_FIELDS = ['hash', 'project', 'execution', 'job', 'nodeId', 'branch'];
storage = require('../storage')(logger, gmeConfig);
logger.debug('initializing ...');
// Ensure authenticated can be used only after this rule.
router.use('*', function (req, res, next) {
// This header ensures that any failures with authentication won't redirect.
res.setHeader('X-WebGME-Media-Type', 'webgme.v1');
next();
});
// Use ensureAuthenticated if the routes require authentication. (Can be set explicitly for each route.)
router.use('*', ensureAuthenticated);
// Connect to mongo...
router.get('/', function (req, res) {
mongo.find().toArray((err, all) => {
if (err) {
return res.status(500).send(err);
}
res.json(all.map(entry => {
delete entry._id;
return entry;
}));
});
});
router.get('/:jobHash', function (req, res/*, next*/) {
var hash = req.params.jobHash,
jobInfo = {};
mongo.findOne({hash: hash})
.then(result => {
if (result) {
// Filter the result object
for (var i = REQUIRED_FIELDS.length; i--;) {
jobInfo[REQUIRED_FIELDS[i]] = result[REQUIRED_FIELDS[i]];
}
return res.json(jobInfo);
}
res.sendStatus(404);
})
.catch(err => {
logger.error(`Storing job info failed: ${err}`);
res.status(500).send(err);
});
});
router.post('/:jobHash', function (req, res/*, next*/) {
var hash = req.params.jobHash,
jobInfo = {
hash: hash,
project: req.body.project,
execution: req.body.execution,
branch: req.body.branch,
job: req.body.job, // job name
nodeId: req.body.nodeId
};
// Check that none of the fields are undefined
var missing = utils.getMissingField(jobInfo, REQUIRED_FIELDS);
if (missing) {
return res.status(400).send(`Missing required field: ${missing}`);
}
logger.debug(`Storing job info for ${hash}`);
return mongo.insertOne(jobInfo)
.then(() => res.sendStatus(201))
.catch(err => {
logger.error(`Storing job info failed: ${err}`);
res.status(500).send(err.toString());
});
});
router.delete('/:jobHash', function (req, res/*, next*/) {
var hash = req.params.jobHash;
mongo.findOneAndDelete({hash: hash})
.then(() => res.sendStatus(204));
});
// on fork
router.patch('/:jobHash', function (req, res) {
var hash = req.params.jobHash;
if (!req.body.branch) {
return res.status(400).send('Missing "branch" field');
}
return mongo.findOneAndUpdate({hash: hash}, {$set: {branch: req.body.branch}})
.then(() => {
logger.debug('Finished updateOne!');
res.sendStatus(200);
})
.catch(err => {
logger.error(`Job update failed: ${err}`);
res.status(500).send(err);
});
});
logger.debug('ready');
}
/**
* Called before the server starts listening.
* @param {function} callback
*/
function start(callback) {
storage.then(db => {
mongo = db.collection(MONGO_COLLECTION);
callback();
});
}
/**
* Called after the server stopped listening.
* @param {function} callback
*/
function stop(callback) {
callback();
}
module.exports = {
initialize: initialize,
router: router,
start: start,
stop: stop
};
-19
Ver Arquivo
@@ -1,19 +0,0 @@
// Get a mongodb connection
var mongodb = require('mongodb'),
connection;
module.exports = function(logger, gmeConfig) {
if (!connection) {
connection = mongodb.MongoClient.connect(gmeConfig.mongo.uri, gmeConfig.mongo.options)
.then(db => {
logger.debug('Connected to mongo!');
return db;
})
.catch(err => {
logger.error(`Could not connect to mongo: ${err}`);
throw err;
});
}
return connection;
};
-10
Ver Arquivo
@@ -1,10 +0,0 @@
module.exports = {
getMissingField: function(array, fields) {
for (var i = fields.length; i--;) {
if (!array[fields[i]]) {
return fields[i];
}
}
return null;
}
};
Arquivo binário não exibido.
Arquivo binário não exibido.
+1 -1
Ver Arquivo
@@ -1 +1 @@
0.4.0
0.2.0
Arquivo binário não exibido.
+1 -1
Ver Arquivo
@@ -1 +1 @@
0.4.0
0.3.0
Arquivo binário não exibido.
+3 -51
Ver Arquivo
@@ -31,8 +31,8 @@
},
{
"id": "RootViz",
"title": "ForwardViz",
"panel": "panels/ForwardViz/ForwardVizPanel",
"title": "MainView",
"panel": "panels/MainView/MainViewPanel",
"DEBUG_ONLY": false
},
{
@@ -71,30 +71,6 @@
"panel": "panels/PipelineIndex/PipelineIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "ArchitectureIndex",
"title": "ArchitectureIndex",
"panel": "panels/ArchIndex/ArchIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "OperationIndex",
"title": "OperationIndex",
"panel": "js/Panels/ModelEditor/ModelEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "LayerIndex",
"title": "LayerIndex",
"panel": "js/Panels/ModelEditor/ModelEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "DataTypeIndex",
"title": "DataTypeIndex",
"panel": "js/Panels/ModelEditor/ModelEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "JobEditor",
"title": "JobEditor",
@@ -124,29 +100,5 @@
"title": "ExecutionIndex",
"panel": "panels/ExecutionIndex/ExecutionIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "WorkerHeader",
"title": "WorkerHeader",
"panel": "panels/WorkerHeader/WorkerHeaderPanel",
"DEBUG_ONLY": false
},
{
"id": "ArtifactIndex",
"title": "ArtifactIndex",
"panel": "panels/ArtifactIndex/ArtifactIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "ArchIndex",
"title": "ArchIndex",
"panel": "panels/ArchIndex/ArchIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "ForwardViz",
"title": "ForwardViz",
"panel": "panels/ForwardViz/ForwardVizPanel",
"DEBUG_ONLY": false
}
]
]
@@ -4,14 +4,14 @@
define([
'deepforge/Constants',
'deepforge/globals',
'deepforge/viz/panels/ThumbnailControl',
'panels/EasyDAG/EasyDAGControl',
'js/NodePropertyNames',
'js/Utils/ComponentSettings',
'underscore'
], function (
Constants,
DeepForge,
ThumbnailControl,
EasyDAGControl,
nodePropertyNames,
ComponentSettings,
_
@@ -32,12 +32,12 @@ define([
};
ArchEditorControl = function (options) {
ThumbnailControl.call(this, options);
EasyDAGControl.call(this, options);
this._config = DEFAULT_CONFIG;
ComponentSettings.resolveWithWebGMEGlobal(this._config, this.getComponentId());
};
_.extend(ArchEditorControl.prototype, ThumbnailControl.prototype);
_.extend(ArchEditorControl.prototype, EasyDAGControl.prototype);
ArchEditorControl.prototype.TERRITORY_RULE = {children: 1};
ArchEditorControl.prototype.DEFAULT_DECORATOR = 'LayerDecorator';
@@ -46,7 +46,7 @@ define([
};
ArchEditorControl.prototype.selectedObjectChanged = function(id) {
ThumbnailControl.prototype.selectedObjectChanged.call(this, id);
EasyDAGControl.prototype.selectedObjectChanged.call(this, id);
DeepForge.last.Architecture = id;
if (typeof id === 'string') {
@@ -56,8 +56,7 @@ define([
};
ArchEditorControl.prototype._getObjectDescriptor = function(id) {
var node = this._client.getNode(id),
desc = ThumbnailControl.prototype._getObjectDescriptor.call(this, id);
var desc = EasyDAGControl.prototype._getObjectDescriptor.call(this, id);
// Filter attributes
if (!desc.isConnection) {
@@ -79,7 +78,7 @@ define([
for (i = names.length; i--;) {
// check if it is a setter
schema = node.getAttributeMeta(names[i]);
schema = this._client.getAttributeSchema(id, names[i]);
if (names[i] === 'name' || schema.setterType) {
desc.attributes[names[i]] = allAttrs[names[i]];
}
@@ -88,7 +87,8 @@ define([
// Add layer type (base class's base class)
desc.layerType = null;
if (desc.baseName) {
var base = this._client.getNode(node.getMetaTypeId()),
var node = this._client.getNode(id),
base = this._client.getNode(node.getMetaTypeId()),
layerType = this._client.getNode(base.getBaseId()),
color;
@@ -109,19 +109,30 @@ define([
};
////////////////////////// Layer Selection Logic //////////////////////////
ArchEditorControl.prototype.getValidSuccessors =
ArchEditorControl.prototype._getValidInitialNodes = function() {
return this._client.getChildrenMeta(this._currentNodeId).items
// For now, anything is possible!
// FIXME
.map(info => this._getAllDescendentIds(info.id))
.reduce((prev, curr) => prev.concat(curr))
// Filter all abstract nodes
.filter(nodeId => {
return !this._client.getNode(nodeId).isAbstract();
})
.map(id => this._getObjectDescriptor(id))
.filter(obj => !obj.isConnection && obj.name !== 'Connection')
.filter(layer => layer.layerType !== 'Criterion');
};
ArchEditorControl.prototype._getValidSuccessorNodes =
ArchEditorControl.prototype._getValidInitialNodes =
ArchEditorControl.prototype.getNonCriterionLayers = function() {
// Return all (non-criterion) layer types
var metanodes = this._client.getAllMetaNodes(),
layerId,
connId,
conn,
criterionId,
allLayers = [],
allLayerIds = [],
layers = [],
tgts,
j,
i;
for (i = metanodes.length; i--;) {
@@ -131,40 +142,24 @@ define([
}
}
// Remove all criterion layers and abstract layers
for (i = metanodes.length; i--;) {
if (layerId) {
if (!metanodes[i].isAbstract() && metanodes[i].isTypeOf(layerId)) {
if (!metanodes[i].isAbstract() &&
this._client.isTypeOf(metanodes[i].getId(), layerId)) {
if (metanodes[i].getAttribute('name') === 'Criterion') {
criterionId = metanodes[i].getId();
} else {
allLayers.push(metanodes[i]);
}
} else if (!connId && metanodes[i].getAttribute('name') === 'Connection') { // Detect the layer connection type...
tgts = this._client.getPointerMeta(metanodes[i].getId(), 'src').items;
for (j = tgts.length; j--;) {
if (tgts[j].id === layerId) {
connId = metanodes[i].getId();
}
allLayerIds.push(metanodes[i].getId());
}
}
}
}
if (!connId) {
this._logger.warn('Could not find a layer connector');
return [];
}
// Convert the layers into the correct format
conn = this._getObjectDescriptor(connId);
// Remove all criterion layers and abstract layers
for (i = allLayers.length; i--;) {
if (!allLayers[i].isTypeOf(criterionId)) {
layers.push({
node: this._getObjectDescriptor(allLayers[i].getId()),
conn: conn
});
for (i = allLayerIds.length; i--;) {
if (!this._client.isTypeOf(allLayerIds[i], criterionId)) {
layers.push({node: this._getObjectDescriptor(allLayerIds[i])});
}
}
@@ -177,7 +172,7 @@ define([
// Widget extensions
ArchEditorControl.prototype._initWidgetEventHandlers = function() {
ThumbnailControl.prototype._initWidgetEventHandlers.call(this);
EasyDAGControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getCreateNewDecorator = this.getCreateNewDecorator.bind(this);
};
@@ -1,100 +0,0 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/ArchIndex/ArchIndexWidget',
'panels/PipelineIndex/PipelineIndexControl'
], function (
PanelBaseWithHeader,
IActivePanel,
ArchIndexWidget,
ArchIndexControl
) {
'use strict';
var ArchIndexPanel;
ArchIndexPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArchIndexPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ArchIndexPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(ArchIndexPanel.prototype, IActivePanel.prototype);
ArchIndexPanel.prototype._initialize = function () {
var self = this;
//set Widget title
this.setTitle('');
this.widget = new ArchIndexWidget(this.logger, this.$el);
this.widget.setTitle = function (title) {
self.setTitle(title);
};
this.control = new ArchIndexControl({
logger: this.logger,
client: this._client,
embedded: this._embedded,
widget: this.widget
});
this.onActivate();
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ArchIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
ArchIndexPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ArchIndexPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
ArchIndexPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
ArchIndexPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return ArchIndexPanel;
});
@@ -1,203 +0,0 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'blob/BlobClient',
'js/Constants'
], function (
BlobClient,
CONSTANTS
) {
'use strict';
var ArtifactIndexControl;
ArtifactIndexControl = function (options) {
this._logger = options.logger.fork('Control');
this.blobClient = new BlobClient({
logger: this._logger.fork('BlobClient')
});
this._client = options.client;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
ArtifactIndexControl.prototype._initWidgetEventHandlers = function () {
this._widget.onNodeClick = (/*id*/) => {
// Change the current active object
// This is currently disabled as there are not any good
// visualizers for the data types
// WebGMEGlobal.State.registerActiveObject(id);
};
this._widget.onNodeDeleteClicked = id => {
var name = this._client.getNode(id).getAttribute('name'),
msg = `Deleted "${name}" artifact (${id}) --`;
this._client.startTransaction(msg);
this._client.deleteNode(id);
this._client.completeTransaction();
};
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
// One major concept here is with managing the territory. The territory
// defines the parts of the project that the visualizer is interested in
// (this allows the browser to then only load those relevant parts).
ArtifactIndexControl.prototype.selectedObjectChanged = function (nodeId) {
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
if (this._currentNodeId) {
this._client.removeUI(this._territoryId);
}
this._currentNodeId = nodeId;
if (typeof this._currentNodeId === 'string') {
// Put new node's info into territory rules
this._widget.currentNode = this._currentNodeId;
this._selfPatterns = {};
this._territoryId = this._client.addUI(this, events => {
this._eventCallback(events);
});
this._selfPatterns[nodeId] = {children: 1};
this._client.updateTerritory(this._territoryId, this._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
ArtifactIndexControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
base,
hash,
objDescriptor;
if (node) {
base = this._client.getNode(node.getBaseId());
hash = node.getAttribute('data');
objDescriptor = {
id: node.getId(),
type: base ? base.getAttribute('name') : 'n/a',
name: node.getAttribute('name'),
createdAt: node.getAttribute('createdAt'),
dataURL: this.blobClient.getDownloadURL(hash),
parentId: node.getParentId()
};
}
return this.blobClient.getMetadata(hash)
.then(metadata => {
objDescriptor.size = this._humanFileSize(metadata.size);
return objDescriptor;
});
};
ArtifactIndexControl.prototype._humanFileSize = function (bytes, si) {
var thresh = si ? 1000 : 1024,
units = si ?
['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] :
['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'],
u = -1;
if (bytes < thresh) {
return bytes + ' B';
}
do {
bytes = bytes / thresh;
u += 1;
} while (bytes >= thresh);
return bytes.toFixed(1) + ' ' + units[u];
};
/* * * * * * * * Node Event Handling * * * * * * * */
ArtifactIndexControl.prototype._eventCallback = function (events) {
var i = events ? events.length : 0,
event;
this._logger.debug('_eventCallback \'' + i + '\' items');
while (i--) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
this._onLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
break;
}
}
this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
};
ArtifactIndexControl.prototype._onLoad = function (gmeId) {
this._getObjectDescriptor(gmeId).then(desc => this._widget.addNode(desc));
};
ArtifactIndexControl.prototype._onUpdate = function (gmeId) {
this._getObjectDescriptor(gmeId).then(desc => this._widget.updateNode(desc));
};
ArtifactIndexControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
ArtifactIndexControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId === activeObjectId) {
// The same node selected as before - do not trigger
} else {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ArtifactIndexControl.prototype.destroy = function () {
this._detachClientEventListeners();
};
ArtifactIndexControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this);
};
ArtifactIndexControl.prototype._detachClientEventListeners = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged);
};
ArtifactIndexControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
ArtifactIndexControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return ArtifactIndexControl;
});
@@ -1,99 +0,0 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/ArtifactIndex/ArtifactIndexWidget',
'./ArtifactIndexControl'
], function (
PanelBaseWithHeader,
IActivePanel,
ArtifactIndexWidget,
ArtifactIndexControl
) {
'use strict';
var ArtifactIndexPanel;
ArtifactIndexPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArtifactIndexPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ArtifactIndexPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(ArtifactIndexPanel.prototype, IActivePanel.prototype);
ArtifactIndexPanel.prototype._initialize = function () {
var self = this;
//set Widget title
this.setTitle('');
this.widget = new ArtifactIndexWidget(this.logger, this.$el);
this.widget.setTitle = function (title) {
self.setTitle(title);
};
this.control = new ArtifactIndexControl({
logger: this.logger,
client: this._client,
widget: this.widget
});
this.onActivate();
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ArtifactIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
ArtifactIndexPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ArtifactIndexPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
ArtifactIndexPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
ArtifactIndexPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return ArtifactIndexPanel;
});
@@ -100,7 +100,7 @@ define([
this._client.startTransaction(`Updating class "${name || nodeName}"`);
if (name) {
this._client.setAttribute(id, 'name', name);
this._client.setAttributes(id, 'name', name);
}
if (basePath) {
this._client.setBase(id, basePath);
@@ -137,7 +137,7 @@ define([
}
for (i = nameMatches.length; i--;) {
if (nameMatches[i].isTypeOf(classNode.getId())) {
if (this._client.isTypeOf(nameMatches[i].getId(), classNode.getId())) {
return nameMatches[i].getId();
}
}
@@ -6,14 +6,12 @@ define([
'deepforge/Constants',
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/PipelineControl',
'deepforge/viz/Execute',
'underscore'
], function (
GME_CONSTANTS,
CONSTANTS,
EasyDAGControl,
PipelineControl,
Execute,
_
) {
@@ -23,18 +21,15 @@ define([
ExecutionViewControl = function (options) {
EasyDAGControl.call(this, options);
Execute.call(this, this._client, this._logger);
this.addedNodes = {};
this.originTerritory = {};
this.originTerritoryId = null;
this.readOnly = false;
};
_.extend(
ExecutionViewControl.prototype,
EasyDAGControl.prototype,
PipelineControl.prototype,
Execute.prototype
PipelineControl.prototype
);
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
@@ -81,9 +76,6 @@ define([
this._client.removeUI(this.originTerritoryId);
}
}
if (!this.readOnly) {
this.checkPipelineExecution(this._client.getNode(id));
}
}
};
@@ -73,7 +73,7 @@ define([
ExecutionViewPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
this.control.readOnly = isReadOnly;
};
ExecutionViewPanel.prototype.onResize = function (width, height) {
@@ -178,7 +178,7 @@ define([
ForgeActionButton.prototype.createNamedNode = function(baseId, isMeta) {
var parentId = this._currentNodeId,
newId = this.client.createNode({parentId, baseId}),
newId = this.client.createChild({parentId, baseId}),
basename = 'New' + this.client.getNode(baseId).getAttribute('name'),
newName = this.getUniqueName(parentId, basename);
@@ -186,7 +186,7 @@ define([
if (!isMeta) {
newName = newName.substring(0, 1).toLowerCase() + newName.substring(1);
}
this.client.setAttribute(newId, 'name', newName);
this.client.setAttributes(newId, 'name', newName);
return newId;
};
@@ -355,8 +355,8 @@ define([
var nodeId = this._currentNodeId;
if (nodeId) {
this.client.startTransaction(msg);
this.client.deleteNode(nodeId);
this.client.completeTransaction();
this.client.delMoreNodes([nodeId]);
this.client.completeTransaction(msg);
}
};
@@ -1,67 +0,0 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'deepforge/globals',
'js/PanelBase/PanelBaseWithHeader'
], function (
CONSTANTS,
DeepForge,
PanelBaseWithHeader
) {
'use strict';
var ForwardVizPanel;
ForwardVizPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ForwardViz';
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ForwardVizPanel.prototype, PanelBaseWithHeader.prototype);
ForwardVizPanel.prototype._initialize = function () {
this.control = this;
this.onActivate();
};
ForwardVizPanel.prototype.selectedObjectChanged = function(nodeId) {
if (nodeId === CONSTANTS.PROJECT_ROOT_ID) {
DeepForge.places.MyPipelines().then(id => WebGMEGlobal.State.registerActiveObject(id));
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
//apply parent's onReadOnlyChanged
ForwardVizPanel.prototype.onReadOnlyChanged = function() {
PanelBaseWithHeader.prototype.onReadOnlyChanged.apply(this, arguments);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ForwardVizPanel.prototype.destroy = function () {
PanelBaseWithHeader.prototype.destroy.call(this);
};
ForwardVizPanel.prototype.onReadOnlyChanged =
ForwardVizPanel.prototype.onResize =
ForwardVizPanel.prototype.onActivate =
ForwardVizPanel.prototype.onDeactivate = function () {
};
return ForwardVizPanel;
});
@@ -10,13 +10,11 @@ define([
'panels/TilingViz/TilingVizPanel',
'panels/OutputViewer/OutputViewerPanel',
'panels/OperationCodeEditor/OperationCodeEditorPanel',
'deepforge/viz/Execute',
'js/Constants'
], function (
TilingViz,
OutputViewer,
OperationCodeEditor,
Execute,
CONSTANTS
) {
'use strict';
@@ -25,16 +23,11 @@ define([
JobEditorPanel = function (layoutManager, params) {
TilingViz.call(this, layoutManager, params);
Execute.call(this, this._client, this.logger);
this.readOnly = false;
};
//inherit from PanelBaseWithHeader
_.extend(
JobEditorPanel.prototype,
Execute.prototype,
TilingViz.prototype
);
_.extend(JobEditorPanel.prototype, TilingViz.prototype);
JobEditorPanel.prototype.getPanels = function () {
if (this.readOnly) {
@@ -95,10 +88,6 @@ define([
// update the OutputViewer controller
var i = this._panels.length;
this._panels[i-1].control.selectedObjectChanged(nodeId);
// Check if the job needs to be reconnected
if (!this.isReadOnly()) {
this.checkJobExecution(node);
}
}
};
@@ -94,10 +94,10 @@ define([
this._client.startTransaction(msg);
TextEditorControl.prototype.saveTextFor.call(this, id, text, true);
this._client.setAttribute(id, 'name', layerSchema.name);
this._client.setAttributes(id, 'name', layerSchema.name);
this._logger.debug(`Setting ctor args to ${ctorAttrs.join(',')}`);
this._client.setAttribute(id, Constants.CTOR_ARGS_ATTR, ctorAttrs.join(','));
this._client.setAttributes(id, Constants.CTOR_ARGS_ATTR, ctorAttrs.join(','));
types = layerSchema.types || {};
schema = this.getPointerMeta();
@@ -114,29 +114,29 @@ define([
// Remove old pointers
node.getPointerNames().filter(ptr => !currentPtrs[ptr])
.forEach(ptr => this._client.delMetaPointer(id, ptr));
.forEach(ptr => this._client.deleteMetaPointer(id, ptr));
// Remove old attributes
setterNames = Object.keys(layerSchema.setters);
_.difference(currentAttrs, ctorAttrs, setterNames)
.forEach(attr => this._client.delAttributeMeta(id, attr));
.forEach(attr => this._client.removeAttributeSchema(id, attr));
// Add setters
for (i = setterNames.length; i--;) {
schema = utils.getSetterSchema(setterNames[i], layerSchema.setters, layerSchema.defaults);
// Get setter attr schema
if (schema.hasOwnProperty('default')) {
this._client.setAttribute(id, setterNames[i], schema.default);
this._client.setAttributes(id, setterNames[i], schema.default);
delete schema.default;
}
if (types[setterNames[i]]) {
schema.type = types[setterNames[i]];
}
this._client.setAttributeMeta(id, setterNames[i], schema);
this._client.setAttributeSchema(id, setterNames[i], schema);
}
ctorAttrs.forEach(attr =>
this._client.setAttributeMeta(id, attr, {
this._client.setAttributeSchema(id, attr, {
type: types[attr] || 'string'
})
);
@@ -5,7 +5,7 @@
// if the job is running, get the logs from the log-storage
define([
'q',
'deepforge/api/JobLogsClient',
'deepforge/JobLogsClient',
'js/Constants',
'deepforge/Constants',
'panels/TextEditor/TextEditorControl'
@@ -82,14 +82,7 @@ define([
};
LogViewerControl.prototype._getRunningLogs = function (id) {
var logManager;
if (!this._client.getActiveBranchName() || !this._client.getActiveProjectId()) {
// Logs are only stored for a given branch
return Q().then(() => '');
}
logManager = new JobLogsClient({
var logManager = new JobLogsClient({
logger: this._logger,
projectId: this._client.getActiveProjectId(),
branchName: this._client.getActiveBranchName()
@@ -0,0 +1,244 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'blob/BlobClient',
'js/Constants',
'q',
'deepforge/globals'
], function (
BlobClient,
CONSTANTS,
Q,
DeepForge
) {
'use strict';
var MainViewControl;
MainViewControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
this._widget = options.widget;
this._currentNodeId = null;
this._embedded = options.embedded;
this.territory = {};
this.ui = {};
this._blobClient = new BlobClient({
logger: this._logger.fork('BlobClient')
});
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
MainViewControl.prototype._initWidgetEventHandlers = function () {
this._widget.deleteNode = id => {
var node = this._client.getNode(id),
baseId = node.getBaseId(),
base = this._client.getNode(baseId),
baseName = base.getAttribute('name'),
name = node.getAttribute('name'),
msg = `Deleting ${baseName} "${name}"`;
this._client.startTransaction(msg);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
};
this._widget.dataUrlFor = id => {
var node = this._client.getNode(id),
hash = node.getAttribute('data');
if (hash) {
return this._blobClient.getDownloadURL(hash);
} else {
return null;
}
};
this._widget.toggleEmbeddedPanel = () => this.toggleEmbeddedPanel();
this._widget.updateLibraries = this.updateLibraries.bind(this);
this._widget.checkLibUpdates = this.checkLibUpdates.bind(this);
this._widget.getProjectName = this.getProjectName.bind(this);
};
MainViewControl.prototype.getProjectName = function () {
return this._client.getActiveProjectId().split('+')[1];
};
MainViewControl.prototype.checkLibUpdates = function () {
var pluginId = 'CheckLibraries',
context = this._client.getCurrentPluginContext(pluginId);
return Q.ninvoke(this._client, 'runServerPlugin', pluginId, context)
.then(res => {
return res.messages.map(msg => msg.message.split(' '));
});
};
MainViewControl.prototype.updateLibraries = function (libraries) {
var promises = libraries
.map(lib => Q.ninvoke(this._client, 'updateLibrary', lib[0], lib[1]));
return Q.all(promises);
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
MainViewControl.prototype.selectedObjectChanged = function (nodeId) {
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
this.clearTerritoryRules();
this._currentNodeId = nodeId;
if (typeof this._currentNodeId === 'string') {
var terrTypes = [
/* [type, root dir] */
['arch', 'MyArchitectures'],
['artifact', 'MyArtifacts']
];
terrTypes.forEach(pair => {
var type = pair[0],
dirname = pair[1];
// Update the territory
this.territory[type] = {};
DeepForge.places[dirname]().then(id => {
this.territory[type][id] = {children: 1};
this.ui[type] = this._client.addUI(this, this.handleEvents.bind(this, type));
this._client.updateTerritory(this.ui[type], this.territory[type]);
});
});
}
};
MainViewControl.prototype.handleEvents = function (type, events) {
var event;
// Remove the containing dir
events = events.filter(e => !this.territory[type][e.eid]);
this._logger.debug('_eventCallback \'' + i + '\' items');
for (var i = events.length; i--;) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
this.onLoad(type, event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(type, event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
break;
}
}
this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
};
MainViewControl.prototype.onLoad = function(type, id) {
// Load a node of the given type
var desc = this._getObjectDescriptor(type, id);
if (type === 'arch') {
this._widget.addArch(desc);
} else { // artifacts
this._widget.addArtifact(desc);
}
};
// This next function retrieves the relevant node information for the widget
MainViewControl.prototype._getArtifactDesc = function (id) {
var node = this._client.getNode(id),
data = node.getAttribute('data'),
desc = this._getBasicDesc(id);
desc.data = data;
return desc;
};
MainViewControl.prototype._getArchDesc =
MainViewControl.prototype._getBasicDesc = function (id) {
var node = this._client.getNode(id);
return {
id: id,
name: node.getAttribute('name')
};
};
MainViewControl.prototype._getObjectDescriptor = function (type, id) {
return type === 'arch' ?
this._getArchDesc(id) :
this._getArtifactDesc(id);
};
/* * * * * * * * Node Event Handling * * * * * * * */
MainViewControl.prototype._onUpdate = function (type, gmeId) {
var description = this._getObjectDescriptor(type, gmeId);
this._widget.updateNode(description);
};
MainViewControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
MainViewControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId !== activeObjectId) {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
MainViewControl.prototype.destroy = function () {
this._detachClientEventListeners();
this.clearTerritoryRules();
};
MainViewControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged, this);
}
};
MainViewControl.prototype._detachClientEventListeners = function () {
if (!this._embedded) {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
}
};
MainViewControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
MainViewControl.prototype.clearTerritoryRules = function () {
if (Object.keys(this.ui).length) {
Object.keys(this.ui).forEach(id =>
this._client.removeUI(this.ui[id]));
}
};
MainViewControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return MainViewControl;
});
@@ -0,0 +1,167 @@
/*globals define, $, _, WebGMEGlobal*/
/*jshint browser: true*/
// The main panel shows the PipelineIndex w/ a bar on the left for viewing architectures
// and pipelines
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/MainView/MainViewWidget',
'./MainViewControl',
'panels/PipelineIndex/PipelineIndexPanel',
'panels/ExecutionIndex/ExecutionIndexPanel',
'deepforge/globals'
], function (
PanelBaseWithHeader,
IActivePanel,
MainViewWidget,
MainViewControl,
PipelineIndexPanel,
ExecutionIndexPanel,
DeepForge
) {
'use strict';
var MainViewPanel;
MainViewPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'MainViewPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this.$nav = $('<div>', {id: 'nav-container'});
this.$el.css({padding: 0});
this.embeddedPanels = [
PipelineIndexPanel,
ExecutionIndexPanel
];
this.nextPanelIndex = 0;
this._lm = layoutManager;
this._params = params;
this.$el.append(this.$nav);
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(MainViewPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(MainViewPanel.prototype, IActivePanel.prototype);
MainViewPanel.prototype._initialize = function () {
//set Widget title
this.setTitle('');
this.widget = new MainViewWidget(this.logger, this.$nav);
this.control = new MainViewControl({
logger: this.logger,
client: this._client,
embedded: this._embedded,
widget: this.widget
});
this.control.toggleEmbeddedPanel = this.toggleEmbeddedPanel.bind(this);
var selectedObjectChanged = this.control.selectedObjectChanged;
this.control.selectedObjectChanged = id => {
this.getEmbeddedNode().then(nodeId =>
this.embeddedPanel.control.selectedObjectChanged(nodeId));
selectedObjectChanged.call(this.control, id);
};
this.toggleEmbeddedPanel(true);
this.onActivate();
};
MainViewPanel.prototype.getEmbeddedNode = function() {
if (this.nextPanelIndex === 1) {
return DeepForge.places.MyPipelines();
} else {
return DeepForge.places.MyExecutions();
}
};
MainViewPanel.prototype.toggleEmbeddedPanel = function (silent) {
var Panel = this.embeddedPanels[this.nextPanelIndex];
this.nextPanelIndex = (this.nextPanelIndex + 1) % this.embeddedPanels.length;
if (this.embeddedPanel) { // Remove current
this.embeddedPanel.destroy();
this.$embedded.remove();
}
this.embeddedPanel = new Panel(this._lm, this._params);
this.$embedded = this.embeddedPanel.$el;
this.$embedded.addClass('main-view-embedded');
this.$el.append(this.$embedded);
// Call on Resize and selectedObjectChanged
this.onResize(this.width, this.height);
if (!silent) {
this.getEmbeddedNode().then(nodeId =>
this.embeddedPanel.control.selectedObjectChanged(nodeId));
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
MainViewPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
MainViewPanel.prototype.onResize = function (width, height) {
var navWidth,
embeddedWidth;
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
navWidth = this.widget.width();
embeddedWidth = width-navWidth;
this.$embedded.css({
width: embeddedWidth,
height: height,
left: navWidth,
margin: 'inherit'
});
this.embeddedPanel.onResize(embeddedWidth, height);
this.width = width;
this.height = height;
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
MainViewPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
MainViewPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
MainViewPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return MainViewPanel;
});
@@ -135,7 +135,7 @@ define([
}
]
});
this._client.setPointer(this._currentNodeId, ptrName, null);
this._client.makePointer(this._currentNodeId, ptrName, null);
this._client.completeTransaction();
};
@@ -174,10 +174,10 @@ define([
this._client.startTransaction(msg);
// Currently, this will not update children already using old name...
this._client.delMetaPointer(this._currentNodeId, from);
this._client.deleteMetaPointer(this._currentNodeId, from);
this._client.delPointer(this._currentNodeId, from);
this._client.setPointerMeta(this._currentNodeId, ptrName, meta);
this._client.setPointer(this._currentNodeId, ptrName, null);
this._client.makePointer(this._currentNodeId, ptrName, null);
this._client.completeTransaction();
};
@@ -188,7 +188,7 @@ define([
this._client.startTransaction(msg);
// Currently, this will not update children already using old name...
this._client.delMetaPointer(this._currentNodeId, name);
this._client.deleteMetaPointer(this._currentNodeId, name);
this._client.delPointer(this._currentNodeId, name);
this._client.completeTransaction();
};
@@ -204,13 +204,13 @@ define([
msg = `Adding ${isInput ? 'input' : 'output'} "${dataName}" to ${name} interface`;
this._client.startTransaction(msg);
var id = this._client.createNode({
var id = this._client.createChild({
parentId: cntrId,
baseId: typeId
});
// Set the name of the new input
this._client.setAttribute(id, 'name', dataName);
this._client.setAttributes(id, 'name', dataName);
this._client.completeTransaction();
};
@@ -128,10 +128,10 @@ define([
operation = metanodes.find(n => n.getAttribute('name') === 'Data');
// Get all the meta nodes that are instances of Data
metanodes
.filter(node => node.isTypeOf(operation.getId()))
metanodes.map(n => n.getId())
.filter(nId => this._client.isTypeOf(nId, operation.getId()))
// Add a rule for them
.forEach(op => this._territories[op.getId()] = {children: 0});
.forEach(opId => this._territories[opId] = {children: 0});
this._client.updateTerritory(this._territoryId, this._territories);
};
@@ -199,7 +199,6 @@ define([
OutputViewerPanel.prototype.handleEvents = function (events) {
var metadataId = this.getMetadataId(),
node,
event;
if (!metadataId) {
@@ -207,13 +206,8 @@ define([
return;
}
events = events.filter(event => {
if (event.eid) {
node = this._client.getNode(event.eid);
return this._pages[event.eid] || node.isTypeOf(metadataId);
}
return false;
});
events = events.filter(event => event.eid && (this._pages[event.eid] ||
this._client.isTypeOf(event.eid, metadataId)));
for (var i = events.length; i--;) {
event = events[i];
switch (event.etype) {
@@ -4,7 +4,7 @@
define([
'deepforge/Constants',
'js/Constants',
'deepforge/viz/panels/ThumbnailControl',
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/PipelineControl',
'deepforge/viz/Execute',
'deepforge/globals',
@@ -15,7 +15,7 @@ define([
], function (
CONSTANTS,
GME_CONSTANTS,
ThumbnailControl,
EasyDAGControl,
PipelineControl,
Execute,
DeepForge,
@@ -40,7 +40,7 @@ define([
DECORATORS[CONSTANTS.OP.INPUT] = 'ArtifactOpDecorator';
PipelineEditorControl = function (options) {
ThumbnailControl.call(this, options);
EasyDAGControl.call(this, options);
Execute.call(this, this._client, this._logger);
this.addedIds = {};
this.executionTerritory = {};
@@ -52,7 +52,7 @@ define([
_.extend(
PipelineEditorControl.prototype,
ThumbnailControl.prototype,
EasyDAGControl.prototype,
PipelineControl.prototype,
Execute.prototype
);
@@ -98,7 +98,7 @@ define([
var msg = `Renaming pipeline "${from}" -> "${to}"`;
if (from !== to && !/^\s*$/.test(to)) {
this._client.startTransaction(msg);
this._client.setAttribute(this._currentNodeId, 'name', to);
this._client.setAttributes(this._currentNodeId, 'name', to);
this._client.completeTransaction();
}
};
@@ -124,10 +124,10 @@ define([
operation = metanodes.find(n => n.getAttribute('name') === 'Operation');
// Get all the meta nodes that are instances of Operations
metanodes
.filter(n => n.isTypeOf(operation.getId()))
metanodes.map(n => n.getId())
.filter(nId => this._client.isTypeOf(nId, operation.getId()))
// Add a rule for them
.forEach(op => this._territories[op.getId()] = this.TERRITORY_RULE);
.forEach(opId => this._territories[opId] = this.TERRITORY_RULE);
// Add arch/artifact dir to the territory
// loading more than necessary.... can restrict it in the future
@@ -138,11 +138,12 @@ define([
};
PipelineEditorControl.prototype._initWidgetEventHandlers = function () {
ThumbnailControl.prototype._initWidgetEventHandlers.call(this);
EasyDAGControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getExistingPortMatches = this.getExistingPortMatches.bind(this);
this._widget.createConnection = this.createConnection.bind(this);
this._widget.removeConnection = this.removeConnection.bind(this);
this._widget.getDecorator = this.getDecorator.bind(this);
this._widget.updateThumbnail = this.updateThumbnail.bind(this);
};
PipelineEditorControl.prototype.isContainedInActive = function (gmeId) {
@@ -158,7 +159,7 @@ define([
this.addedIds[desc.id] = true;
// Validate any connections
if (this.isValid(desc)) {
return ThumbnailControl.prototype._onLoad.call(this, gmeId);
return EasyDAGControl.prototype._onLoad.call(this, gmeId);
}
} else if (desc.parentId !== null &&
this.isContainedInActive(desc.parentId) && desc.isDataPort) {
@@ -178,7 +179,7 @@ define([
this.invalidated[desc.id] = true;
this._client.startTransaction(msg);
this._client.deleteNode(desc.id);
this._client.delMoreNodes([desc.id]);
this._client.completeTransaction();
return false;
}
@@ -197,7 +198,7 @@ define([
if(this.addedIds[gmeId]) {
delete this.addedIds[gmeId];
return ThumbnailControl.prototype._onUnload.call(this, gmeId);
return EasyDAGControl.prototype._onUnload.call(this, gmeId);
}
};
@@ -238,13 +239,8 @@ define([
PipelineEditorControl.prototype.getValidOutputs = function (inputId, outputs) {
// Valid input if one of the isTypeOf(<output>, inputId)
// for at least one output
var inputType = this._client.getNode(inputId).getMetaTypeId(),
node;
return outputs.filter(type => {
node = this._client.getNode(type);
return node.isTypeOf(inputType);
}).length;
var inputType = this._client.getNode(inputId).getMetaTypeId();
return outputs.filter(type => this._client.isTypeOf(type, inputType)).length;
};
PipelineEditorControl.prototype._getValidSuccessorNodes = function (nodeId) {
@@ -287,7 +283,7 @@ define([
msg = `Disconnecting ${names[0]} of ${names[1]} from ${names[2]} of ${names[3]}`;
this._client.startTransaction(msg);
this._client.deleteNode(id);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
};
@@ -329,13 +325,10 @@ define([
return [
node.getId(),
dstPorts.filter(id => {
var typeId = this._client.getNode(id).getMetaTypeId(),
portTypeNode = this._client.getNode(portType),
typeNode = this._client.getNode(typeId);
var typeId = this._client.getNode(id).getMetaTypeId();
return isOutput ?
portTypeNode.isTypeOf(typeId) :
typeNode.isTypeOf(portType);
this._client.isTypeOf(portType, typeId) :
this._client.isTypeOf(typeId, portType);
})
];
};
@@ -359,12 +352,12 @@ define([
this._client.startTransaction(msg);
connId = this._client.createNode({
connId = this._client.createChild({
parentId: this._currentNodeId,
baseId: this.getConnectionId()
});
this._client.setPointer(connId, CONN.SRC, srcId);
this._client.setPointer(connId, CONN.DST, dstId);
this._client.makePointer(connId, CONN.SRC, srcId);
this._client.makePointer(connId, CONN.DST, dstId);
this._client.completeTransaction();
};
@@ -376,16 +369,14 @@ define([
// the dst operation
var result = [],
ipairs = inputs.map(id => [id, this._client.getNode(id).getMetaTypeId()]),
oType,
oTypeId;
oType;
// For each output, get all possible (valid) input destinations
outputs.forEach(outputId => {
oTypeId = this._client.getNode(outputId).getMetaTypeId();
oType = this._client.getNode(oTypeId);
oType = this._client.getNode(outputId).getMetaTypeId();
result = result.concat(ipairs.filter(pair =>
// output type should be valid input type
oType.isTypeOf(pair[1])
this._client.isTypeOf(oType, pair[1])
)
.map(pair => [outputId, pair[0]]) // Get the input data id
);
@@ -596,7 +587,7 @@ define([
if (this.executionUI) {
this._client.removeUI(this, this.executionEvents.bind(this));
}
ThumbnailControl.prototype._detachClientEventListeners.call(this);
EasyDAGControl.prototype._detachClientEventListeners.call(this);
};
////////////////////// Execution Support END //////////////////////
@@ -637,15 +628,37 @@ define([
this._deleteTag(name); // Remove execution tag
if (this.isRunning(node)) {
this.silentStopExecution(id, true).then(() => {
this._client.deleteNode(id);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
});
} else {
this._client.deleteNode(id);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
}
};
PipelineEditorControl.prototype.updateThumbnail = function (svg) {
var node = this._client.getNode(this._currentNodeId),
name,
attrs,
currentThumbnail,
attrName = 'thumbnail',
msg;
if (node) { // may have been deleted
name = node.getAttribute('name');
attrs = node.getValidAttributeNames();
currentThumbnail = node.getAttribute(attrName);
msg = `Updating pipeline thumbnail for "${name}"`;
if (attrs.indexOf(attrName) > -1 && currentThumbnail !== svg) {
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, attrName, svg);
this._client.completeTransaction();
}
}
};
////////////////////// Criterion Support //////////////////////
PipelineEditorControl.prototype._getValidTargetsFor = function (id, ptr) {
// Check if the pointer is a Criterion pointer -> if so, only show the meta types
@@ -659,8 +672,8 @@ define([
if (criterion) {
// Get all criterion types
criterionId = criterion.getId();
items = this._client.getAllMetaNodes()
.filter(node => node.isTypeOf(criterionId));
items = this._client.getAllMetaNodes().map(node => node.getId())
.filter(id => this._client.isTypeOf(id, criterionId));
return items.map(id => {
return {
@@ -668,7 +681,7 @@ define([
};
});
} else {
return ThumbnailControl.prototype._getValidTargetsFor.apply(this, arguments);
return EasyDAGControl.prototype._getValidTargetsFor.apply(this, arguments);
}
};
@@ -54,7 +54,7 @@ define([
}
this._client.startTransaction(msg);
this._client.deleteNodes(ids);
this._client.delMoreNodes(ids);
this._client.completeTransaction();
this._client.removeUI(delUI);
@@ -68,7 +68,7 @@ define([
if (oldName !== name && !/^\s*$/.test(name)) {
this._client.startTransaction(msg);
this._client.setAttribute(id, 'name', name);
this._client.setAttributes(id, 'name', name);
this._client.completeTransaction();
}
};
@@ -102,20 +102,20 @@ define([
// This next function retrieves the relevant node information for the widget
PipelineIndexControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
base,
objDescriptor;
if (node) {
base = this._client.getNode(node.getBaseId());
objDescriptor = {
id: node.getId(),
name: node.getAttribute(nodePropertyNames.Attributes.name),
parentId: node.getParentId(),
id: undefined,
name: undefined,
parentId: undefined,
thumbnail: node.getAttribute('thumbnail'),
type: base.getAttribute('name'),
executionCount: node.getMemberIds('executions').length
};
objDescriptor.id = node.getId();
objDescriptor.name = node.getAttribute(nodePropertyNames.Attributes.name);
objDescriptor.parentId = node.getParentId();
}
return objDescriptor;
@@ -1,170 +0,0 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'js/PanelBase/PanelBase',
'panels/AutoViz/AutoVizPanel',
'widgets/Sidebar/SidebarWidget',
'deepforge/globals',
'q'
], function (
CONSTANTS,
PanelBase,
AutoVizPanel,
SidebarWidget,
DeepForge,
Q
) {
'use strict';
var SidebarPanel,
CATEGORY_TO_PLACE = {
pipelines: 'MyPipelines',
executions: 'MyExecutions',
architectures: 'MyArchitectures',
artifacts: 'MyArtifacts'
};
SidebarPanel = function (layoutManager, params) {
var opts = {};
opts[PanelBase.OPTIONS.LOGGER_INSTANCE_NAME] = 'SidebarPanel';
PanelBase.call(this, opts);
this._client = params.client;
this._embedded = params.embedded;
this._lm = layoutManager;
this._params = params;
this._panels = {};
this._initialize();
this.logger.debug('ctor finished');
};
SidebarPanel.prototype = Object.create(PanelBase.prototype);
SidebarPanel.prototype._initialize = function () {
this.widget = new SidebarWidget(this.logger, this.$el);
this.widget.getProjectName = this.getProjectName.bind(this);
this.widget.updateLibraries = this.updateLibraries.bind(this);
this.widget.checkLibUpdates = this.checkLibUpdates.bind(this);
this.widget.setEmbeddedPanel = this.setEmbeddedPanel.bind(this);
this.onActivate();
};
SidebarPanel.prototype._stateActiveBranchChanged = function (model, branchId) {
if (branchId) {
this.widget.checkLibraries();
}
};
SidebarPanel.prototype.setEmbeddedPanel = function (category) {
var placeName = CATEGORY_TO_PLACE[category];
return DeepForge.places[placeName]()
.then(nodeId => WebGMEGlobal.State.registerActiveObject(nodeId));
};
SidebarPanel.prototype.selectedObjectChanged = function (nodeId) {
var categories,
category,
place;
if (typeof nodeId === 'string') {
categories = Object.keys(CATEGORY_TO_PLACE);
Q.all(categories.map(category => {
place = CATEGORY_TO_PLACE[category];
return DeepForge.places[place]();
}))
.then(nodeIdPrefixes => {
for (var i = nodeIdPrefixes.length; i--;) {
if (nodeId.indexOf(nodeIdPrefixes[i]) > -1) {
category = categories[i];
return this.widget.highlight(category);
}
}
});
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
SidebarPanel.prototype.onResize = function (width, height) {
var navWidth,
embeddedWidth;
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
navWidth = this.widget.width();
embeddedWidth = width-navWidth;
if (this.embeddedPanel) {
this.$embedded.css({
width: embeddedWidth,
height: height,
left: navWidth,
margin: 'inherit'
});
this.embeddedPanel.onResize(embeddedWidth, height);
}
this.width = width;
this.height = height;
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
SidebarPanel.prototype.destroy = function () {
this.widget.destroy();
this.$el.remove();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
SidebarPanel.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
this.selectedObjectChanged(activeObjectId);
};
SidebarPanel.prototype.onActivate = function () {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged, this);
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_BRANCH_NAME,
this._stateActiveBranchChanged, this);
this.widget.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
SidebarPanel.prototype.onDeactivate = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_BRANCH_NAME,
this._stateActiveBranchChanged, this);
this.widget.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
/* * * * * * * * Library Updates * * * * * * * */
SidebarPanel.prototype.getProjectName = function () {
var projectId = this._client.getActiveProjectId();
return projectId && projectId.split('+')[1];
};
SidebarPanel.prototype.checkLibUpdates = function () {
var pluginId = 'CheckLibraries',
context = this._client.getCurrentPluginContext(pluginId);
return Q.ninvoke(this._client, 'runServerPlugin', pluginId, context)
.then(res => {
return res.messages.map(msg => msg.message.split(' '));
});
};
SidebarPanel.prototype.updateLibraries = function (libraries) {
var promises = libraries
.map(lib => Q.ninvoke(this._client, 'updateLibrary', lib[0], lib[1]));
return Q.all(promises);
};
return SidebarPanel;
});
@@ -55,7 +55,7 @@ define([
if (!inTransaction) {
this._client.startTransaction(msg);
}
this._client.setAttribute(id, this.ATTRIBUTE_NAME, text);
this._client.setAttributes(id, this.ATTRIBUTE_NAME, text);
if (!inTransaction) {
this._client.completeTransaction();
}
@@ -67,7 +67,7 @@ define([
msg = `Renaming ${oldName} -> ${name}`;
this._client.startTransaction(msg);
this._client.setAttribute(this._currentNodeId, 'name', name);
this._client.setAttributes(this._currentNodeId, 'name', name);
this._client.completeTransaction();
};
@@ -1,82 +0,0 @@
/* globals define, WebGMEGlobal*/
define([
'js/Constants',
'panels/BreadcrumbHeader/NodePathNavigator'
], function(
CONSTANTS,
NodePathNavigator
) {
var PATH_SEP = '/';
var NodePathWithHidden = function() {
NodePathNavigator.apply(this, arguments);
};
NodePathWithHidden.prototype = Object.create(NodePathNavigator.prototype);
NodePathWithHidden.prototype.getNodePath = function() {
var nodeIds = NodePathNavigator.prototype.getNodePath.apply(this, arguments),
lastRootChildIndex = -1,
pathSepRegex = new RegExp(PATH_SEP, 'g'),
i;
// Treat any nodeIds in the root object as the same node then remove them
// Hide any nodeIds in the root object
for (i = nodeIds.length; i-- && lastRootChildIndex === -1;) {
// Check for multiple '/' separators in the id (else it's a child of
// the root node)
if (nodeIds[i] && nodeIds[i].match(pathSepRegex).length === 1) {
lastRootChildIndex = i;
}
}
if (lastRootChildIndex > -1) {
for (i = 1; i <= lastRootChildIndex; i++) {
delete this.territories[nodeIds[i]];
}
nodeIds.splice(1, lastRootChildIndex);
}
return nodeIds;
};
NodePathWithHidden.prototype.addNode = function(id, isActive) {
if (id === CONSTANTS.PROJECT_ROOT_ID && !isActive) {
var item = document.createElement('li'),
anchor = document.createElement('a');
this._nodes[id] = anchor;
item.appendChild(anchor);
item.addEventListener('click', () => {
var nodeId = this._nodeHistory[1],
node;
if (nodeId) {
// Get the id for the child of the root node
node = this.client.getNode(nodeId);
if (node.getParentId() !== CONSTANTS.PROJECT_ROOT_ID) {
nodeId = node.getParentId();
}
} else {
// Try to load the 'MyPipelines' child of the root node
node = this.client.getNode(CONSTANTS.PROJECT_ROOT_ID)
// Get the child nodes
.getChildrenIds().map(id => this.client.getNode(id))
// Find the child named 'MyPipelines'
.find(child => child && child.getAttribute('name') === 'MyPipelines');
if (node) {
nodeId = node.getId();
}
}
// If none are loaded, try to register MyPipelines
WebGMEGlobal.State.registerActiveObject(nodeId || id);
});
this.territories[id] = {children: 0};
this.pathContainer.append(item);
} else {
return NodePathNavigator.prototype.addNode.apply(this, arguments);
}
};
return NodePathWithHidden;
});
@@ -1,106 +0,0 @@
/* globals define, WebGMEGlobal */
define([
'js/Dialogs/Projects/ProjectsDialog',
'./WorkerDialog',
'js/Panels/Header/ProjectNavigatorController'
], function(
ProjectsDialog,
WorkerDialog,
GMEProjectNavigatorController
) {
'use strict';
var ProjectNavigatorController = function() {
GMEProjectNavigatorController.apply(this, arguments);
};
ProjectNavigatorController.prototype = Object.create(GMEProjectNavigatorController.prototype);
ProjectNavigatorController.prototype.initialize = function () {
var self = this,
newProject,
manageProjects,
manageWorkers;
// initialize model structure for view
self.$scope.navigator = {
items: [],
separator: true
};
manageProjects = function (/*data*/) {
var pd = new ProjectsDialog(self.gmeClient);
pd.show();
};
newProject = function (data) {
var pd = new ProjectsDialog(self.gmeClient, true, data.newType);
pd.show();
};
self.userId = WebGMEGlobal.userInfo._id;
manageWorkers = function() {
// Create the worker dialog
var pd = new WorkerDialog(self.logger);
pd.show();
};
// initialize root menu
// projects id is mandatory
if (self.config.disableProjectActions === false) {
self.root.menu = [
{
id: 'top',
items: [
{
id: 'manageProject',
label: 'Manage projects ...',
iconClass: 'glyphicon glyphicon-folder-open',
action: manageProjects,
actionData: {}
},
{
id: 'newProject',
label: 'New project ...',
disabled: WebGMEGlobal.userInfo.canCreate !== true,
iconClass: 'glyphicon glyphicon-plus',
action: newProject,
actionData: {newType: 'seed'}
},
{
id: 'importProject',
label: 'Import project ...',
disabled: WebGMEGlobal.userInfo.canCreate !== true,
iconClass: 'glyphicon glyphicon-import',
action: newProject,
actionData: {newType: 'import'}
},
{
id: 'manageWorkers',
label: 'View workers ...',
iconClass: 'glyphicon glyphicon-cloud',
action: manageWorkers
}
]
},
{
id: 'projects',
label: 'Recent projects',
totalItems: 20,
items: [],
showAllItems: manageProjects
}
];
}
self.initWithClient();
// only root is selected by default
self.$scope.navigator = {
items: self.config.disableProjectActions ? [] : [self.root],
separator: true
};
};
return ProjectNavigatorController;
});
@@ -1,239 +0,0 @@
/* globals define, $ */
define([
'q',
'superagent',
'deepforge/viz/Utils',
'deepforge/api/JobOriginClient',
'text!./WorkerModal.html',
'text!./WorkerTemplate.html.ejs',
'text!./WorkerJobItem.html',
'css!./WorkerModal.css'
], function(
Q,
superagent,
utils,
JobOriginClient,
WorkerHtml,
WorkerTemplate,
WorkerJobItem
) {
'use strict';
var WORKER_ENDPOINT = '/rest/executor/worker',
JOBS_ENDPOINT = '/rest/executor';
var WorkerDialog = function(logger) {
this.workerDict = {};
this.workers = {};
this.runningWorkers = [];
this.jobsDict = {};
this.jobs = {};
this.active = false;
this.logger = logger.fork('WorkerDialog');
this.originManager = new JobOriginClient({
logger: this.logger
});
};
WorkerDialog.prototype.initialize = function() {
this._dialog = $(WorkerHtml);
this._table = this._dialog.find('.worker-list');
this.$noJobs = this._dialog.find('.no-jobs-msg');
this.$noWorkers = this._dialog.find('.no-workers-msg');
this._isShowingJobs = false;
this._isShowingWorkers = true;
this._queue = this._dialog.find('.job-queue-list');
this._dialog.modal('show');
this._dialog.on('hidden.bs.modal', () => this.active = false);
};
WorkerDialog.prototype.show = function() {
this.active = true;
this.update();
this.initialize();
};
WorkerDialog.prototype.get = function(url) {
var deferred = Q.defer();
superagent.get(url)
.end((err, res) => {
if (err) {
return deferred.reject(err);
}
deferred.resolve(JSON.parse(res.text));
});
return deferred.promise;
};
WorkerDialog.prototype.update = function() {
// Poll the workers
return Q.all([
this.get(WORKER_ENDPOINT).then(workers => this.updateWorkers(workers)),
this.get(JOBS_ENDPOINT).then(jobs => this.updateJobs(jobs))
]).then(() => {
if (this.active) {
setTimeout(this.update.bind(this), 1000);
}
})
.catch(err => this.logger.error('Update failed:', err));
};
WorkerDialog.prototype.updateWorkers = function(workerDict) {
var ids = Object.keys(workerDict),
oldWorkerIds,
visibleWorkers = false,
i;
this.runningWorkers = [];
for (i = ids.length; i--;) {
this.updateWorker(workerDict[ids[i]]);
visibleWorkers = true;
delete this.workerDict[ids[i]];
}
this.toggleNoWorkersMsg(!visibleWorkers);
// Clear old workers
oldWorkerIds = Object.keys(this.workerDict);
for (i = oldWorkerIds.length; i--;) {
this.removeWorker(oldWorkerIds[i]);
}
this.workerDict = workerDict;
};
WorkerDialog.prototype.updateWorker = function(worker) {
var row = this.workers[worker.clientId] || $(WorkerTemplate),
clazz;
worker.lastSeen = utils.getDisplayTime(worker.lastSeen*1000);
worker.status = worker.jobs.length ? 'RUNNING' : 'READY';
clazz = worker.status === 'RUNNING' ? 'warning' : 'success';
row[0].className = clazz;
row.find('.lastSeen').text(worker.lastSeen);
row.find('.clientId').text(worker.clientId);
row.find('.status').text(worker.status);
if (!this.workers[worker.clientId]) {
this._table.append(row);
this.workers[worker.clientId] = row;
}
if (worker.status === 'RUNNING') {
this.runningWorkers.push(worker);
}
};
WorkerDialog.prototype.removeWorker = function(workerId) {
this.workers[workerId].remove();
delete this.workers[workerId];
};
WorkerDialog.prototype.updateJobs = function(jobsDict) {
var allJobIds = Object.keys(jobsDict),
hasJobs = false,
id;
this.jobsDict = jobsDict;
for (var i = allJobIds.length; i--;) {
id = allJobIds[i];
if (this.jobs[id] || !this.isFinished(id)) {
hasJobs = this.updateJobItem(id) || hasJobs;
}
}
this.setNoJobsMessage(!hasJobs); // hide if no queue
};
WorkerDialog.prototype.setNoJobsMessage = function(visible) {
var visibility = visible ? 'inherit' : 'none',
wasVisible = !this._isShowingJobs;
if (visible !== wasVisible) {
this.$noJobs.css('display', visibility);
this._isShowingJobs = !visible;
}
};
WorkerDialog.prototype.toggleNoWorkersMsg = function(visible) {
var visibility = visible ? 'inherit' : 'none';
if (visible !== this._isShowingWorkers) {
this.$noWorkers.css('display', visibility);
this._isShowingWorkers = visible;
}
};
WorkerDialog.prototype.isFinished = function(jobId) {
return this.jobsDict[jobId].status === 'FAILED_TO_EXECUTE' ||
this.jobsDict[jobId].status === 'SUCCESS' ||
this.jobsDict[jobId].status === 'CANCELED';
};
WorkerDialog.prototype.updateJobItemName = function(jobId) {
return this.originManager.getOrigin(jobId)
.then(info => {
var job = this.jobs[jobId],
project = info.project.replace(/^guest\+/, '');
if (job && this.active) {
if (info.branch !== 'master') {
project += ' (' + info.branch + ')';
}
job.find('.job-id').text(info.job);
job.find('.execution').text(info.execution);
job.find('.project').text(project);
}
});
};
WorkerDialog.prototype.getWorkerWithJob = function(jobId) {
var jobs;
for (var i = this.runningWorkers.length; i--;) {
jobs = this.runningWorkers[i].jobs;
for (var j = jobs.length; j--;) {
if (jobs[j].hash === jobId) {
return this.runningWorkers[i].clientId;
}
}
}
return 'unknown';
};
WorkerDialog.prototype.updateJobItem = function(jobId) {
var job = this.jobs[jobId] || $(WorkerJobItem),
info = this.jobsDict[jobId],
createdTime = new Date(info.createTime).getTime(),
clazz = utils.ClassForJobStatus[info.status.toLowerCase()],
status = info.status;
job[0].className = `job-tag ${clazz}`;
// Add the worker id if running
if (info.status.toLowerCase() === 'running') {
var workerId = this.getWorkerWithJob(jobId);
status += ' (' + workerId + ')';
}
job.find('.status').text(status);
if (!this.jobs[jobId]) {
job.find('.job-id').text('Loading');
job.find('.createdAt').text(utils.getDisplayTime(createdTime));
this.updateJobItemName(jobId);
this._queue.append(job);
this.jobs[jobId] = job;
}
if (this.isFinished(jobId)) {
job.remove();
delete this.jobs[jobId];
return false;
}
return true;
};
return WorkerDialog;
});
@@ -1,54 +0,0 @@
/*globals define, angular, _, $, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Panels/Header/HeaderPanel',
'panels/BreadcrumbHeader/BreadcrumbHeaderPanel',
'js/Widgets/UserProfile/UserProfileWidget',
'js/Widgets/ConnectedUsers/ConnectedUsersWidget',
'js/Panels/Header/DefaultToolbar',
'./NodePathNavWithHiddenNodes',
'js/Toolbar/Toolbar',
'./ProjectNavigatorController'
], function (
HeaderBase,
BreadcrumbHeader,
UserProfileWidget,
ConnectedUsersWidget,
DefaultToolbar,
NodePathNavWithHiddenNodes,
Toolbar,
ProjectNavigatorController
) {
'use strict';
var HeaderPanel;
HeaderPanel = function (layoutManager, params) {
BreadcrumbHeader.call(this, layoutManager, params);
};
//inherit from PanelBaseWithHeader
_.extend(HeaderPanel.prototype, BreadcrumbHeader.prototype);
HeaderPanel.prototype._initialize = function () {
HeaderBase.prototype._initialize.call(this);
var app = angular.module('gmeApp'),
nodePath = new NodePathNavWithHiddenNodes({
container: $('<div/>', {class: 'toolbar-container'}),
client: this._client,
logger: this.logger
});
app.controller('ProjectNavigatorController', ['$scope', 'gmeClient', '$timeout', '$window', '$http',
ProjectNavigatorController]);
this.$el.find('.toolbar-container').remove();
this.$el.append(nodePath.$el);
WebGMEGlobal.Toolbar = Toolbar.createToolbar($('<div/>'));
new DefaultToolbar(this._client);
};
return HeaderPanel;
});
@@ -1,7 +0,0 @@
<tr>
<td class="job-id"></td>
<td class="execution">unknown</td>
<td class="project">unknown</td>
<td class="createdAt">unknown</td>
<td class="status">unknown</td>
</tr>
@@ -1,47 +0,0 @@
.worker-modal .modal-content .modal-header span {
font-size: 28px;
vertical-align: middle;
}
.worker-modal .modal-content .modal-header .header-icon {
height: 28px;
width: 28px;
margin-right: 1ex;
display: inline-block;
vertical-align: middle;
background-size: 28px 28px;
}
.worker-modal .modal-content .modal-body th {
text-align: left;
}
.worker-modal .job-tag {
margin-right: 5px;
}
.worker-modal .queue-title {
float: left;
margin-right: 5px;
font-size: 1.4em;
color: #555555;
font-weight: bold;
width: 100%;
text-align: center;
}
.worker-modal .no-jobs-msg {
font-style: italic;
font-size: 1.3em;
color: #777;
}
.worker-modal .no-workers-msg {
font-style: italic;
font-size: 1.3em;
color: #777;
}
.worker-modal .job-queue {
padding-top: 1em;
}
@@ -1,60 +0,0 @@
<div class="worker-modal modal fade in" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">x</button>
<i class="header-icon gme-icon"></i>
<span>Overview</span>
</div>
<div class="modal-body">
<div>
<div class="queue-title">Connected Workers</div>
<table class="table table-projects">
<thead>
<tr class="with-children">
<th class="title-owner">Worker Id
<!--<i class="glyphicon glyphicon-sort-by-attributes-alt sorted in-order"></i>
<i class="glyphicon glyphicon-sort-by-attributes sorted rev-order"></i>-->
</th>
<th class="title-name">Last Seen
<!--<i class="glyphicon glyphicon-sort-by-attributes-alt sorted in-order"></i>
<i class="glyphicon glyphicon-sort-by-attributes sorted rev-order"></i>-->
</th>
<th class="title-modified">Status
<!--<i class="glyphicon glyphicon-sort-by-attributes-alt sorted in-order"></i>
<i class="glyphicon glyphicon-sort-by-attributes sorted rev-order"></i>-->
</th>
</tr>
<!--<tr class="with-no-children">
<th>No projects in this group...</th>
</tr>-->
</thead>
<tbody class="worker-list">
<tr><td class="no-workers-msg">No Connected Workers...</td></tr>
</tbody>
</table>
</div>
<div class="job-queue">
<div class="queue-title">Job Queue</div>
<table class="table table-projects">
<thead>
<tr class="with-children">
<th>Job</th>
<th>Execution</th>
<th>Project</th>
<th>Creation Date</th>
<th>Status</th>
</tr>
<!--<tr class="with-no-children">-->
<!--<th>No queued jobs</th>-->
<!--</tr>-->
</thead>
<tbody class="job-queue-list">
<tr><td class="no-jobs-msg">No Running Jobs...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@@ -1,5 +0,0 @@
<tr>
<td class="clientId"></td>
<td class="lastSeen">unknown</td>
<td class="status">unknown</td>
</tr>
@@ -3,8 +3,7 @@
define([
'deepforge/globals',
'widgets/EasyDAG/Buttons',
'deepforge/viz/widgets/Thumbnail',
'widgets/EasyDAG/EasyDAGWidget',
'widgets/EasyDAG/AddNodeDialog',
'./SelectionManager',
'./Layer',
@@ -13,8 +12,7 @@ define([
'css!./styles/ArchEditorWidget.css'
], function (
DeepForge,
Buttons,
ThumbnailWidget,
EasyDAGWidget,
AddNodeDialog,
SelectionManager,
Layer,
@@ -25,83 +23,18 @@ define([
var CREATE_ID = '__NEW_LAYER__',
ArchEditorWidget,
WIDGET_CLASS = 'arch-editor',
LAYER_TAB_ORDER = [
'Simple',
'Transfer',
'Convolution',
'RNN',
'Containers',
'Misc'
];
WIDGET_CLASS = 'arch-editor';
ArchEditorWidget = function (logger, container) {
ThumbnailWidget.call(this, logger, container);
EasyDAGWidget.call(this, logger, container);
this.$el.addClass(WIDGET_CLASS);
this._emptyMsg = 'Click to add a new layer';
};
_.extend(ArchEditorWidget.prototype, ThumbnailWidget.prototype);
_.extend(ArchEditorWidget.prototype, EasyDAGWidget.prototype);
ArchEditorWidget.prototype.ItemClass = Layer;
ArchEditorWidget.prototype.SelectionManager = SelectionManager;
ArchEditorWidget.prototype.setupItemCallbacks = function() {
var widget = this;
ThumbnailWidget.prototype.setupItemCallbacks.apply(this, arguments);
// Add the hover button functions
this.ItemClass.prototype.showHoverButtons = function() {
var layer = this;
widget.showHoverButtons(layer);
};
this.ItemClass.prototype.hideHoverButtons = this.hideHoverButtons.bind(this);
this.ItemClass.prototype.isHoverAllowed = () => !this.isConnecting();
};
ArchEditorWidget.prototype.showHoverButtons = function(layer) {
var btn,
height = layer.height,
cx = layer.width/2;
if (this.$hoverBtns) {
this.hideHoverButtons();
}
this.$hoverBtns = layer.$el
.append('g')
.attr('class', 'hover-container');
btn = new Buttons.Connect.From({
context: this,
$pEl: this.$hoverBtns,
item: layer,
x: cx,
y: height
});
btn = new Buttons.Connect.To({
context: this,
$pEl: this.$hoverBtns,
item: layer,
x: cx,
y: 0
});
return btn;
};
ArchEditorWidget.prototype.hideHoverButtons = function() {
if (this.$hoverBtns) {
this.$hoverBtns.remove();
this.$hoverBtns = null;
}
};
ArchEditorWidget.prototype.startConnection = function () {
this.hideHoverButtons();
ThumbnailWidget.prototype.startConnection.apply(this, arguments);
};
ArchEditorWidget.prototype.onCreateInitialNode = function() {
var nodes = this.getValidInitialNodes();
return this.promptLayer(nodes)
@@ -115,30 +48,6 @@ define([
.then(selected => this.onAddItemSelected(item, selected, reverse));
};
ArchEditorWidget.prototype.getLayerCategoryTabs = function(types) {
var tabs = [],
allTabs = {},
tab,
i;
Object.keys(types).forEach(type => allTabs[type] = true);
delete allTabs.Criterion;
// Add the ordered tabs
for (i = LAYER_TAB_ORDER.length; i--;) {
tab = LAYER_TAB_ORDER[i];
if (allTabs[tab]) {
tabs.unshift(tab);
delete allTabs[tab];
}
}
// Add any remaining categories
Object.keys(allTabs).forEach(tab => tabs.unshift(tab));
return tabs;
};
ArchEditorWidget.prototype.promptLayer = function(nodes) {
var deferred = Q.defer(),
types = {},
@@ -155,7 +64,7 @@ define([
nodes = nodes.concat(createNews);
// Sort by layer type
opts.tabs = this.getLayerCategoryTabs(types);
opts.tabs = Object.keys(types);
opts.tabFilter = (tab, pair) => {
return pair.node.layerType === tab;
};
-23
Ver Arquivo
@@ -29,10 +29,6 @@ define([
this.width = this.decorator.width;
this.height = this.decorator.height;
this._hovering = false;
this.$el.on('mouseenter', () => this.onHover());
this.$el.on('mouseleave', () => this._hovering && this.onUnhover());
this.initializeTooltips();
// Set up decorator callbacks
this.setupDecoratorCallbacks();
@@ -40,24 +36,5 @@ define([
_.extend(Layer.prototype, DAGItem.prototype);
Layer.prototype.onHover = function() {
if (!this.isSelected() && this.isHoverAllowed()) {
this._hovering = true;
this.showHoverButtons();
}
};
Layer.prototype.onUnhover = function() {
this._hovering = false;
this.hideHoverButtons();
};
Layer.prototype.onSelect = function() {
DAGItem.prototype.onSelect.apply(this, arguments);
if (this._hovering) {
this.onUnhover();
}
};
return Layer;
});
@@ -26,7 +26,6 @@ define([
btn = new Buttons.GoToBase({
$pEl: this.$selection,
context: this._widget,
title: 'Edit layer definition',
item: this.selectedItem,
disabled: disabled,
x: width,
@@ -1,22 +0,0 @@
/*globals define */
/*jshint browser: true*/
define([
'widgets/PipelineIndex/PipelineIndexWidget'
], function (
PipelineIndexWidget
) {
'use strict';
var ArchIndexWidget = function () {
PipelineIndexWidget.apply(this, arguments);
};
ArchIndexWidget.prototype = Object.create(PipelineIndexWidget.prototype);
ArchIndexWidget.prototype.getEmptyMsg = function() {
return 'No Existing Architectures...';
};
return ArchIndexWidget;
});
@@ -1,10 +0,0 @@
/**
* This file is for any css that you may want for this visualizer.
*
* Ideally, you would use the scss file also provided in this directory
* and then generate this file automatically from that. However, you can
* simply write css if you prefer
*/
.arch-index {
outline: none; }
@@ -1,7 +0,0 @@
/**
* This file is for any scss that you may want for this visualizer.
*/
.arch-index {
outline: none;
}
@@ -1,88 +0,0 @@
/*globals define, $*/
/*jshint browser: true*/
define([
'./ModelItem',
'text!./Table.html',
'css!./styles/ArtifactIndexWidget.css'
], function (
ModelItem,
TABLE_HTML
) {
'use strict';
var ArtifactIndexWidget,
WIDGET_CLASS = 'artifact-index',
nop = function(){};
ArtifactIndexWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this.nodes = {};
this.currentNode = null;
this._initialize();
this._logger.debug('ctor finished');
};
ArtifactIndexWidget.prototype._initialize = function () {
// set widget class
this.$el.addClass(WIDGET_CLASS);
this.$content = $(TABLE_HTML);
this.$el.append(this.$content);
this.$list = this.$content.find('.list-content');
};
ArtifactIndexWidget.prototype.onWidgetContainerResize = nop;
// Adding/Removing/Updating items
ArtifactIndexWidget.prototype.addNode = function (desc) {
if (desc && desc.parentId === this.currentNode) {
var node = new ModelItem(this.$list, desc);
this.nodes[desc.id] = node;
node.$delete.on('click', event => {
this.onNodeDeleteClicked(desc.id);
event.stopPropagation();
event.preventDefault();
});
node.$download.on('click', event => event.stopPropagation());
node.$el.on('click', event => {
this.onNodeClick(desc.id);
event.stopPropagation();
event.preventDefault();
});
}
};
ArtifactIndexWidget.prototype.removeNode = function (gmeId) {
var node = this.nodes[gmeId];
if (node) {
node.remove();
delete this.nodes[gmeId];
}
};
ArtifactIndexWidget.prototype.updateNode = function (desc) {
if (desc && desc.parentId === this.currentNode) {
this.nodes[desc.id].update(desc);
}
};
/* * * * * * * * Visualizer event handlers * * * * * * * */
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ArtifactIndexWidget.prototype.destroy = function () {
};
ArtifactIndexWidget.prototype.onActivate = function () {
};
ArtifactIndexWidget.prototype.onDeactivate = function () {
};
return ArtifactIndexWidget;
});
@@ -1,43 +0,0 @@
/*globals define, $*/
define([
'deepforge/viz/Utils',
'text!./ModelRow.html'
], function(
Utils,
ROW_HTML
) {
'use strict';
var ModelItem = function(parent, node) {
this.$el = $(ROW_HTML);
this.initialize();
this.update(node);
parent.append(this.$el);
};
ModelItem.prototype.initialize = function() {
// Get the fields and stuff
this.$name = this.$el.find('.name');
this.$type = this.$el.find('.type');
this.$size = this.$el.find('.size');
this.$createdAt = this.$el.find('.createdAt');
this.$download = this.$el.find('.data-download');
this.$delete = this.$el.find('.data-remove');
};
ModelItem.prototype.update = function(node) {
var date = node.createdAt ? Utils.getDisplayTime(node.createdAt) : 'unknown';
this.$name.text(node.name);
this.$type.text(node.type || 'unknown');
this.$size.text(node.size || 'unknown');
this.$download.attr('href', node.dataURL);
this.$createdAt.text(date);
};
ModelItem.prototype.remove = function() {
this.$el.remove();
};
return ModelItem;
});
@@ -1,12 +0,0 @@
<tr>
<td class="name"></td>
<td class="type"></td>
<td class="size"></td>
<td class="createdAt"></td>
<td class="actions">
<a class="data-download" target="_self">
<span class="glyphicon glyphicon-download"></span>
</a>
<span class="glyphicon glyphicon-remove data-remove"></span>
</td>
</tr>
@@ -1,12 +0,0 @@
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Size</th>
<th>Creation Date</th>
</tr>
</thead>
<tbody class="list-content">
</tbody>
</table>
@@ -1,13 +0,0 @@
.artifact-index {
background-color: #eee !important;
outline: none;
text-align: center;
}
.artifact-index .data-download {
color: inherit;
}
.artifact-index .type {
font-style: italic;
}
@@ -27,7 +27,6 @@ define([
new Buttons.Enter({
context: this._widget,
$pEl: this.$selection,
title: 'View output',
item: this.selectedItem,
icon: 'monitor',
x: width,
@@ -0,0 +1,11 @@
<li data-id="<%= id %>" class="select-node">
<a>
<%= name %>
<div class="pull-right">
<% if (typeof data !== 'undefined') { %>
<span class="glyphicon glyphicon-cloud-download dl-node"></span>
<% } %>
<span class="glyphicon glyphicon-remove del-node"></span>
</div>
</a>
</li>
@@ -0,0 +1,247 @@
/*globals $, WebGMEGlobal,define */
/*jshint browser: true*/
define([
'panel/FloatingActionButton/styles/Materialize',
'deepforge/globals',
'text!./NavBar.html',
'text!./ListItem.ejs',
'underscore',
'css!./styles/MainViewWidget.css'
], function (
Materialize,
DeepForge,
NavBarHTML,
ListItem,
_
) {
'use strict';
var MainViewWidget,
WIDGET_CLASS = 'main-view',
CreateListItem = _.template(ListItem),
ToggleLabels = [
'Executions',
'Pipelines'
];
MainViewWidget = function (logger, container) {
this.logger = logger.fork('Widget');
this.$el = container;
this.$el.addClass(WIDGET_CLASS);
this.toggleIndex = 0;
this.initialize();
this.logger.debug('ctor finished');
};
MainViewWidget.prototype.initialize = function () {
// Create the nav bar
this.$nav = $(NavBarHTML);
this.$el.append(this.$nav);
// Execution support
this.$toggle = this.$nav.find('#toggle-main');
this.$toggleLabel = this.$nav.find('.toggle-label');
this.$toggle.on('click', () => {
if (this._closed) { // shouldn't be clicked when closed (but it is possible)
return;
}
this.toggleEmbeddedPanel();
// Update the toggle name
this.toggleIndex = (this.toggleIndex + 1) % 2;
this.$toggleLabel.text(ToggleLabels[this.toggleIndex]);
});
this.$archlist = this.$nav.find('#arch-list-content');
this.$artifacts = this.$nav.find('#artifact-list-content');
// opening, closing
this._closed = true;
this.$nav.find('.side-nav-control').on('click', this.controlClicked.bind(this));
this.$nav.on('transitionend', this.onChanged.bind(this));
// action buttons
this.$nav.on('click', '#create-artifact', DeepForge.create.Artifact);
this.$nav.on('click', '#create-arch', DeepForge.create.Architecture);
this.$nav.on('click', '.select-node', this.onNodeClick.bind(this));
this.$nav.on('click', '.del-node', this.onDelNodeClick.bind(this));
this.$nav.on('click', '.dl-node', this.onDownloadNodeClick.bind(this));
this.htmlFor = {};
setTimeout(() => this.checkLibraries(), 100);
};
MainViewWidget.prototype.checkLibraries = function () {
this.checkLibUpdates()
.then(updates => {
if (updates.length) { // prompt about updates
var names = updates.map(update => update[0]),
projName = this.getProjectName(),
content = $('<span>'),
msg = `${projName} is out of date. Click to update.`;
this.logger.info(`Updates available for ${names.join(', ')}`);
if (names.indexOf('nn') !== -1) {
msg = 'Newer nn library available. Click to update';
} else if (names.indexOf('pipeline') !== -1) {
msg = 'Execution updates available. Click to update';
}
content.text(msg);
content.on('click', () => {
// Remove the toast
content.parent().fadeOut();
// Create updating notification
msg = 'Updating execution library...';
if (names.indexOf('nn') !== -1) {
msg = 'Updating nn library...';
}
content.text(msg);
Materialize.toast(content, 8000);
this.updateLibraries(updates).then(() => {
content.parent().remove();
Materialize.toast('Update complete!', 2000);
});
});
Materialize.toast(content, 8000);
}
})
.fail(err => Materialize.toast(`Library update check failed: ${err}`, 2000));
};
MainViewWidget.prototype.width = function () {
return this._closedWidth;
};
MainViewWidget.prototype.onChanged = function () {
if (!this._closed) { // add the text back
this.$nav.removeClass('hide-list');
} else {
this._closedWidth = this.$nav.width();
}
};
MainViewWidget.prototype.controlClicked = function () {
this._closed = !this._closed;
if (this._closed) {
this.$nav.addClass('hide-list');
this.$nav.addClass('closed');
} else { // remove the 'closed' class
this.$nav.removeClass('closed');
}
};
MainViewWidget.prototype.onWidgetContainerResize = function () {
var rect = this.$el[0].getBoundingClientRect(),
top = rect.top;
this.$nav.css({
top: top + 'px'
});
if (this._closed) {
this._closedWidth = this.$nav.width();
}
};
MainViewWidget.prototype.createNode = function(desc) {
// Create the architecture list item
var li;
desc.download = false;
li = $(CreateListItem(desc));
this.htmlFor[desc.id] = li;
return li;
};
MainViewWidget.prototype.addArch = function(desc) {
var html = this.createNode(desc);
this.$archlist.append(html);
};
MainViewWidget.prototype.addArtifact = function(desc) {
var html = this.createNode(desc);
this.$artifacts.append(html);
};
MainViewWidget.prototype.onDelNodeClick = function(event) {
var id = this.getElementId(event.target);
event.stopPropagation();
if (id) {
this.deleteNode(id);
}
};
MainViewWidget.prototype.onDownloadNodeClick = function(event) {
var id = this.getElementId(event.target),
url;
event.stopPropagation();
if (id) {
url = this.dataUrlFor(id);
if (url) {
this._download(url);
}
}
};
MainViewWidget.prototype._download = function(url) {
var anchor = document.createElement('a');
anchor.setAttribute('href', url);
anchor.setAttribute('target', '_self');
anchor.click();
};
MainViewWidget.prototype.onNodeClick = function(event) {
var id = this.getElementId(event.target);
event.stopPropagation();
if (id) {
WebGMEGlobal.State.registerActiveObject(id);
}
};
MainViewWidget.prototype.getElementId = function(element) {
while(!element.getAttribute('data-id') && element.parentNode) {
element = element.parentNode;
}
return element.getAttribute('data-id');
};
MainViewWidget.prototype.removeNode = function(id) {
if (this.htmlFor[id]) {
this.htmlFor[id].remove();
delete this.htmlFor[id];
}
};
MainViewWidget.prototype.updateNode = function (desc) {
var oldHtml = this.htmlFor[desc.id],
node;
if (oldHtml) {
node = this.createNode(desc);
node.insertAfter(oldHtml);
oldHtml.remove();
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
MainViewWidget.prototype.destroy = function () {
};
MainViewWidget.prototype.onActivate = function () {
this.logger.debug('MainViewWidget has been activated');
};
MainViewWidget.prototype.onDeactivate = function () {
this.logger.debug('MainViewWidget has been deactivated');
};
return MainViewWidget;
});
+40
Ver Arquivo
@@ -0,0 +1,40 @@
<nav class="side-nav fixed closed hide-list">
<li class="pull-right side-nav-control">
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
</li >
<li class="no-padding" id="toggle-main">
<ul>
<li class="no-padding">
<a class="toggle-label">Executions</a>
</li>
</ul>
</li>
<li class="no-padding">
<ul class="collapsible" data-collapsible="accordion">
<li>
<a data-target="#arch-list" data-toggle="collapse">Architectures</a>
<div id="arch-list" class="collapse">
<ul class="sublist">
<div id="arch-list-content"></div>
<li><a id="create-arch" class="action" href="#">New...</a></li>
</ul>
</div>
</li>
</ul>
</li>
<li class="no-padding">
<ul class="collapsible collapsible-accordion">
<li>
<a data-target="#artifact-list" data-toggle="collapse">Artifacts</a>
<div id="artifact-list" class="collapse">
<ul class="sublist">
<div id="artifact-list-content"></div>
<li>
<a id="create-artifact" class="action" href="#!">Upload...</a>
</li>
</ul>
</div>
</li>
</ul>
</li>
</nav>
@@ -4,29 +4,10 @@
.main-view .side-nav-control {
padding-right: 1em;
padding-left: 1em;
padding-top: 1em;
line-height: inherit !important;
}
.main-view .side-nav-icon.active {
border-left-style: solid;
border-left-width: thick;
border-left-color: #fcb385;
}
.main-view .side-nav-icon {
padding-left: 1.1em;
padding-top: 0.75em;
padding-bottom: 0.5em;
line-height: inherit !important;
}
.main-view .side-nav-icon span {
color: #757575;
font-size: 16px;
}
.main-view .side-nav-control span {
font-size: 16px;
color: #757575;
@@ -37,6 +18,10 @@
width: 40px;
}
.main-view .hide-list ul {
visibility: hidden;
}
.main-view .side-nav {
transform: translateX(0);
transition: width 0.3s;
@@ -162,11 +147,22 @@
}
.main-view .side-nav {
position: fixed;
width: 200px;
left: 0;
top: 64px;
bottom: 27px; /* footer height */
top: 0;
margin: 0;
-o-transform: translateX(-100%);
-ms-transform: translateX(-100%);
-webkit-transform: translateX(-100%);
-moz-transform: translateX(-100%);
transform: translateX(-100%);
height: 100%;
height: calc(100% + 60px);
height: -moz-calc(100%);
padding-bottom: 60px;
background-color: #fff;
z-index: 999;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
overflow-y: auto;
@@ -182,7 +178,6 @@
}
.main-view .side-nav li.active {
padding-left: 0.7em;
background-color: rgba(0, 0, 0, 0.05);
}
@@ -12,7 +12,6 @@ define([
) {
var AddOutput = function(params) {
params.title = params.title || 'Add operation output';
EasyDAGButtons.Add.call(this, params);
};
@@ -36,7 +35,6 @@ define([
};
var AddInput = function(params) {
params.title = params.title || 'Add operation input';
EasyDAGButtons.Add.call(this, params);
};
_.extend(AddInput.prototype, AddOutput.prototype);
@@ -47,7 +45,6 @@ define([
// References
var AddRef = function(params) {
params.title = params.title || 'Add pointer type';
EasyDAGButtons.Add.call(this, params);
};
@@ -17,5 +17,16 @@ define([
_.extend(Connection.prototype, EasyDAGConn.prototype);
Connection.prototype.setStartPoint = function(point) {
// Update 'this.points' to start at the given point
this.points[0] = point;
};
Connection.prototype.setEndPoint = function(point) {
// Update 'this.points' to end at the given point
var last = this.points.length-1;
this.points[last] = point;
};
return Connection;
});
@@ -1,4 +1,4 @@
/*globals define, d3 */
/*globals define */
define([
'widgets/EasyDAG/DAGItem',
'underscore'
@@ -13,10 +13,6 @@ define([
this.inputs = desc.inputs;
this.outputs = desc.outputs;
this._visiblePorts = null;
this._hovering = false;
this.$el.on('mouseenter', () => this.onHover());
this.$el.on('mouseleave', () => this._hovering && this.onUnhover());
};
_.extend(OperationNode.prototype, DAGItem.prototype);
@@ -25,13 +21,8 @@ define([
DAGItem.prototype.setupDecoratorCallbacks.call(this);
this.decorator.onPortClick = (id, portId, isSrc) => {
var srcPort = this.inputs.find(port => port.id === portId);
d3.event.stopPropagation();
d3.event.preventDefault();
if (srcPort && srcPort.connection) {
this.disconnectPort(portId, srcPort.connection);
this.hidePorts();
} else {
this.connectPort(id, portId, isSrc);
}
@@ -91,34 +82,13 @@ define([
// TODO
};
OperationNode.prototype.onHover = function() {
if (!this.isSelected() && this.canShowPorts()) {
this.showPorts();
this._hovering = true;
}
};
OperationNode.prototype.onUnhover = function() {
// Only fire these events if:
// - not selected
// - not creating a connection in the widget
if (!this.isSelected() && this.canShowPorts()) {
this.hidePorts();
this._hovering = false;
}
};
OperationNode.prototype.onSelect = function() {
DAGItem.prototype.onSelect.call(this);
if (this._hovering) {
this._hovering = false;
}
this.decorator.onSelect();
this.showPorts();
};
OperationNode.prototype.onDeselect = function() {
DAGItem.prototype.onDeselect.call(this);
this.decorator.onDeselect();
this.hidePorts();
};
@@ -1,10 +1,10 @@
/*globals WebGMEGlobal, $, define, $klay*/
/*globals WebGMEGlobal, $, define*/
/*jshint browser: true*/
define([
'deepforge/Constants',
'widgets/EasyDAG/AddNodeDialog',
'deepforge/viz/widgets/Thumbnail',
'widgets/EasyDAG/EasyDAGWidget',
'deepforge/viz/PipelineControl',
'deepforge/viz/Utils',
'deepforge/globals',
@@ -12,12 +12,11 @@ define([
'./Connection',
'./SelectionManager',
'underscore',
'./klay',
'css!./styles/PipelineEditorWidget.css'
], function (
CONSTANTS,
AddNodeDialog,
ThumbnailWidget,
EasyDAGWidget,
PipelineControl,
Utils,
DeepForge,
@@ -38,8 +37,7 @@ define([
};
PipelineEditorWidget = function (logger, container, execCntr) {
ThumbnailWidget.call(this, logger, container);
this._emptyMsg = 'Click to add an operation';
EasyDAGWidget.call(this, logger, container);
this.$el.addClass(WIDGET_CLASS);
this.portIdToNode = {};
this.PORT_STATE = STATE.DEFAULT;
@@ -51,8 +49,7 @@ define([
this.initExecs(execCntr);
};
_.extend(PipelineEditorWidget.prototype, ThumbnailWidget.prototype);
_.extend(PipelineEditorWidget.prototype, EasyDAGWidget.prototype);
PipelineEditorWidget.prototype.ItemClass = OperationNode;
PipelineEditorWidget.prototype.SelectionManager = SelectionManager;
PipelineEditorWidget.prototype.Connection = Connection;
@@ -61,23 +58,16 @@ define([
PipelineControl.prototype.onCreateInitialNode;
PipelineEditorWidget.prototype.setupItemCallbacks = function() {
ThumbnailWidget.prototype.setupItemCallbacks.call(this);
EasyDAGWidget.prototype.setupItemCallbacks.call(this);
this.ItemClass.prototype.connectPort =
PipelineEditorWidget.prototype.connectPort.bind(this);
this.ItemClass.prototype.disconnectPort =
PipelineEditorWidget.prototype.disconnectPort.bind(this);
this.ItemClass.prototype.canShowPorts = () => {
// when the widget is connecting ports, the items
// will ignore hover event behaviors wrt showing
// ports
return !this.isConnectingPorts();
};
};
//////////////////// Port Support ////////////////////
PipelineEditorWidget.prototype.addConnection = function(desc) {
ThumbnailWidget.prototype.addConnection.call(this, desc);
EasyDAGWidget.prototype.addConnection.call(this, desc);
// Record the connection with the input (dst) port
var dstItem = this.items[desc.dst],
dstPort;
@@ -95,10 +85,11 @@ define([
// Update the given port...
dstItem.refreshPorts();
}
this.refreshThumbnail();
};
PipelineEditorWidget.prototype.addNode = function(desc) {
ThumbnailWidget.prototype.addNode.call(this, desc);
EasyDAGWidget.prototype.addNode.call(this, desc);
// Update the input port connections (if not connection)
var item = this.items[desc.id];
if (item) {
@@ -110,10 +101,11 @@ define([
}
// If in a "connecting-port" state, refresh the port
if (this.isConnectingPorts()) {
if (this.PORT_STATE === STATE.CONNECTING) {
this.PORT_STATE = STATE.DEFAULT;
this.connectPort.apply(this, this.srcPortToConnectArgs);
}
this.refreshThumbnail();
};
PipelineEditorWidget.prototype._removeConnection = function(id) {
@@ -127,7 +119,8 @@ define([
port.connection = null;
dst.refreshPorts();
}
ThumbnailWidget.prototype._removeConnection.call(this, id);
EasyDAGWidget.prototype._removeConnection.call(this, id);
this.refreshThumbnail();
};
// May not actually need these port methods
@@ -146,7 +139,8 @@ define([
if (this.portIdToNode.hasOwnProperty(gmeId)) {
this.removePort(gmeId);
} else {
ThumbnailWidget.prototype.removeNode.call(this, gmeId);
EasyDAGWidget.prototype.removeNode.call(this, gmeId);
this.refreshThumbnail();
}
};
@@ -162,15 +156,11 @@ define([
this.removeConnection(connId);
};
PipelineEditorWidget.prototype.isConnectingPorts = function() {
return this.PORT_STATE === STATE.CONNECTING;
};
PipelineEditorWidget.prototype.connectPort = function(nodeId, id, isOutput) {
this._logger.info('port ' + id + ' has been clicked! (', isOutput, ')');
if (this.PORT_STATE === STATE.DEFAULT) {
this.srcPortToConnectArgs = arguments;
return this.startPortConnection(nodeId, id, isOutput);
this.startPortConnection(nodeId, id, isOutput);
} else if (this._selectedPort !== id) {
this._logger.info('connecting ' + this._selectedPort + ' to ' + id);
var src = !isOutput ? this._selectedPort : id,
@@ -179,22 +169,25 @@ define([
this.createConnection(src, dst);
} else if (!this._selectedPort) {
this._logger.error(`Invalid connection state: ${this.PORT_STATE} w/ ${this._selectedPort}`);
this.resetPortState();
}
this.resetPortState();
};
PipelineEditorWidget.prototype.startPortConnection = function(nodeId, id, isOutput) {
var existingMatches = this.getExistingPortMatches(id, isOutput);
var existingMatches = this.getExistingPortMatches(id, isOutput),
item = this.items[nodeId];
// Hide all ports except 'id' on 'nodeId'
this._selectedPort = id;
item.showPorts(id, !isOutput);
// Get all existing potential port destinations for the id
existingMatches.forEach(match =>
this.showPorts(match.nodeId, match.portIds, isOutput)
);
this.showPorts(nodeId, id, !isOutput);
// Show the 'add' button
// TODO
this.PORT_STATE = STATE.CONNECTING;
};
@@ -216,6 +209,27 @@ define([
PipelineEditorWidget.prototype.refreshExtras =
PipelineEditorWidget.prototype.updateEmptyMsg;
PipelineEditorWidget.prototype.refreshConnections = function() {
// Update the connections to they first update their start/end points
var connIds = Object.keys(this.connections),
src,
dst,
conn;
for (var i = connIds.length; i--;) {
conn = this.connections[connIds[i]];
// Update the start/end point
src = this.items[conn.src];
conn.setStartPoint(src.getPortLocation(conn.srcPort));
dst = this.items[conn.dst];
conn.setEndPoint(dst.getPortLocation(conn.dstPort, true));
conn.redraw();
}
};
//////////////////// Action Overrides ////////////////////
PipelineEditorWidget.prototype.onAddItemSelected = function(item, selected) {
@@ -334,7 +348,7 @@ define([
// Create new architecture from the "set ptr" dialog
return this.selectArchitectureTarget.apply(this, arguments);
} else {
return ThumbnailWidget.prototype.selectTargetFor.apply(this, arguments);
return EasyDAGWidget.prototype.selectTargetFor.apply(this, arguments);
}
};
@@ -388,114 +402,46 @@ define([
////////////////////////// Action Overrides END //////////////////////////
// Changing the layout to klayjs
PipelineEditorWidget.prototype.refreshScreen = function() {
if (!this.active) {
return;
}
////////////////////////// Thumbnail updates //////////////////////////
PipelineEditorWidget.prototype.getSvgDistanceDim = function(dim) {
var maxValue = this._getMaxAlongAxis(dim),
nodes,
minValue;
// WRITE UPDATES
// Update the locations of all the nodes
var graph = {
id: 'root',
properties: {
direction: 'DOWN',
'de.cau.cs.kieler.spacing': 25,
'de.cau.cs.kieler.edgeRouting': 'ORTHOGONAL'
//'de.cau.cs.kieler.klay.layered.nodePlace': 'INTERACTIVE'
},
edges: [],
children: []
};
graph.children = Object.keys(this.items).map(itemId => {
var item = this.items[itemId],
ports;
ports = item.inputs.map(p => this._getPortInfo(item, p, true))
.concat(item.outputs.map(p => this._getPortInfo(item, p)));
return {
id: itemId,
height: item.height,
width: item.width,
ports: ports,
properties: {
'de.cau.cs.kieler.portConstraints': 'FIXED_POS'
}
};
});
graph.edges = Object.keys(this.connections).map(connId => {
var conn = this.connections[connId];
return {
id: connId,
source: conn.src,
target: conn.dst,
sourcePort: conn.srcPort,
targetPort: conn.dstPort
};
});
$klay.layout({
graph: graph,
success: graph => {
this.resultGraph = graph;
this.queueFns([
this.applyLayout.bind(this, graph),
this.updateTranslation.bind(this),
this.refreshItems.bind(this),
this.refreshConnections.bind(this),
this.selectionManager.redraw.bind(this.selectionManager),
this.updateContainerWidth.bind(this),
this.refreshExtras.bind(this)
]);
}
});
nodes = this.graph.nodes().map(id => this.graph.node(id));
minValue = Math.min.apply(null, nodes.map(node => node[dim]));
return maxValue-minValue;
};
PipelineEditorWidget.prototype._getPortInfo = function(item, port, isInput) {
var position = item.decorator.getPortLocation(port.id, isInput),
side = isInput ? 'NORTH' : 'SOUTH';
position.y += (item.height/2) - 1;
return {
id: port.id,
width: 1, // Ports are rendered outside the node in this library;
height: 1, // we want it to look like it goes right up to the node
properties: {
'de.cau.cs.kieler.portSide': side
},
x: position.x,
y: position.y
};
PipelineEditorWidget.prototype.getSvgWidth = function() {
return this.getSvgDistanceDim('x');
};
PipelineEditorWidget.prototype.applyLayout = function (graph) {
var id,
item,
lItem, // layout item
i;
for (i = graph.children.length; i--;) {
// update the x, y
lItem = graph.children[i];
id = lItem.id;
item = this.items[id];
item.x = lItem.x + item.width/2;
item.y = lItem.y + item.height/2;
}
for (i = graph.edges.length; i--;) {
// update the connection.points
lItem = graph.edges[i];
id = lItem.id;
item = this.connections[id];
item.points = lItem.bendPoints || [];
item.points.unshift(lItem.sourcePoint);
item.points.push(lItem.targetPoint);
}
PipelineEditorWidget.prototype.getSvgHeight = function() {
return this.getSvgDistanceDim('y');
};
PipelineEditorWidget.prototype.getViewBox = function() {
var maxX = this.getSvgWidth('x'),
maxY = this.getSvgHeight('y');
return `0 0 ${maxX} ${maxY}`;
};
PipelineEditorWidget.prototype.refreshThumbnail = _.debounce(function() {
// Get the svg...
var svg = document.createElement('svg'),
group = this.$svg.node(),
child;
svg.setAttribute('viewBox', this.getViewBox());
for (var i = 0; i < group.children.length; i++) {
child = $(group.children[i]);
svg.appendChild(child.clone()[0]);
}
this.updateThumbnail(svg.outerHTML);
}, 1000);
return PipelineEditorWidget;
});

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais