Comparar commits
1 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 3676d4c340 |
@@ -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
|
||||
|
||||
@@ -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
@@ -4,22 +4,16 @@
|
||||
[](https://gitter.im/dfst/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](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.
|
||||
|
||||

|
||||
|
||||
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!
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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'));
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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...`);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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 @@
|
||||
0.4.0
|
||||
0.2.0
|
||||
Arquivo binário não exibido.
@@ -1 +1 @@
|
||||
0.4.0
|
||||
0.3.0
|
||||
Arquivo binário não exibido.
@@ -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;
|
||||
});
|
||||
+6
-6
@@ -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();
|
||||
};
|
||||
|
||||
+3
-3
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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>
|
||||
+17
-22
@@ -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
Referência em uma Nova Issue
Bloquear um usuário