Comparar commits

..

88 Commits

Autor SHA1 Mensagem Data
Brian Broll d88b758f43 v0.10.0 2016-07-25 12:05:58 -05:00
Brian Broll 0e6ae8f9b6 Added deepforge management cli. Fixes #526 (#545)
WIP #526 Added update command

WIP #526 Added start command

WIP #488 Added mongo detection

WIP #526 Added torch checking & installation

WIP #526 Added help if no args and 'mongodb not installed' msg

WIP #526 Made mongo check into a promise

WIP #526 Made mongodb dir customizable

WIP #526 Config getting/setting

WIP #526 Fixed mongodb starting/checking

WIP #526 Added --torch to update cmd

WIP #526 Added uninstall command

WIP #526 Added --server opt to update and updated package.json

WIP #526 Added eslintrc for bin scripts

WIP #526 minor description fix

WIP #526 Fixed missing dependency

WIP #526 Added some cli test boilerplate

WIP #526 Added cli tests
2016-07-25 12:03:31 -05:00
Brian Broll 3426a07096 Added graphing support in operations/jobs. Fixes #488 (#543)
WIP #488 Added logs for graph plotting

WIP #488 Added graph creation from cmdline logs

WIP #488 Fixed JobEditor bugs exposed by metadata

WIP #488 Removed old metadata on ExecuteJob

WIP #488 Moved graph points to graph attribute

WIP #488 Removed extra whitespace in points

WIP #488 Fixed graph id collisions between jobs

WIP #488 Created OutputViewer

WIP #488 Added filtering for the metadata nodes

WIP #488 Fixed visibility

WIP #488 Adding auto hide when not relevant

WIP #488 remove entries from pagination on delete

WIP #488 Added initialization to the LineGraph

WIP #488 Added LineGraph viz boilerplate

WIP #488 Added basic linegraph

WIP #488 Set LineGraph to use the 'Graph' node

WIP #488 Fixed double-playing commands

WIP #488 Fixed graph sizing and showing in the outputviewer

WIP #488 Adding metadata updating support

WIP #488 Updating graph w/ new data

WIP #488 Added some multi-line support

WIP #488 Added mult-line support for LineGraph

WIP #488 Added Graph metadata type

WIP #488 Fixed 'No Data Available' on quick graph open

WIP #488 revert to console if active graph deleted

WIP #488 Fixed graph update error

WIP #488 Fixed JobEditor nodeId checking

WIP #488 Removed 'points' from Graph

WIP #488 Filtered out deepforge commands from stdout

WIP #488 Fixed filtering deepforge cmds

WIP #488 Fixed ExecutePipeline

WIP #488 Added nvd3 to codeclimate ignore

WIP #488. better error handling for incorrect node types

WIP #488 Removed extra files and fixed code climate issues
2016-07-22 21:12:05 -05:00
Brian Broll e95f611b79 Fixed side-effects to ast on var usage detection. Fixes #538 (#539) 2016-07-20 20:59:43 -05:00
Brian Broll 5d0f13c5ec Moved default execution management to server. Fixes #363 (#537)
WIP #363 Fixed plugin execution on server

WIP #363 Changed primary execution env to the server

WIP #363 Set initial pipeline execution to be on server
2016-07-20 18:39:35 -05:00
Brian Broll 88e1f3828e Removed lineOffset from pipeline editor ops. Fixes #535 (#536) 2016-07-20 09:43:43 -05:00
Brian Broll 4de9cf29fe Retrieved all attribute names (inc reserved names). Fixes #533 (#534) 2016-07-20 08:37:19 -05:00
Brian Broll 448616be12 Hide 'lineOffset' in operation interface editor. Fixes #531 (#532)
WIP #531 Created Constants for lineOffset

WIP #531 Removed 'lineOffset' from visible op node attr
2016-07-20 08:24:56 -05:00
Brian Broll 93a2905534 Set shiftKey check for secondary exec env. Fixes #528 (#530)
WIP #528 Fixed code climate issue
2016-07-19 12:40:24 -05:00
Brian Broll 0bd0bd70f2 Removed dialog from restart execution button. Fixes #524 (#529)
WIP #524 Added restart execution button

WIP #524 Removed 'ExecPipeline' from Executions
2016-07-19 11:04:29 -05:00
Brian Broll 1720fc869a Correct op code line numbers in job editor. Fixes #229 (#527)
WIP #229 Added line number offset support to viz's

WIP #229 Store line offset when generating the op main file

WIP #229 Added 'lineOffset' to 'Operation'

WIP #229. Fixing code climate issues
2016-07-19 10:38:30 -05:00
Brian Broll 41e7750dd1 Created JobEditor for non-snapshotted executions. Fixes #364 (#525)
WIP #364 Created ExecuteJob plugin

WIP #364 ExecutePipeline working again

WIP #364 Added restart job fn-ality

WIP #364 Fixed job status updating

WIP #364 Added JobEditor

WIP #364 Fixed class deserialization

WIP #364 Update exec status on job complete

WIP #364 Fixed JobEditor view for snapshotted jobs

WIP #364 Updated seeds

WIP #364 verify current node is Job

WIP #364 Fixed code climate issues

WIP #364 Fixed some code duplication
2016-07-19 09:44:06 -05:00
Brian Broll 81afc81887 Added unused output detection. Fixes #518 (#522)
WIP #518 Fixed usage update
2016-07-18 21:21:31 -05:00
Brian Broll 3e9931fa3b Added better error handing for invalid lua in op. Fixes #520 (#521)
WIP #520 removed usage info on ptr delete
2016-07-18 20:16:27 -05:00
Brian Broll 5135ccef09 v0.9.0 2016-07-18 08:39:49 -05:00
Brian Broll 6314e00a8d Fixed the attribute shown in deserialize viz. Fixes #512 (#517) 2016-07-17 21:10:22 -05:00
Brian Broll 779429e24d Fixed obj changed pass thru in main view. Fixes #513 (#514) 2016-07-17 20:34:15 -05:00
Brian Broll a7f4eac09d Updated arch editor tooltip init. Fixes #515 (#516) 2016-07-17 20:34:01 -05:00
Brian Broll 7c645e9b23 Added unused op input warning. Fixes #499 (#511)
WIP #499 Added unused input detection

WIP #499. Added input highlight updating on code change

WIP #499 Added warning tooltip and fixed removal

WIP #499 Fixed warning location on position change

WIP #499 Removed unnecessary timeout

WIP #499 Added sophisticated usage checking

WIP #499 Removed code climate issues
2016-07-16 22:42:14 -05:00
Brian Broll fc3e14644f Updated the selObjChanged to update pipeline list. Fixes #507 (#508)
WIP #507 set webgme-autoviz to track master
2016-07-16 15:37:59 -05:00
Brian Broll fd48c1b480 Removed panel padding. Fixes #502 (#506)
WIP #502 Removed padding from the tiling viz's panel
2016-07-16 14:14:11 -05:00
Brian Broll 8928d0f105 Removed old 'code' attr. Fixes #93 (#505) 2016-07-16 13:53:11 -05:00
Brian Broll 6857da5ac7 Updated webgme-autoviz. Fixes #503 (#504) 2016-07-16 13:40:01 -05:00
Brian Broll fee584cfde Added lenet arch to cifar10 example. Fixes #66 (#501) 2016-07-15 20:13:24 -05:00
Brian Broll 45fcd81739 Added tracking EOF for log viewer. Fixes #304 (#500)
WIP #304 Added scroll to bottom

WIP #304 Added eof detection
2016-07-15 17:48:14 -05:00
Brian Broll d831f5e032 Added ubuntu support to install script. Fixes #395 (#498)
WIP #395 Added ubuntu/arch detection

WIP #395 added manual nvm loading

WIP #395 Added source post-installation instructions

WIP #395 Added ubuntu/arch detection
2016-07-15 16:06:18 -05:00
Brian Broll 65e938f489 Created better execution fork names. Fixes #494 (#496)
Improved execution fork name. Fixes #494
2016-07-15 10:25:33 -05:00
Brian Broll b9b5cea5a1 Added exec fork notification. Fixes #345 (#495) 2016-07-15 10:08:26 -05:00
Brian Broll 6c639376d1 Added attributes to condense for width calc. Fixes #492 (#493) 2016-07-15 09:27:03 -05:00
Brian Broll 58ed3048f8 Updated OperationDecorator transitions. Fixes #490 (#491) 2016-07-15 07:41:00 -05:00
Brian Broll f64492061d Added operation attribute support. Fixes #487 (#489)
WIP #487 Added attr edit/del fn-ality

WIP #487 Added attribute creation

WIP #487 Fixed invalid name list

WIP #487 Fixed code climate issue

WIP #487 Fixed operation only behavoirs

WIP #487 Removed 'code' attribute and added number check

WIP #487 Added scientific notation detection

WIP #487 Updated seeds
2016-07-14 12:19:04 -05:00
Brian Broll 552e71687d Added editors to preload by autoviz. Fixes #479 (#486)
WIP #479 Updated autoviz version
2016-07-13 09:37:29 -05:00
Brian Broll 448de23945 Check if instance exists before invoking ser method. Fixes #484 (#485) 2016-07-11 13:53:25 -05:00
Brian Broll dbd00e5946 Added filter for 'return to' action btns. Fixes #482 (#483) 2016-07-11 13:38:38 -05:00
Brian Broll 4d0b4ae017 Added primitive renaming support (by editing comment). Fixes #444 (#480)
WIP #444 Naming support for SerializeEditor

WIP #444 Added renaming functionality for the deserialize editor

WIP #444 Fixed code climate issues
2016-07-11 13:03:20 -05:00
Brian Broll d6c201cce6 Retrieve the deser fn from source node. Fixes #245 (#478) 2016-07-11 12:12:08 -05:00
Brian Broll b8bc3af524 Escaped quoted operation name in log. Fixes #470 (#475) 2016-07-11 11:48:54 -05:00
Brian Broll 72de1d44da Set inputs/outputs for all nodes in pipeline editor. Fixes #411 (#473) 2016-07-11 10:51:02 -05:00
Brian Broll da6f186b52 Added string, boolean types. Fixes #471 (#474) 2016-07-11 10:50:57 -05:00
Brian Broll 5f1c50beb6 Removed territory on text editor destory. Fixes #409 (#472) 2016-07-11 10:50:52 -05:00
Brian Broll 3a79afbc41 v0.8.0 2016-07-11 10:30:22 -05:00
Brian Broll ba210e4b27 Updated icons. Fixes #406 (#469)
WIP #406 Updated some icons

WIP #406 Updated the terminal icon

WIP #406 Updated operation interface icons

WIP #406 terminal -> monitor icon

WIP #406 Fixed code climate issue
2016-07-09 17:15:44 -05:00
Brian Broll bdb21a5262 Set title to regular case. Fixes #467 (#468) 2016-07-09 16:05:30 -05:00
Brian Broll 4b6471efbc Updated buttons and methods for webgme-easydag update. Fixes #465 (#466)
WIP #465 Updated onAddButtonClicked

WIP #465 Updated callbacks for webgme-easydag update

WIP #465 Fixing code climate issue
2016-07-09 15:42:04 -05:00
JimnyCricket beeb1deb3c Merge pull request #457 from dfst/456-simple-cifar
Split cifar10 example into 4 pipelines. Fixes #456
2016-07-08 17:37:19 -05:00
Brian Broll 0bc6846c32 Optimized the arch editor layer selection. Fixes #78 (#463)
WIP #78 ~3x speedup in arch editor

WIP #78 Removed unused var
2016-07-08 10:00:47 -06:00
Brian Broll 8a40cb95fb Updated and configured breadcrumbheader. Fixes #441 (#462) 2016-07-08 07:29:45 -06:00
Brian Broll 92ea4b2ff5 Removed ptrs from op desc in OpIntEditor. Fixes #433 (#461) 2016-07-07 17:48:56 -06:00
Brian Broll e0a83b4d6c Added 'print', 'SGD' ops. Fixes #368 (#460) 2016-07-07 17:41:58 -06:00
Brian Broll 49268b9554 Fixed arch update on main screen. Fixes #458 (#459) 2016-07-07 17:41:51 -06:00
Brian Broll 65164bcb76 Merge branch 'master' into 456-simple-cifar 2016-07-07 17:31:43 -05:00
Brian Broll 1afcaf9238 Split cifar10 example into 4 pipelines. Fixes #456 2016-07-07 17:30:34 -05:00
Brian Broll 92021a06ba Decreased cifar10 max iterations. Fixes #424 (#455) 2016-07-07 15:48:18 -06:00
Brian Broll be1e4fa388 Added 'Data' to op input options. Fixes #376 (#454)
WIP #376 Removed 'Data' from output options
2016-07-07 15:17:27 -06:00
JimnyCricket 09505c9989 Clears jobs on restart of server Fixes #452 (#453) 2016-07-07 14:57:34 -06:00
Brian Broll b96f2a845a Added criterion reference support. Fixes #369 (#450)
WIP #369 Removed criterion filter

WIP #396 Added criterion layers to nn seed

WIP #369 Added GenerateCriterion plugin

WIP #369 Added GenerateCriterion to criterion meta

WIP #369 Filtered criterion from the ArchEditor

WIP Removed old css

WIP #369 filtered criterion types

WIP #369. Fixed criterion pointer assignment

WIP #369 Fixed criterion execution problems

WIP #369 Updated seeds

WIP #369 Fixed failing test
2016-07-07 11:54:09 -06:00
Brian Broll 14c0af86c9 Added import torch action to arch editor. Fixes #447 (#449) 2016-07-07 10:29:13 -06:00
Brian Broll 56a0b788ee Added editable title for architecture. Fixes #445 (#448)
WIP #445 Refactoring the panel title renaming

WIP #445 Made arch editor renameable

WIP #445 Fixed capitalization for consistency
2016-07-07 10:28:54 -06:00
Brian Broll 873cbc2145 Updated main view to have nav bar and pipeline index. Fixes #440 (#446)
WIP #440 Added MainView

WIP #440 Removed unneeded files

WIP #440 Added basic left bar

WIP #440 Added root node actions

WIP #440 Embedded PipelineIndex

WIP #440 Removed unused js

WIP #440 Removed setTimeout

WIP #440 Fixed some layout issues. css reduction

WIP #440 Added glyphicon

WIP #440 Fixed menu control icon placement, size, color

WIP

WIP #440 Added opening/closing of the nav bar

WIP #440 Added grey background-color

WIP #440 Fixed hide on small screens

WIP #440. Added action buttons

WIP #440 Fixed arch-content list

WIP #440 Removed bullet points

WIP #440 Fixed resize positioning

WIP #440 Increased font size for headers

WIP #440 italic actions

WIP #440 Added some structure for the artifacts

WIP #440 Added download artifact link

WIP #440 Fixed lingering territory rules

WIP #440 removed unused lib files

WIP #440 Fixed code climate issues
2016-07-07 09:21:35 -06:00
Brian Broll 3e3326688c Added meaningful error if retrieving nil val from layer. Fixes #386 (#442)
WIP #386 Added googlenet-setters for testing error messages

WIP #386 Commented out tacking in extra values

WIP #386 Ignore "nil gets" if in "set" operation
2016-07-01 13:14:06 -05:00
Brian Broll 6e32394e01 Added pipeline index viz. Fixes #429 (#438)
WIP #429 Added basic boilerplate for the pipeline index viz

WIP #429 Removed the title

WIP #429 Fixed columns (and text)

WIP #429 Added open, delete actions

WIP #429 Added double click to edit pipeline name

WIP #429 Added check for empty, same name

WIP #429 Added comment for thing to add next

WIP #429 Added some thumbnail support and embedded support

WIP #429 Fixed the thumbnail

WIP #429 thumbnail updates

WIP #429 Set background color and fixed updateNode bug

WIP #429 Fixed update thumbnail deletion

WIP #429 Added preview click-to-open

WIP #429 Added empty message

WIP #429 slight refactor

WIP #429 Added executions text (better phrasing)

WIP #429 Removed toolbar items

WIP #429 Fixed remove undefined bug

WIP #429 Updated seeds

WIP #429 Added pipeline index css to ignore

WIP #429 Fixed code climate issues

WIP #429 Added csslint ignore file

WIP #429 Fixed code climate issues

WIP #429 Added csslint ignore block for materialize

WIP #429 Added thumbnails to cifar10 example
2016-06-30 15:33:05 -05:00
Brian Broll afed957af8 Set artifact loader to remove data handle on "unset". Fixes #437 (#439) 2016-06-30 15:24:42 -05:00
Brian Broll 4c100ac001 Added support for creating primitive types from op editor. Fixes #432 (#435)
WIP #432 Added basic support for primitive/complex coloring and creation

WIP #432 Added tabs
2016-06-30 14:46:06 -05:00
Brian Broll 29724551f0 Updated reference selection btns in op editor. Fixes #434 (#436) 2016-06-29 14:50:18 -05:00
Brian Broll 1f5c8d7423 Updated ImportArtifact result checking. Fixes #427 (#431) 2016-06-29 13:24:18 -05:00
Brian Broll a613a1e8f7 Added artifact upload from ArtifactLoader. Fixes #422 (#428)
WIP #422 Added upload artifact icon

WIP #422 Added upload artifact functionality
2016-06-29 13:10:09 -05:00
JimnyCricket 7fce6e98dd Merge pull request #426 from dfst/425-port-must-be-num
Casted PORT to num. Fixes #425
2016-06-29 11:04:09 -07:00
Brian Broll ea572e8f6c Casted PORT to num. Fixes #425 2016-06-29 12:26:24 -05:00
Brian Broll 36290d8dc7 Removed the data type card. Fixes #420 (#421) 2016-06-29 09:32:50 -05:00
Brian Broll dadc09e0e1 Added delete, return-to-op fab actions for Primitive editing. Fixes #418 (#419) 2016-06-29 09:07:17 -05:00
Brian Broll be3d278d13 Added GoToBase btn for data in op editor. Fixes #414 (#417) 2016-06-29 09:00:22 -05:00
Brian Broll 32a96fbf2b Added class def -> op editor pivots and del btn. Fixes #413 (#416)
WIP #413. Fixed code climate issue
2016-06-29 08:51:38 -05:00
Brian Broll ebe391c948 Added 'Create Class' node in OperationEditor. Fixes #171 (#415)
WIP #171 Adding support for new classes

WIP #171. Fixed "New Class" tooltip

WIP #171 Fixed eslint error
2016-06-29 08:41:15 -05:00
Brian Broll e30ebf3a45 Added os not recognized message. Fixes #404 (#405)
WIP #404 Added "install mongo" message at end

WIP #404 Fixed message when mongo installed
2016-06-28 15:43:37 -05:00
Brian Broll 9e0a780ed2 Updated new op name to conform to new layer name. Fixes #399 (#403) 2016-06-28 15:17:58 -05:00
Brian Broll 841637e804 Updated plugin names and icons. Fixes #401 (#402) 2016-06-28 15:01:44 -05:00
Brian Broll 75241262c4 Added delete custom layer def. Fixes #389 (#400)
WIP #389 code climate fix
2016-06-28 14:37:40 -05:00
Brian Broll b39ac022b6 Added operation deletion button. Fixes #390 (#398)
WIP #390 Added delete button (non-func)

WIP #390 Added deletion func for deleting current node
2016-06-28 14:20:05 -05:00
Brian Broll 8486b86a05 Added pivot back to last arch from custom layer. Fixes #388 (#396)
WIP #388 Refactored op -> pipeline pivoting
2016-06-28 13:53:36 -05:00
Brian Broll 322af8a4f5 Removed 'MyLayers' card. Fixes #391 (#394) 2016-06-28 13:39:49 -05:00
Brian Broll 5e1930f096 Added tabs to initial layer dialog. Fixes #392 (#393) 2016-06-28 13:09:28 -05:00
Brian Broll c0f1348a14 Added sponsor info and removed caffe support comment 2016-06-28 13:06:35 -05:00
Brian Broll 383f5f9fa0 Added (tabbed) custom layer creation from arch editor. Fixes #385 (#387)
WIP #385 Added node icons to arch creator.

WIP #385 Updated for new AddNodeDialog.prompt interface

WIP #385 Added tabs to layers and create layer support

WIP #385 Added code climate ignore dup (non) issue

WIP Added codeclimate, csslint configs
2016-06-28 10:50:40 -05:00
Brian Broll 5cf592e103 removed old 'demo' seed. Fixes #365 (#384) 2016-06-28 07:46:26 -05:00
Brian Broll a14e750b6f Made pipeline title editable. Fixes #375 (#383) 2016-06-27 16:12:25 -05:00
Brian Broll 73e165197f Added editable operation title & better header comment. Fixes #380 (#381)
WIP #380 Added editable title

WIP #380 Updated the operation header comment

WIP #380 Fixed code climate warning
2016-06-27 14:26:59 -05:00
Brian Broll 9dd0815625 Auto-remove dangling connections in pipelines. Fixes #377 (#382) 2016-06-27 14:26:51 -05:00
Brian Broll 8e3ac1d203 Removed Ops, Execs cards from root view. Fixes #373 (#379) 2016-06-27 13:45:32 -05:00
112 arquivos alterados com 26067 adições e 1190 exclusões
+36
Ver Arquivo
@@ -0,0 +1,36 @@
---
engines:
csslint:
enabled: true
duplication:
enabled: true
exclude_fingerprints:
- 1e004cf4e49528a58a0ac3858112601c
config:
languages:
- ruby
- javascript
- python
- php
eslint:
enabled: true
fixme:
enabled: true
ratings:
paths:
- "**.css"
- "**.inc"
- "**.js"
- "**.jsx"
- "**.module"
- "**.php"
- "**.py"
- "**.rb"
exclude_paths:
- config/
- test/
- src/common/lua.js
- src/common/js-yaml.min.js
- src/visualizers/widgets/TextEditor/lib/
- src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
- src/visualizers/widgets/LineGraph/lib/
+3
Ver Arquivo
@@ -0,0 +1,3 @@
--exclude-exts=.min.css
--exclude-list=src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
+4 -4
Ver Arquivo
@@ -1,10 +1,10 @@
[![Release State](https://img.shields.io/badge/state-alpha-orange.svg)](https://img.shields.io/badge/state-alpha-orange.svg)
[![Release State](https://img.shields.io/badge/state-beta-yellow.svg)](https://img.shields.io/badge/state-beta-yellow.svg)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE)
[![Build Status](https://travis-ci.org/dfst/deepforge.svg?branch=master)](https://travis-ci.org/dfst/deepforge)
[![Join the chat at https://gitter.im/dfst/deepforge](https://badges.gitter.im/dfst/deepforge.svg)](https://gitter.im/dfst/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Stories in Ready](https://badge.waffle.io/dfst/deepforge.png?label=ready&title=Ready)](https://waffle.io/dfst/deepforge)
**Notice**: DeepForge is still very much 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)!
**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. Currently, it supports Convolutional Neural Networks but we are planning on supporting additional deep learning classifiers such as RNNs and LSTMs. Additional features include real-time collaborative editing and version control.
@@ -20,8 +20,8 @@ Next, follow the postinstall instructions to start MongoDB and DeepForge!
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions,check out our [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
## Caffe Support?
DeepForge uses Torch to perform the actual training and testing of the models. If you are interested in DeepForge using Caffe for actual training and testing, check out [DeepForge-Caffe](https://github.com/dfst/deepforge-caffe).
## Interested in contributing?
Contributions are welcome! Either fork the project and submit some PR's or shoot me an email about getting more involved!
Sponsored by [Digital Reasoning](http://www.digitalreasoning.com/)
+21
Ver Arquivo
@@ -0,0 +1,21 @@
env:
browser: true
node: true
mocha: true
es6: true
extends: 'eslint:recommended'
rules:
no-console:
- 0
indent:
- 2
- 4
linebreak-style:
- 2
- unix
quotes:
- 2
- single
semi:
- 2
- always
+8
Ver Arquivo
@@ -0,0 +1,8 @@
{
"torch": {
"dir": "~/.deepforge/torch"
},
"mongo": {
"dir": "~/.deepforge/data"
}
}
Arquivo executável
+393
Ver Arquivo
@@ -0,0 +1,393 @@
#!/usr/bin/env node
var Command = require('commander').Command,
program = new Command(),
childProcess = require('child_process'),
spawn = childProcess.spawn,
execSync = childProcess.execSync,
path = require('path'),
fs = require('fs'),
version = require('../package.json').version,
exists = require('exists-file'),
forever = require('forever-monitor'),
DEFAULT_CONFIG = require('./config.json'),
assign = require('lodash.assign'),
config,
configDir = path.join(process.env.HOME, '.deepforge'),
configPath = path.join(configDir, 'config.json'),
dataPath = path.join(configDir, 'data'),
localConfig,
p = dir => dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
// Check for any commands
if (process.argv.length === 2) {
process.argv.push('--help');
}
// Create the config if it doesn't exist
if (!exists.sync(configDir)) {
fs.mkdirSync(configDir);
}
if (!exists.sync(dataPath)) {
fs.mkdirSync(dataPath);
}
if (!exists.sync(configPath)) {
fs.writeFileSync(configPath, '{\n}');
}
localConfig = require(configPath);
config = assign(DEFAULT_CONFIG, require(configPath));
var getConfigValue = function(id) {
var keys = id.split('.'),
value = config;
for (var i = 0; i < keys.length; i++) {
value = value[keys[i]];
if (!value) {
return null;
}
}
return value;
};
var storeConfig = function(id, value) {
// load the config
var keys = id.split('.').filter(k => k),
lastKey = keys.pop(),
currentObj = localConfig,
current = getConfigValue(id);
// Check if it is a valid key
if (current === null) {
return false;
}
for (var i = 0; i < keys.length; i++) {
if (!currentObj[keys[i]]) {
currentObj[keys[i]] = {};
}
currentObj = currentObj[keys[i]];
}
currentObj[lastKey] = value;
fs.writeFileSync(configPath, JSON.stringify(localConfig, null, 2));
return true;
};
program
.version('v' + version)
.description('Command line interface for managing deepforge');
// start
var start = function(main, opts) {
var child = new forever.Monitor(main, opts);
child.on('exit', function () {
console.log('Exited after 3 failed restarts');
});
child.start();
};
var isLocalUri = function(protocol, uri) {
return uri.indexOf(protocol + '://localhost') === 0 ||
uri.indexOf(protocol + '://127.0.0.1') === 0;
};
var checkMongo = function(args) {
// check the webgme config
var gmeConfig = require('../config'),
mongoUri = gmeConfig.mongo.uri;
if (isLocalUri('mongodb', mongoUri)) {
// Make sure mongo is running locally (using pgrep)
try {
execSync('pgrep mongod').toString();
console.log('MongoDB is already running!');
} catch (e) { // no pIds
console.log('Starting MongoDB...');
startMongo(args, true);
}
}
};
var startMongo = function(args, silent) {
var job = spawn('mongod', ['--dbpath', p(config.mongo.dir)], {
cwd: process.env.HOME
});
if (!silent) {
job.stdout.on('data',
data => process.stdout.write(data.toString()));
}
job.on('error', err => {
if (err.code === 'ENOENT') {
console.log('Could not find MongoDB. Is it installed?');
if (!args.mongo) {
console.log('Otherwise, set MONGO_URI to the desired mongo uri and try again:');
console.log('');
console.log(' MONGO_URI=mongodb://some.other.ip:27017' +
`/deepforge deepforge ${process.argv.slice(2).join(' ')}`);
console.log('');
}
} else {
console.log('Error encountered while starting MongoDB');
throw err;
}
});
job.stderr.on('data', data => {
var msg = 'mongodb: ' + data;
process.stdout.write(msg);
});
job.on('exit', code => {
if (code) {
console.log('MongoDB closed w/ error code: ' + code);
}
});
};
var checkTorch = function() {
return new Promise(_checkTorch)
.catch(() => 'Torch installation failed');
};
var _checkTorch = function(resolve, reject) {
var result = childProcess.spawnSync('th', ['--help']),
tgtDir = p(config.torch.dir),
cmds;
if (result.error) {
// Try to install torch
console.log(`Torch7 not found. Installing to ${tgtDir}...`);
cmds = [
`git clone https://github.com/torch/distro.git ${tgtDir} --recursive`,
`cd ${tgtDir}`,
'bash install-deps',
'./install.sh'
];
spawnMany(cmds,
() => {
storeConfig('torch.dir', tgtDir);
resolve(true);
},
reject
);
} else {
resolve(false);
}
};
var spawnMany = function(cmds, succ, err) {
var rawCmd,
cmd,
args,
job;
if (cmds.length === 0) {
return succ();
}
rawCmd = cmds.shift();
args = rawCmd.split(' ');
cmd = args.shift();
job = spawn(cmd, args);
job.stdout.on('data', data => process.stdout.write(data));
job.stderr.on('data', data => process.stderr.write(data));
job.on('close', code => {
if (code) {
console.log(`${rawCmd} failed w/ error code ${code}`);
err(code, rawCmd);
} else {
spawnMany(cmds, succ, err);
}
});
};
program.command('start')
.description('start deepforge locally (default) or specific components')
.option('-p, --port <port>', 'specify the port to use')
.option('-s, --server', 'start the server')
.option('-w, --worker [url]', 'start a worker and connect to given url. Defaults to local deepforge')
.option('-m, --mongo', 'start MongoDB')
.action(args => {
var main = path.join(__dirname, 'start-local.js'),
opts;
opts = {
max: 3,
args: []
};
if (args.port) {
opts.env = {
PORT: args.port
};
}
if (args.server) {
checkMongo(args);
main = path.join(__dirname, '..', 'app.js');
start(main, opts);
}
if (args.worker) {
checkTorch().then(() => {
main = path.join(__dirname, 'start-worker.js');
if (args.worker !== true) {
opts.args.push(args.worker);
}
start(main, opts);
});
}
if (args.mongo) {
startMongo(args);
}
if (!args.server && !args.worker && !args.mongo) {
// Starting everything
checkMongo(args);
checkTorch().then(() => start(main, opts));
}
});
// update
program
.command('update')
.description('upgrade deepforge to latest version')
.option('-g, --git', 'update tracking the git repo')
.option('-t, --torch', 'update torch installation')
.option('-s, --server', 'update deepforge')
.action(args => {
var pkg = 'deepforge',
job,
latestVersion;
// Install the project
if (!args.torch || args.server) {
if (args.git) {
pkg = 'dfst/deepforge';
} else {
// Check the version
try {
latestVersion = execSync('npm show deepforge version')
.toString().replace(/\s+$/, '');
if (latestVersion === version) {
console.log('Already up-to-date');
return;
}
} catch (e) {
console.log('Could not retrieve the latest deepforge version');
}
}
job = spawn('npm', ['install', '-g', pkg]);
job.stdout.on('data', data => process.stdout.write(data.toString()));
job.stderr.on('data', data => process.stderr.write(data.toString()));
job.on('close', code => {
if (!code) {
console.log('Upgrade successful!');
} else {
console.log('Upgrade failed w/ error code: ' + code);
}
});
}
if (args.torch || !args.server) {
// Update torch
checkTorch().then(justInstalled => {
if (!justInstalled) {
// Upgrade torch
console.log('Upgrading torch...');
job = spawn('bash', ['./update.sh'], {
cwd: p(config.torch.dir)
});
job.stdout.on('data', data => process.stdout.write(data.toString()));
job.stderr.on('data', data => process.stderr.write(data.toString()));
job.on('close', code => {
if (!code) {
console.log('Upgrade successful!');
} else {
console.log('Upgrade failed w/ error code: ' + code);
}
});
}
});
}
});
// uninstall command
program
.command('uninstall')
.description('uninstall deepforge from the system')
.option('-t, --torch', 'uninstall torch')
.option('-c, --clean', 'uninstall deepforge, torch and all associated data/config')
.action(opts => {
if (opts.torch || opts.clean) {
if (opts.torch) {
console.log(`uninstalling torch at ${p(config.torch.dir)}`);
}
fs.unlinkSync(p(config.torch.dir));
}
if (opts.clean) { // remove the .deepforge directory
console.log('removing config and data files...');
fs.unlinkSync(p(config.mongo.dir));
fs.unlinkSync(p(configDir));
}
if (!opts.torch || opts.clean) { // uninstall deepforge
spawnMany(
['npm uninstall -g deepforge'],
() => console.log('deepforge has been uninstalled!'),
() => console.log('uninstall failed')
);
}
});
// config
program
.command('config [key] [value]')
.description('read or edit config options (omit "value" to see current value)')
.action(key => {
var value = program.args[1],
success;
if (value) { // write a value
success = storeConfig(key, value);
if (success) {
console.log('Config has been updated!');
}
} else if (key) { // read a single value
value = getConfigValue(key);
if (value === null) {
console.log(`Invalid config value: "${key}"`);
return;
}
if (typeof value === 'object') {
value = JSON.stringify(value, null, 2);
}
console.log(value);
} else { // print entire config
console.log(`Current config:\n${JSON.stringify(config, null, 2)}`);
}
});
module.exports = function(cmd) {
var cmds = cmd.split(/\s+/).filter(w => !!w);
cmds.unshift('node');
cmds.unshift('./bin/deepforge');
program.parse(cmds);
};
if (require.main === module) {
program.parse(process.argv);
}
+16 -27
Ver Arquivo
@@ -1,8 +1,19 @@
{
"AutoViz": {
"preloadIds": [
"ArchEditor",
"PipelineEditor",
"OperationEditor",
"ExecutionView"
]
},
"ArchEditor": {
"hotkeys": "none",
"LayerColors": {}
},
"BreadcrumbHeader": {
"pathRule": "history"
},
"FloatingActionButton": {
"hideOnEmpty": true
},
@@ -43,48 +54,26 @@
"nodes": [
{
"nodeName": "MyArchitectures",
"title": "Architectures",
"icon": "shuffle",
"rank": 1,
"description": "Neural network architectures are stored here and can be used in pipelines."
},
{
"nodeName": "MyOperations",
"icon": "mode_edit",
"rank": 2,
"color": "blue-grey",
"description": "Operations are the building blocks of pipelines. Custom operations can be created and stored here."
},
{
"nodeName": "MyPipelines",
"title": "Pipelines",
"color": "blue-grey",
"icon": "input",
"rank": 3,
"description": "Pipelines compose operations together to effectively train, test and/or ensemble models."
},
{
"nodeName": "MyLayers",
"icon": "clear_all",
"rank": 4,
"color": "blue-grey",
"description": "Custom torch layers can be created and stored here for use in neural network architectures."
},
{
"nodeName": "MyArtifacts",
"title": "Artifacts",
"icon": "view_quilt",
"color": "blue-grey",
"rank": 5,
"description": "Artifacts from pipeline executions are stored here."
},
{
"nodeName": "MyExecutions",
"icon": "list",
"rank": 6,
"color": "blue-grey",
"description": "Executions are read-only snapshots of pipelines that have been executed. Past and current executing pipelines are stored here."
},
{
"nodeName": "MyDataTypes",
"icon": "settings",
"rank": 7,
"description": "Custom defined data types are stored here."
}
]
}
+2 -1
Ver Arquivo
@@ -7,7 +7,7 @@ var config = require('./config.webgme'),
require('dotenv').load({silent: true});
// Add/overwrite any additional settings here
config.server.port = process.env.PORT || config.server.port;
config.server.port = +process.env.PORT || config.server.port;
config.mongo.uri = process.env.MONGO_URI || config.mongo.uri;
config.requirejsPaths.deepforge = './src/common';
config.seedProjects.defaultProject = 'project';
@@ -16,6 +16,7 @@ config.plugin.allowBrowserExecution = true;
config.plugin.allowServerExecution = true;
config.executor.enable = true;
config.executor.clearOldDataAtStartUp = true;
config.visualization.extraCss.push('deepforge/styles/global.css');
-1
Ver Arquivo
@@ -18,7 +18,6 @@ config.seedProjects.basePaths.push('src/seeds/devTests');
config.seedProjects.basePaths.push('src/seeds/devUtilTests');
config.seedProjects.basePaths.push('src/seeds/pipeline');
config.seedProjects.basePaths.push('src/seeds/devPipelineTests');
config.seedProjects.basePaths.push('src/seeds/demo');
config.seedProjects.basePaths.push('src/seeds/project');
config.seedProjects.basePaths.push('src/seeds/cifar10');
+42 -2
Ver Arquivo
@@ -53,6 +53,7 @@ command -v node >/dev/null 2>&1 || {
echo >&2 "NodeJS is not found. Installing (using nvm)...";
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash;
source $DETECTED_PROFILE
. $NVM_DIR/nvm.sh
# Install nodejs v6.2.0
echo "Installing nodejs v6.2.0"
@@ -61,7 +62,6 @@ command -v node >/dev/null 2>&1 || {
# Install npm@2
npm install npm@2 -g
}
command -v node >/dev/null 2>&1 || {
@@ -69,6 +69,35 @@ command -v node >/dev/null 2>&1 || {
echo >&2 "MongoDB is not found. Installing...";
if [[ `uname` == "Darwin" ]]; then
brew install mongodb
elif [[ "$(uname)" == 'Linux' ]]; then
if [[ -r /etc/os-release ]]; then
# this will get the required information without dirtying any env state
DIST_VERS="$( ( . /etc/os-release &>/dev/null
echo "$ID $VERSION_ID") )"
DISTRO="${DIST_VERS%% *}" # get our distro name
VERSION="${DIST_VERS##* }" # get our version number
elif [[ -r /etc/lsb-release ]]; then
DIST_VERS="$( ( . /etc/lsb-release &>/dev/null
echo "${DISTRIB_ID,,} $DISTRIB_RELEASE") )"
DISTRO="${DIST_VERS%% *}" # get our distro name
VERSION="${DIST_VERS##* }" # get our version number
else # well, I'm out of ideas for now
echo '==> Failed to determine distro and version.'
exit 1
fi
# Detect archlinux
if [[ "$DISTRO" = "arch" ]]; then
distribution="archlinux"
sudo pacman -S mongodb
# Detect Ubuntu
elif [[ "$DISTRO" = "ubuntu" ]]; then
export DEBIAN_FRONTEND=noninteractive
sudo apt-get install mongodb
else
NEEDS_MONGO=true
fi
fi
}
@@ -80,7 +109,18 @@ cd ~/deepforge
npm install
mkdir ~/deepforge/data 2> /dev/null
echo "DeepForge is installed! To run it:"
echo "Final Installation steps:"
echo " 1) Close and re-open your terminal"
echo " (or run \"source $DETECTED_PROFILE\")"
if [[ $NEEDS_MONGO ]]; then
echo " 2) Install MongoDB for your OS"
echo " (available at https://www.mongodb.com/download-center)"
fi
echo ""
echo "Then run DeepForge!"
echo " 1) make sure MongoDB is running locally"
echo " (start mongo w/ \"mongod --dbpath ~/deepforge/data\")"
echo " 2) Run \"npm run local\" from ~/deepforge"
+13 -5
Ver Arquivo
@@ -1,5 +1,8 @@
{
"name": "deepforge",
"bin": {
"deepforge": "./bin/deepforge"
},
"scripts": {
"start": "node app.js",
"start-dev": "NODE_ENV=dev node app.js",
@@ -9,23 +12,28 @@
"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.7.0",
"version": "0.10.0",
"dependencies": {
"commander": "^2.9.0",
"dotenv": "^2.0.0",
"exists-file": "^2.1.0",
"forever-monitor": "^1.7.0",
"lodash.assign": "^4.0.9",
"lodash.difference": "^4.1.2",
"nodemon": "^1.9.2",
"webgme": "^2.0.0",
"webgme-autoviz": "^2.0.3",
"webgme-breadcrumbheader": "^2.0.0",
"webgme-autoviz": "dfst/webgme-autoviz",
"webgme-breadcrumbheader": "^2.1.0",
"webgme-chflayout": "^2.0.0",
"webgme-easydag": "dfst/webgme-easydag",
"webgme-fab": "dfst/webgme-fab",
"webgme-simple-nodes": "^2.0.0"
},
"devDependencies": {
"chai": "^3.0.0",
"jszip": "^2.5.0",
"mocha": "^2.2.5",
"rimraf": "^2.4.0",
"chai": "^3.0.0"
"mockery": "^1.7.0",
"rimraf": "^2.4.0"
}
}
+10
Ver Arquivo
@@ -0,0 +1,10 @@
/* globals define */
define({
LINE_OFFSET: 'lineOffset',
// DeepForge metadata creation in dist execution
START_CMD: 'deepforge-cmd',
GRAPH_CREATE: 'GRAPH',
GRAPH_PLOT: 'PLOT',
GRAPH_CREATE_LINE: 'LINE'
});
+97 -5
Ver Arquivo
@@ -1,4 +1,4 @@
/* globals WebGMEGlobal, define*/
/* globals Materialize, WebGMEGlobal, define*/
// This file creates the DeepForge namespace and defines basic actions
define([
'js/RegistryKeys',
@@ -89,13 +89,14 @@ define([
return name;
};
/////////// Initializing DeepForge ///////////
//////////////////// DeepForge places detection ////////////////////
var TYPE_TO_CONTAINER = {
Architecture: 'MyArchitectures',
Pipeline: 'MyPipelines',
Execution: 'MyExecutions',
Layer: 'MyLayers',
Artifact: 'MyArtifacts',
Operation: 'MyOperations',
Primitive: 'MyDataTypes',
Complex: 'MyDataTypes'
@@ -141,8 +142,7 @@ define([
placesTerritoryId = null;
};
// Add DeepForge action primitives
// Creating custom operations
//////////////////// DeepForge creation actions ////////////////////
var instances = [
'Architecture',
'Pipeline'
@@ -180,6 +180,92 @@ define([
return newId;
};
var createCustomLayer = function(typeName) {
var metanodes = client.getAllMetaNodes(),
msg = `Created new custom ${typeName} layer`,
newId,
customLayerId,
baseId,
name,
i = metanodes.length;
while (i-- && !(baseId && customLayerId)) {
name = metanodes[i].getAttribute('name');
if (name === 'CustomLayer') {
customLayerId = metanodes[i].getId();
} else if (name === typeName) {
baseId = metanodes[i].getId();
}
}
client.startTransaction(msg);
newId = createNamedNode(baseId, DeepForge.places.MyLayers, true);
addToMetaSheet(newId, 'CustomLayers');
client.addMixin(newId, customLayerId);
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(newId);
};
// Creating Artifacts
var UPLOAD_PLUGIN = 'ImportArtifact',
DATA_TYPE_CONFIG = {
name: 'dataTypeId',
displayName: 'Data Type Id',
valueType: 'string',
valueItems: []
};
var uploadArtifact = function() {
// Get the data types
var dataBase,
dataBaseId,
metanodes = client.getAllMetaNodes(),
dataTypes = [];
dataBase = metanodes.find(n => n.getAttribute('name') === 'Data');
if (!dataBase) {
this.logger.error('Could not find the base Data node!');
return;
}
dataBaseId = dataBase.getId();
dataTypes = metanodes.filter(n => client.isTypeOf(n.getId(), dataBaseId))
.filter(n => !n.getRegistry('isAbstract'))
.map(node => node.getAttribute('name'));
//this.logger.info(`Found ${dataTypes.length} data types`);
// Add the target type to the pluginMetadata... hacky :/
var metadata = WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN],
config = metadata.configStructure
.find(opt => opt.name === DATA_TYPE_CONFIG.name);
if (!config) {
config = DATA_TYPE_CONFIG;
WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN].configStructure.push(config);
}
config.valueItems = dataTypes;
config.value = dataTypes[0];
WebGMEGlobal.InterpreterManager.configureAndRun(metadata, (result) => {
var msg = 'Artifact upload complete!';
if (!result) {
return;
}
if (!result.success) {
msg = `Artifact upload failed: ${result.error}`;
}
Materialize.toast(msg, 2000);
});
};
DeepForge.last = {};
DeepForge.create = {};
instances.forEach(type => {
DeepForge.create[type] = function() {
@@ -193,10 +279,16 @@ define([
};
});
DeepForge.create.Layer = createCustomLayer;
DeepForge.create.Artifact = uploadArtifact;
//////////////////// DeepForge prev locations ////////////////////
// Update DeepForge on project changed
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_PROJECT_NAME, updateDeepForgeNamespace, null);
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_PROJECT_NAME,
updateDeepForgeNamespace, null);
// define DeepForge globally
window.DeepForge = DeepForge;
return DeepForge;
});
+1
Ver Arquivo
@@ -2687,6 +2687,7 @@ function LuaContext(){
}
exports.stdlib(_G, helpers)();
}
this.__helpers = helpers;
}
LuaContext.prototype = {}
+4
Ver Arquivo
@@ -18,3 +18,7 @@
.deepforge-logo .item-label {
font-family: 'Audiowide', cursive;
}
.create-node text {
font-style: italic;
}
-19
Ver Arquivo
@@ -1,19 +0,0 @@
.new-node-decorator rect {
fill: #78909C;
/*fill: #90caf9;*/
}
.new-node-decorator circle {
fill: #81c784;
/*fill: #90caf9;*/
}
.new-node-decorator line {
stroke: white;
stroke-width: 4px;
}
.new-node-decorator .dark line {
stroke: black;
stroke-width: 2.5px;
}
-84
Ver Arquivo
@@ -1,84 +0,0 @@
/* globals define */
// This contains decorators for actions such as 'New Operation' so
// the given action can be used as a node in NodePrompter, etc
define([
'css!./AddDecorator.css'
], function(
) {
var NewDecorator = function (opts) {
this.$el = opts.parentEl.append('g')
.attr('class', 'centering-offset');
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.radius = opts.radius || 20;
this.height = this.radius*2;
this.width = opts.width || 90;
this.size = this.radius * 1.00;
if (opts.circle) {
this.render = this.renderCircle;
} else {
this.render = this.renderRect;
}
};
NewDecorator.prototype.renderRect = function() {
this.$body.remove();
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.$body.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', this.width)
.attr('height', this.height);
this.renderPlus()
.attr('class', 'dark')
.attr('transform', `translate(${this.width/2-this.size}, 0)`);
};
NewDecorator.prototype.renderCircle = function() {
this.$body.remove();
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.$body.append('circle')
.attr('cx', this.radius)
.attr('cy', this.radius)
.attr('r', this.radius);
this.renderPlus();
this.$el.attr('transform', `translate(${this.width/2-this.size}, ${this.height/2-this.size})`);
};
NewDecorator.prototype.renderPlus = function() {
// Create a large '+' symbol in a rectangle
var start = this.radius-this.size/2,
end = start + this.size,
middle = (start+end)/2,
plus = this.$body.append('g');
plus.append('line')
.attr('x1', start)
.attr('x2', end)
.attr('y1', middle)
.attr('y2', middle)
.attr('stroke', 'black');
plus.append('line')
.attr('x1', middle)
.attr('x2', middle)
.attr('y1', start)
.attr('y2', end)
.attr('stroke', 'black');
return plus;
};
return NewDecorator;
});
+65
Ver Arquivo
@@ -0,0 +1,65 @@
/*globals define, WebGMEGlobal*/
define([
'widgets/EasyDAG/Buttons',
'widgets/EasyDAG/Icons'
], function(
EasyDAGButtons,
Icons
) {
// Create a GoToBase button
var client = WebGMEGlobal.Client;
var GoToBase = function(params) {
// Check if it should be disabled
var baseId = this._getBaseId(params.item),
base = baseId && client.getNode(baseId);
if (!params.disabled) {
params.disabled = base ? base.isLibraryElement() : true;
}
EasyDAGButtons.ButtonBase.call(this, params);
};
GoToBase.SIZE = 10;
GoToBase.BORDER = 1;
GoToBase.prototype.BTN_CLASS = 'go-to-base';
GoToBase.prototype = new EasyDAGButtons.ButtonBase();
GoToBase.prototype._render = function() {
var lineRadius = GoToBase.SIZE - GoToBase.BORDER,
btnColor = '#90caf9';
if (this.disabled) {
btnColor = '#e0e0e0';
}
this.$el
.append('circle')
.attr('r', GoToBase.SIZE)
.attr('fill', btnColor);
// Show the 'code' icon
Icons.addIcon('code', this.$el, {
radius: lineRadius
});
};
GoToBase.prototype._onClick = function(item) {
var node = client.getNode(item.id),
baseId = node.getBaseId();
WebGMEGlobal.State.registerActiveObject(baseId);
};
GoToBase.prototype._getBaseId = function(item) {
var n = client.getNode(item.id);
return n && n.getBaseId();
};
return {
DeleteOne: EasyDAGButtons.DeleteOne,
GoToBase: GoToBase
};
});
+2 -2
Ver Arquivo
@@ -7,9 +7,9 @@ define([
var OperationControl = function() {
};
OperationControl.prototype.hasMetaName = function(id, name) {
OperationControl.prototype.hasMetaName = function(id, name, inclusive) {
var node = this._client.getNode(id),
bId = node.getBaseId(),
bId = inclusive ? id : node.getBaseId(),
baseName;
while (bId) {
+5
Ver Arquivo
@@ -3,11 +3,13 @@
define([
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/OperationControl',
'deepforge/Constants',
'widgets/EasyDAG/AddNodeDialog',
'underscore'
], function(
EasyDAGControl,
OperationControl,
CONSTANTS,
AddNodeDialog,
_
) {
@@ -72,6 +74,8 @@ define([
var desc = EasyDAGControl.prototype._getObjectDescriptor.call(this, id),
node = this._client.getNode(id);
desc.inputs = [];
desc.outputs = [];
if (this.hasMetaName(id, 'Operation')) {
// Only decorate operations in the currently active node
if (this._currentNodeId !== desc.parentId) {
@@ -95,6 +99,7 @@ define([
// Remove the 'code' attribute
if (desc.attributes.code) {
delete desc.attributes[CONSTANTS.LINE_OFFSET];
delete desc.attributes.code;
}
+60
Ver Arquivo
@@ -0,0 +1,60 @@
/*globals define*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'underscore'
], function(
PanelBaseWithHeader,
IActivePanel,
_
) {
var RenameablePanel = function() {
PanelBaseWithHeader.apply(this, arguments);
};
_.extend(
RenameablePanel.prototype,
PanelBaseWithHeader.prototype,
IActivePanel.prototype
);
RenameablePanel.OPTIONS = PanelBaseWithHeader.OPTIONS;
RenameablePanel.prototype.initializeRenameable = function () {
this.$panelHeaderTitle.on('dblclick', this.editTitle.bind(this));
};
RenameablePanel.prototype.currentNodeId = function () {
return this.control._currentNodeId;
};
RenameablePanel.prototype.currentBaseName = function () {
var currentId = this.currentNodeId(),
node = this._client.getNode(currentId),
baseId = node.getBaseId(),
base = this._client.getNode(baseId);
return base.getAttribute('name');
};
RenameablePanel.prototype.editTitle = function () {
this.$panelHeaderTitle.editInPlace({
css: {
'z-index': 1000
},
onChange: (oldValue, newValue) => {
var nodeId = this.currentNodeId(),
type = this.currentBaseName(),
msg = `Renamed ${type}: ${oldValue} -> ${newValue}`;
if (!/^\s*$/.test(newValue)) {
this._client.startTransaction(msg);
this._client.setAttributes(nodeId, 'name', newValue);
this._client.completeTransaction();
}
}
});
};
return RenameablePanel;
});
@@ -53,7 +53,17 @@ define([
ArtifactOpDecorator.prototype.savePointer = function(name, to) {
// When the 'artifact' pointer is changed, we should change the base
// of the data output node to the target type
if (name === this.castOpts.ptr && (typeof to === 'string')) {
if (typeof to !== 'string') {
var outputId = this._node.outputs[0] && this._node.outputs[0].id;
// Clear the data handle of the output
this.client.startTransaction(`Removing output of ${this.name}`);
this.client.delPointer(this._node.id, name);
if (outputId) {
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.makePointer(this._node.id, name, to);
@@ -0,0 +1,16 @@
/* globals define, _*/
define([
'decorators/EllipseDecorator/EasyDAG/AttributeField'
], function(
AttributeFieldBase
) {
// Attribute field in which the label is clickable and the attribute meta is editable
var AttributeField = function() {
AttributeFieldBase.apply(this, arguments);
this.$label.on('click', () => this.onLabelClick());
};
_.extend(AttributeField.prototype, AttributeFieldBase.prototype);
return AttributeField;
});
@@ -0,0 +1,26 @@
/* globals define */
define([
], function(
) {
var CreateAttrField = function(logger, pEl, y) {
this.$el = pEl.append('text')
.attr('y', y)
.attr('class', 'create-attr-field')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.attr('font-weight', 'bold')
.attr('font-style', 'italic')
.text('New Attribute')
.on('click', () => this.onClick());
};
CreateAttrField.prototype.render =
CreateAttrField.prototype.destroy = function() {};
CreateAttrField.prototype.width = function() {
return this.$el[0][0].getBoundingClientRect().width;
};
return CreateAttrField;
});
@@ -1,15 +1,17 @@
/*globals define, $,_*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'./AttributeField',
'./CreateAttributeField',
'decorators/MetaDecorator/DiagramDesigner/AttributeDetailsDialog',
'css!./OpIntDecorator.EasyDAGWidget.css'
], function (
DecoratorBase
DecoratorBase,
AttributeField,
CreateAttributeField,
AttributeDetailsDialog
) {
'use strict';
@@ -17,13 +19,7 @@ define([
var OpIntDecorator,
DECORATOR_ID = 'OpIntDecorator';
// OpInt nodes need to be able to...
// - show their ports
// - highlight ports
// - unhighlight ports
// - report the location of specific ports
OpIntDecorator = function (options) {
this.color = this.color || '#78909c';
DecoratorBase.call(this, options);
};
@@ -31,9 +27,9 @@ define([
OpIntDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
OpIntDecorator.prototype.initialize = function() {
if (this._node.baseName === 'Operation') {
if (this.isOperation()) {
this.color = '#2196f3';
} else {
} else if (this._node.baseName) {
// On hover, show the type
this.enableTooltip(this._node.baseName, 'dark');
}
@@ -41,6 +37,109 @@ define([
this.$name.on('dblclick', this.editName.bind(this));
};
OpIntDecorator.prototype.AttributeField = AttributeField;
OpIntDecorator.prototype.isOperation = function() {
return this._node.baseName === 'Operation';
};
OpIntDecorator.prototype.createAttributeFields = function(y, width) {
var field,
initialY = y;
if (!this.isOperation()) {
return y;
}
y = DecoratorBase.prototype.createAttributeFields.call(this, y, width);
// Change attribute field so clicking allows user to edit/delete the field
this.fields.forEach(field =>
field.onLabelClick = this.editAttributeMeta.bind(this, field.name));
// Add the 'create new attribute' field
y += this.ROW_HEIGHT + (y === initialY ? 0 : 10);
field = new CreateAttributeField(this.logger, this.$attributes, y, width);
field.onClick = this.newAttribute.bind(this);
this.fields.push(field);
return y;
};
OpIntDecorator.prototype.newAttribute = function() {
var defSchema = {
type: 'string'
};
this.editAttributeMeta(null, defSchema);
};
OpIntDecorator.prototype.expand = function() {
DecoratorBase.prototype.expand.call(this, this.isOperation());
};
OpIntDecorator.prototype.editAttributeMeta = function(name, defSchema) {
var dialog = new AttributeDetailsDialog(),
node = this.client.getNode(this._node.id),
attrNames = node.getValidAttributeNames(),
attrInfo = this._node.attributes[name] || defSchema,
schema,
i;
// Open the dialog for editing the attribute
schema = _.extend({defaultValue: attrInfo.value}, attrInfo);
// Remove the current name
i = attrNames.indexOf(name);
if (i !== -1) {
attrNames.splice(i, 1);
}
dialog.show(schema, attrNames,
desc => this.setAttributeMeta(name, desc),
() => this.deleteAttribute(name));
};
OpIntDecorator.prototype.deleteAttribute = function(name) {
var opName = this._node.attributes.name.value,
msg = `Deleting "${name}" attribute from "${opName}" operation`;
this.client.startTransaction(msg);
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
this.client.completeTransaction();
};
OpIntDecorator.prototype.setAttributeMeta = function(name, desc) {
var schema,
opName = this._node.attributes.name.value,
msg = `Updating "${name}" attribute in "${opName}" operation`;
// Create the schema from the desc
schema = {
type: desc.type,
min: desc.min,
max: desc.max,
regexp: desc.regexp
};
if (desc.isEnum) {
schema.enum = desc.enumValues;
}
// Update the operation's attribute
this.client.startTransaction(msg);
if (name !== desc.name) { // Renaming attribute
if (name) {
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
}
name = desc.name;
}
this.client.setAttributeSchema(this._node.id, name, schema);
this.client.setAttributes(this._node.id, name, desc.defaultValue);
this.client.completeTransaction();
};
OpIntDecorator.prototype.editName = function() {
var html = this.$name[0][0],
position = html.getBoundingClientRect(),
@@ -90,8 +189,5 @@ define([
return this._node.name;
};
// clicking on the name should allow the user to edit it in place
// TODO
return OpIntDecorator;
});
@@ -1,10 +1,6 @@
/*globals define, _, Opentip*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'css!./OperationDecorator.EasyDAGWidget.css'
@@ -47,29 +43,22 @@ define([
};
OperationDecorator.prototype.condense = function() {
var path,
width,
rx;
width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
rx = width/2;
path = [
`M${-rx},0`,
`l ${width} 0`,
`l 0 ${this.dense.height}`,
`l -${width} 0`,
`l 0 -${this.dense.height}`
].join(' ');
var width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
this.$body
.attr('d', path);
.transition()
.attr('x', -width/2)
.attr('y', 0)
.attr('width', width)
.attr('height', this.dense.height);
// Clear the attributes
this.$attributes.remove();
this.clearFields();
this.$attributes = this.$el.append('g')
.attr('fill', '#222222');
.attr('fill', 'none');
this.createAttributeFields(0, width);
this.createPointerFields(0, width, true);
this.height = this.dense.height;
this.width = width;
+1 -1
Ver Arquivo
@@ -118,7 +118,7 @@ define([
this.core.addMember(this.activeNode, 'executions', tgtNode);
return this.project.createTag(
execName.replace(/ /g, '_'),
execName.replace(/[ -]/g, '_'),
this.currentHash
);
})
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
{
"id": "CreateExecution",
"name": "CreateExecution",
"name": "Create Execution",
"version": "0.1.0",
"description": "",
"icon": {
+1 -2
Ver Arquivo
@@ -86,8 +86,7 @@ define([
layers;
try {
layers = JSON.parse(text)
.filter(layer => layer.type !== 'Criterion');
layers = JSON.parse(text);
} catch (e) {
return callback('JSON parse error: ' + e, this.result);
}
+927
Ver Arquivo
@@ -0,0 +1,927 @@
/*globals define*/
/*jshint node:true, browser:true*/
define([
'text!./metadata.json',
'executor/ExecutorClient',
'plugin/PluginBase',
'deepforge/plugin/LocalExecutor',
'deepforge/plugin/PtrCodeGen',
'deepforge/Constants',
'./templates/index',
'q',
'underscore'
], function (
pluginMetadata,
ExecutorClient,
PluginBase,
LocalExecutor, // DeepForge operation primitives
PtrCodeGen,
CONSTANTS,
Templates,
Q,
_
) {
'use strict';
pluginMetadata = JSON.parse(pluginMetadata);
var OUTPUT_INTERVAL = 1500,
STDOUT_FILE = 'job_stdout.txt';
/**
* Initializes a new instance of ExecuteJob.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin ExecuteJob.
* @constructor
*/
var ExecuteJob = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
this._metadata = {};
// Metadata updating
this._markForDeletion = {}; // id -> node
this._oldMetadataByName = {}; // name -> id
this.lastAppliedCmd = {};
};
/**
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
* This is also available at the instance at this.pluginMetadata.
* @type {object}
*/
ExecuteJob.metadata = pluginMetadata;
ExecuteJob.UPDATE_INTERVAL = 1500;
// Prototypical inheritance from PluginBase.
ExecuteJob.prototype = Object.create(PluginBase.prototype);
ExecuteJob.prototype.constructor = ExecuteJob;
/**
* Main function for the plugin to execute. This will perform the execution.
* Notes:
* - Always log with the provided logger.[error,warning,info,debug].
* - Do NOT put any user interaction logic UI, etc. inside this method.
* - callback always has to be called even if error happened.
*
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
ExecuteJob.prototype.main = function (callback) {
// Check the activeNode to make sure it is a valid node
var type = this.core.getMetaType(this.activeNode),
typeName = type && this.core.getAttribute(type, 'name');
if (typeName !== 'Job') {
return callback(`Cannot execute ${typeName} (expected Job)`, this.result);
}
this._callback = callback;
this.prepare()
.then(() => this.executeJob(this.activeNode));
};
ExecuteJob.prototype.getConnections = function (nodes) {
var conns = [];
for (var i = nodes.length; i--;) {
if (this.core.getPointerPath(nodes[i], 'src') &&
this.core.getPointerPath(nodes[i], 'dst')) {
conns.push(nodes[i]);
}
}
return conns;
};
ExecuteJob.prototype.prepare = function () {
var dstPortId,
srcPortId,
conns,
executionNode = this.core.getParent(this.activeNode);
this.pipelineName = this.core.getAttribute(executionNode, 'name');
return this.core.loadSubTree(executionNode)
.then(nodes => {
this.inputPortsFor = {};
this.outputLineCount = {};
conns = this.getConnections(nodes);
// Create inputPortsFor for the given input ports
for (var i = conns.length; i--;) {
dstPortId = this.core.getPointerPath(conns[i], 'dst');
srcPortId = this.core.getPointerPath(conns[i], 'src');
if (!this.inputPortsFor[dstPortId]) {
this.inputPortsFor[dstPortId] = [srcPortId];
} else {
this.inputPortsFor[dstPortId].push(srcPortId);
}
}
})
.then(() => this.recordOldMetadata(this.activeNode));
};
ExecuteJob.prototype.recordOldMetadata = function (job) {
var nodeId = this.core.getPath(job),
name,
id,
idsToDelete = [],
child;
this.lastAppliedCmd[nodeId] = 0;
this._oldMetadataByName[nodeId] = {};
this._markForDeletion[nodeId] = {};
return this.core.loadChildren(job)
.then(jobChildren => {
// Remove any metadata nodes
for (var i = jobChildren.length; i--;) {
child = jobChildren[i];
if (this.isMetaTypeOf(child, this.META.Metadata)) {
id = this.core.getPath(child);
name = this.core.getAttribute(child, 'name');
this._markForDeletion[nodeId][id] = child;
this._oldMetadataByName[nodeId][name] = id;
// children of metadata nodes get deleted
idsToDelete = idsToDelete
.concat(this.core.getChildrenPaths(child));
}
}
// make the deletion ids relative to the job node
idsToDelete = idsToDelete.map(id => id.replace(nodeId, ''));
return Q.all(idsToDelete.map(id => this.core.loadByPath(job, id)));
})
.then(nodes => nodes.forEach(node => this.core.deleteNode(node)));
};
ExecuteJob.prototype.clearOldMetadata = function (job) {
var nodeId = this.core.getPath(job),
nodeIds = Object.keys(this._markForDeletion[nodeId]);
for (var i = nodeIds.length; i--;) {
this.core.deleteNode(this._markForDeletion[nodeId][nodeIds[i]]);
}
delete this.lastAppliedCmd[nodeId];
delete this._markForDeletion[nodeId];
};
ExecuteJob.prototype.onOperationFail =
ExecuteJob.prototype.onOperationComplete =
ExecuteJob.prototype.onComplete = function (opNode, err) {
var job = this.core.getParent(opNode),
exec = this.core.getParent(job),
name = this.core.getAttribute(job, 'name'),
jobId = this.core.getPath(job),
status = err ? 'fail' : 'success',
msg = err ? `${name} execution failed: ${err}` :
`${name} executed successfully!`,
promise = Q();
this.core.setAttribute(job, 'status', status);
this.logger.info(`Setting ${name} (${jobId}) status to ${status}`);
this.clearOldMetadata(job);
if (err) {
this.core.setAttribute(exec, 'status', 'failed');
} else {
// Check if all the other jobs are successful. If so, set the
// execution status to 'success'
promise = this.core.loadChildren(exec)
.then(nodes => {
var execSuccess = true,
type,
typeName;
for (var i = nodes.length; i--;) {
type = this.core.getMetaType(nodes[i]);
typeName = this.core.getAttribute(type, 'name');
if (typeName === 'Job' &&
this.core.getAttribute(nodes[i], 'status') !== 'success') {
execSuccess = false;
}
}
if (execSuccess) {
this.core.setAttribute(exec, 'status', 'success');
}
});
}
promise
.then(() => this.save(msg))
.then(() => {
this.result.setSuccess(!err);
this._callback(err, this.result);
})
.catch(err => {
// Result success is false at invocation.
this._callback(err, this.result);
});
};
ExecuteJob.prototype.getOperation = function (job) {
return this.core.loadChildren(job).then(children =>
children.find(child => this.isMetaTypeOf(child, this.META.Operation)));
};
ExecuteJob.prototype.executeJob = function (job) {
return this.getOperation(job).then(node => {
var jobId = this.core.getPath(job),
name = this.core.getAttribute(node, 'name'),
localTypeId = this.getLocalOperationType(node),
artifact,
artifactName,
files,
data = {},
inputs;
// Execute any special operation types here - not on an executor
this.logger.debug(`Executing operation "${name}"`);
if (localTypeId !== null) {
return this.executeLocalOperation(localTypeId, node);
} else {
// Generate all execution files
return this.createOperationFiles(node).then(results => {
this.logger.info('Created operation files!');
files = results;
artifactName = `${name}_${jobId.replace(/\//g, '_')}-execution-files`;
artifact = this.blobClient.createArtifact(artifactName);
// Add the input assets
// - get the metadata (name)
// - add the given inputs
inputs = Object.keys(files.inputAssets);
return Q.all(
inputs.map(input => { // Get the metadata for each input
var hash = files.inputAssets[input];
// data asset for "input"
return this.blobClient.getMetadata(hash);
})
);
})
.then(mds => {
// get (input, filename) tuples
mds.forEach((metadata, i) => {
// add the hashes for each input
var input = inputs[i],
name = metadata.name,
hash = files.inputAssets[input];
data['inputs/' + input + '/' + name] = hash;
});
delete files.inputAssets;
// Add pointer assets
Object.keys(files.ptrAssets)
.forEach(path => data[path] = files.ptrAssets[path]);
delete files.ptrAssets;
// Add the executor config
return this.getOutputs(node);
})
.then(outputArgs => {
var config,
outputs,
file;
outputs = outputArgs.map(pair => pair[0])
.map(name => {
return {
name: name,
resultPatterns: [`outputs/${name}`]
};
});
outputs.push(
{
name: 'stdout',
resultPatterns: [STDOUT_FILE]
},
{
name: name + '-all-files',
resultPatterns: []
}
);
config = {
cmd: 'bash',
args: ['run.sh'],
outputInterval: OUTPUT_INTERVAL,
resultArtifacts: outputs
};
files['executor_config.json'] = JSON.stringify(config, null, 4);
files['run.sh'] = Templates.BASH;
// Save the artifact
// Remove empty hashes
for (file in data) {
if (!data[file]) {
this.logger.warn(`Empty data hash has been found for file "${file}". Removing it...`);
delete data[file];
}
}
return artifact.addObjectHashes(data);
})
.then(() => {
this.logger.info(`Added ptr/input data hashes for "${artifactName}"`);
return artifact.addFiles(files);
})
.then(() => {
this.logger.info(`Added execution files for "${artifactName}"`);
return artifact.save();
})
.then(hash => {
this.logger.info(`Saved execution files "${artifactName}"`);
this.result.addArtifact(hash); // Probably only need this for debugging...
this.executeDistOperation(job, node, hash);
})
.fail(e => {
this.onOperationFail(node, `Distributed operation "${name}" failed ${e}`);
});
}
});
};
ExecuteJob.prototype.executeDistOperation = function (job, opNode, hash) {
var name = this.core.getAttribute(opNode, 'name'),
jobId = this.core.getPath(job),
isHttps = typeof window === 'undefined' ? false :
window.location.protocol !== 'http:',
executor = new ExecutorClient({
logger: this.logger,
serverPort: this.gmeConfig.server.port,
httpsecure: isHttps
});
this.logger.info(`Executing operation "${name}"`);
this.outputLineCount[jobId] = 0;
// Set the job status to 'running'
this.core.setAttribute(job, 'status', 'queued');
this.core.setAttribute(job, 'stdout', '');
this.logger.info(`Setting ${jobId} status to "queued" (${this.currentHash})`);
this.logger.debug(`Making a commit from ${this.currentHash}`);
this.save(`Queued "${name}" operation in ${this.pipelineName}`)
.then(() => executor.createJob({hash}))
.then(() => this.watchOperation(executor, hash, opNode, job))
.catch(err => this.logger.error(`Could not execute "${name}": ${err}`));
};
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');
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.core.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,
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);
return isClass[baseId];
});
// Get the code definitions for each
code = classNodes.map(node =>
`require './${this.core.getAttribute(node, 'name')}.lua'`
).join('\n');
// Create the class files
classNodes.forEach(node => {
var name = this.core.getAttribute(node, 'name');
files[`classes/${name}.lua`] = this.core.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.core.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.core.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.core.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.core.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.core.getAttribute(base, 'name');
deserFn = `return ${className}.deserialize(path)`;
}
return {
name: name,
code: deserFn
};
});
}));
})
.then(_tplContents => {
tplContents = _tplContents;
var hashes = inputs
// storing the hash for now...
.map(pair =>
files.inputAssets[pair[0]] = this.core.getAttribute(pair[2], 'data')
);
return Q.all(hashes.map(h => this.blobClient.getMetadata(h)));
})
.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.core.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.core.getAttribute(node, 'name'),
code = this.core.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.core.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.core.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'],
numRegex = /^\d+\.?\d*((e|e-)\d+)?$/,
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.core.getAttribute(node, name);
if (!numRegex.test(value)) {
value = `"${value}"`;
}
return [name, value];
})
.map(pair => pair.join(' = '))
.join(',\n\t') + '\n}';
files['attributes.lua'] = `-- attributes of ${this.core.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.core.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.core.getAttribute(node, 'name')}: ${JSON.stringify(e)}`);
return cb(e);
});
};
ExecuteJob.prototype.watchOperation = function (executor, hash, op, job) {
var jobId = this.core.getPath(job),
opId = this.core.getPath(op),
info,
name;
return executor.getInfo(hash)
.then(_info => { // Update the job's stdout
var actualLine, // on executing job
currentLine = this.outputLineCount[jobId];
info = _info;
actualLine = info.outputNumber;
if (actualLine !== null && actualLine >= currentLine) {
this.outputLineCount[jobId] = actualLine + 1;
return executor.getOutput(hash, currentLine, actualLine+1)
.then(outputLines => {
var stdout = this.core.getAttribute(job, 'stdout'),
output = outputLines.map(o => o.output).join(''),
jobName = this.core.getAttribute(job, 'name');
// parse deepforge commands
output = this.parseForMetadataCmds(job, output);
if (output) {
stdout += output;
this.core.setAttribute(job, 'stdout', stdout);
return this.save(`Received stdout for ${jobName}`);
}
});
}
})
.then(() => {
if (info.status === 'CREATED' || info.status === 'RUNNING') {
if (info.status === 'RUNNING' &&
this.core.getAttribute(job, 'status') !== 'running') {
name = this.core.getAttribute(job, 'name');
this.core.setAttribute(job, 'status', 'running');
this.save(`Started "${name}" operation in ${this.pipelineName}`);
}
setTimeout(
this.watchOperation.bind(this, executor, hash, op, job),
ExecuteJob.UPDATE_INTERVAL
);
return;
}
name = this.core.getAttribute(job, 'name');
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
return this.blobClient.getArtifact(info.resultHashes.stdout)
.then(artifact => {
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
return this.blobClient.getObjectAsString(stdoutHash);
})
.then(stdout => {
// Parse the remaining code
stdout = this.parseForMetadataCmds(job, stdout, true);
this.core.setAttribute(job, 'stdout', stdout);
if (info.status !== 'SUCCESS') {
// Download all files
this.result.addArtifact(info.resultHashes[name + '-all-files']);
// Set the job to failed! Store the error
this.onOperationFail(op, `Operation "${opId}" failed! ${JSON.stringify(info)}`);
} else {
this.onDistOperationComplete(op, info);
}
});
})
.catch(err => this.logger.error(`Could not get op info for ${opId}: ${err}`));
};
ExecuteJob.prototype.onDistOperationComplete = function (node, result) {
var nodeId = this.core.getPath(node),
outputMap = {},
outputs;
// Match the output names to the actual nodes
// Create an array of [name, node]
// For now, just match by type. Later we may use ports for input/outputs
// Store the results in the outgoing ports
this.getOutputs(node)
.then(outputPorts => {
outputs = outputPorts.map(tuple => [tuple[0], tuple[2]]);
outputs.forEach(output => outputMap[output[0]] = output[1]);
// this should not be in directories -> flatten the data!
return Q.all(outputs.map(tuple => // [ name, node ]
this.blobClient.getArtifact(result.resultHashes[tuple[0]])
));
})
.then(artifacts => {
this.logger.info(`preparing outputs -> retrieved ${artifacts.length} objects`);
// Create new metadata for each
artifacts.forEach((artifact, i) => {
var name = outputs[i][0],
outputData = artifact.descriptor.content[`outputs/${name}`],
hash = outputData && outputData.content;
if (hash) {
this.core.setAttribute(outputMap[name], 'data', hash);
this.logger.info(`Setting ${nodeId} data to ${hash}`);
}
});
return this.onOperationComplete(node);
})
.fail(e => this.onOperationFail(node, `Operation ${nodeId} failed: ${e}`));
};
ExecuteJob.prototype.getOutputs = function (node) {
return this.getOperationData(node, this.META.Outputs);
};
ExecuteJob.prototype.getInputs = function (node) {
return this.getOperationData(node, this.META.Inputs);
};
ExecuteJob.prototype.getOperationData = function (node, metaType) {
// Load the children and the output's children
return this.core.loadChildren(node)
.then(containers => {
var outputs = containers.find(c => this.core.isTypeOf(c, metaType));
return outputs ? this.core.loadChildren(outputs) : [];
})
.then(outputs => {
var bases = outputs.map(node => this.core.getMetaType(node));
// return [[arg1, Type1, node1], [arg2, Type2, node2]]
return outputs.map((node, i) => [
this.core.getAttribute(node, 'name'),
this.core.getAttribute(bases[i], 'name'),
node
]);
});
};
//////////////////////////// Special Operations ////////////////////////////
ExecuteJob.prototype.executeLocalOperation = function (type, node) {
// Retrieve the given LOCAL_OP type
if (!this[type]) {
this.logger.error(`No local operation handler for ${type}`);
}
this.logger.info(`Running local operation ${type}`);
return this[type](node);
};
_.extend(
ExecuteJob.prototype,
PtrCodeGen.prototype,
LocalExecutor.prototype
);
//////////////////////////// Metadata ////////////////////////////
ExecuteJob.prototype.parseForMetadataCmds = function (job, text, skip) {
var jobId = this.core.getPath(job),
lines = text.split('\n'),
args,
result = [],
cmdCnt = 0,
cmd;
for (var i = 0; i < lines.length; i++) {
// Check for a deepforge command
if (lines[i].indexOf(CONSTANTS.START_CMD) === 0) {
cmdCnt++;
args = lines[i].split(/\s+/);
args.shift();
cmd = args[0];
args[0] = job;
if (this[cmd] && (!skip || cmdCnt >= this.lastAppliedCmd[jobId])) {
this[cmd].apply(this, args);
this.lastAppliedCmd[jobId]++;
} else if (!this[cmd]) {
this.logger.error(`Invoked unimplemented metadata method "${cmd}"`);
}
} else {
result.push(lines[i]);
}
}
return result.join('\n');
};
ExecuteJob.prototype[CONSTANTS.GRAPH_CREATE] = function (job, id) {
var graph,
name = Array.prototype.slice.call(arguments, 2).join(' '),
jobId = this.core.getPath(job),
oldMetadata = this._oldMetadataByName[jobId],
oldId;
id = jobId + '/' + id;
this.logger.info(`Creating graph ${id} named ${name}`);
// Check if the graph already exists
if (oldMetadata && oldMetadata[name]) {
oldId = oldMetadata[name];
graph = this._markForDeletion[jobId][oldId];
// Reset points
this.core.setAttribute(graph, 'points', '');
delete this._markForDeletion[jobId][oldId];
} else { // create new graph
graph = this.core.createNode({
base: this.META.Graph,
parent: job
});
if (name) {
this.core.setAttribute(graph, 'name', name);
}
}
this._metadata[id] = graph;
};
ExecuteJob.prototype[CONSTANTS.GRAPH_PLOT] = function (job, id, x, y) {
var jobId = this.core.getPath(job),
graph,
points;
id = jobId + '/' + id;
this.logger.info(`Adding point ${x}, ${y} to ${id}`);
graph = this._metadata[id];
if (!graph) {
this.logger.warn(`Can't add point to non-existent graph: ${id}`);
return;
}
points = this.core.getAttribute(graph, 'points');
points += `${x},${y};`;
this.core.setAttribute(graph, '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.core.createNode({
base: this.META.Line,
parent: graph
});
this.core.setAttribute(line, 'name', name);
this._metadata[jobId + '/' + id] = line;
};
return ExecuteJob;
});
+14
Ver Arquivo
@@ -0,0 +1,14 @@
{
"id": "ExecuteJob",
"name": "ExecuteJob",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"writeAccessRequired": false,
"configStructure": []
}
@@ -0,0 +1,46 @@
-- Instantiate the deepforge object
deepforge = {}
function deepforge.id()
if __deepforge_id == nil then
__deepforge_id = 0
end
__deepforge_id = __deepforge_id + 1
return __deepforge_id
end
function deepforge._cmd(...)
local cmd = '<%= START_CMD %>'
local arg = {...}
local n = #arg
for i=1,n do
cmd = cmd .. ' ' .. tostring(arg[i])
end
print(cmd)
end
Graph = torch.class('deepforge.Graph')
function Graph:__init(name)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE %>', self.id, name)
end
_Line = torch.class('deepforge._Line')
function _Line:__init(graphId, name, opts)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE_LINE %>', graphId, self.id, name)
end
function _Line:add(x, y)
deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
end
function Graph:line(name, opts)
return deepforge._Line(self.id, name, opts)
end
return deepforge
@@ -1,7 +1,10 @@
-- Instantiate the deepforge object
require './deepforge'
-- run the <%= name %> and serialize the results
print('\n############### Running "<%= name %>" Operation ############### ')
print('\n############### Running "<%= name.replace(/'/g, '\\\'') %>" Operation ############### ')
results = require './main'
print('############### "<%= name %>" Operation Complete! ###############')
print('############### "<%= name.replace(/'/g, '\\\'') %>" Operation Complete! ###############')
-- serialize by type
outputs = require './outputs'
@@ -2,11 +2,13 @@
define([
'text!./entry.ejs',
'text!./main.ejs',
'text!./deepforge.ejs',
'text!./serialize.ejs',
'text!./deserialize.ejs'
], function(
ENTRY,
MAIN,
DEEPFORGE,
SERIALIZE,
DESERIALIZE
) {
@@ -17,6 +19,7 @@ define([
ENTRY,
MAIN,
SERIALIZE,
DEEPFORGE,
DESERIALIZE
};
});
+61 -582
Ver Arquivo
@@ -3,23 +3,19 @@
define([
'plugin/CreateExecution/CreateExecution/CreateExecution',
'deepforge/plugin/PtrCodeGen',
'plugin/ExecuteJob/ExecuteJob/ExecuteJob',
'common/storage/constants',
'common/core/constants',
'q',
'text!./metadata.json',
'./templates/index',
'deepforge/plugin/LocalExecutor',
'executor/ExecutorClient',
'underscore'
], function (
CreateExecution,
PtrCodeGen,
ExecuteJob,
STORAGE_CONSTANTS,
CONSTANTS,
Q,
pluginMetadata,
Templates,
LocalExecutor, // DeepForge operation primitives
ExecutorClient,
_
) {
'use strict';
@@ -32,8 +28,6 @@ define([
* @classdesc This class represents the plugin ExecutePipeline.
* @constructor
*/
var OUTPUT_INTERVAL = 1500,
STDOUT_FILE = 'job_stdout.txt';
var ExecutePipeline = function () {
// Call base class' constructor.
CreateExecution.call(this);
@@ -49,12 +43,13 @@ define([
* @type {object}
*/
ExecutePipeline.metadata = pluginMetadata;
ExecutePipeline.UPDATE_INTERVAL = 1500;
// Prototypical inheritance from CreateExecution.
ExecutePipeline.prototype = Object.create(CreateExecution.prototype);
ExecutePipeline.prototype.constructor = ExecutePipeline;
_.extend(ExecutePipeline.prototype, ExecuteJob.prototype);
ExecutePipeline.prototype.initRun = function () {
// Cache
this.nodes = {};
@@ -80,6 +75,12 @@ define([
// - if so, don't start any more jobs
this.pipelineError = null;
this.runningJobs = 0;
// metadata records
this._metadata = {};
this._markForDeletion = {}; // id -> node
this._oldMetadataByName = {}; // name -> id
this.lastAppliedCmd = {};
};
/**
@@ -103,10 +104,9 @@ define([
startPromise = this.createExecution(this.activeNode)
.then(execNode => {
this.activeNode = execNode;
return this.core.loadSubTree(this.activeNode);
});
} else if (this.core.isTypeOf(this.activeNode, this.META.Execution)) {
startPromise = this.core.loadSubTree(this.activeNode);
startPromise = Q();
} else {
return callback('Current node is not a Pipeline or Execution!', this.result);
}
@@ -115,7 +115,9 @@ define([
this.debug = true; // this.getCurrentConfig().debug;
this._callback = callback;
startPromise.then(subtree => {
startPromise
.then(() => this.core.loadSubTree(this.activeNode))
.then(subtree => {
var children = subtree
.filter(n => this.core.getParent(n) === this.activeNode);
@@ -129,12 +131,36 @@ define([
.fail(e => this.logger.error(e));
};
ExecutePipeline.prototype.updateForkName = function () {
var basename = this.pipelineName + '_fork';
return this.project.getBranches().then(branches => {
var names = Object.keys(branches),
name = basename,
i = 2;
while (names.indexOf(name) !== -1) {
name = basename + '_' + i;
i++;
}
this.forkName = name;
});
};
// 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(() => CreateExecution.prototype.save.call(this, msg));
.then(() => this.updateForkName())
.then(() => CreateExecution.prototype.save.call(this, msg))
.then(result => {
var msg;
if (result.status === STORAGE_CONSTANTS.FORKED) {
msg = `"${this.pipelineName}" execution has forked to "${result.forkName}"`;
this.sendNotification(msg);
}
});
return this._currentSave;
};
@@ -156,7 +182,10 @@ define([
// Set the status for each job to 'pending'
nodes.filter(node => this.core.isTypeOf(node, this.META.Job))
.forEach(node => this.core.setAttribute(node, 'status', 'pending'));
.forEach(node => {
this.recordOldMetadata(node);
this.core.setAttribute(node, 'status', 'pending');
});
// Set the status of the execution to 'running'
this.core.setAttribute(this.activeNode, 'status', 'running');
@@ -186,9 +215,7 @@ define([
this.completedCount = 0;
// Get all connections
conns = nodes.filter(node =>
this.core.getPointerPath(node, 'src') && this.core.getPointerPath(node, 'dst')
);
conns = this.getConnections(nodes);
// Get all operations
nodes
@@ -251,6 +278,17 @@ define([
this.executeReadyOperations();
};
ExecutePipeline.prototype.onOperationFail = function(node, err) {
var job = this.core.getParent(node),
id = this.core.getPath(node),
name = this.core.getAttribute(node, 'name');
this.logger.debug(`Operation ${name} (${id}) failed: ${err}`);
this.core.setAttribute(job, 'status', 'fail');
this.clearOldMetadata(job);
this.onPipelineComplete(err);
};
ExecutePipeline.prototype.onPipelineComplete = function(err) {
var name = this.core.getAttribute(this.activeNode, 'name');
@@ -298,276 +336,16 @@ define([
readyOps.forEach(jobId => {
delete this.incomingCounts[jobId];
});
this.logger.info(`Found ${readyOps.length} ready job(s)`);
readyOps.reduce((prev, jobId) => {
return prev.then(() => this.executeOperation(jobId));
return prev.then(() => this.executeJob(this.nodes[jobId]));
}, Q());
this.runningJobs += readyOps.length;
this.logger.info(`There are now ${this.runningJobs} running jobs`);
this.logger.info(`There ${this.runningJobs === 1 ? 'is' : 'are'} now ${this.runningJobs} running job(s)`);
return readyOps.length;
};
ExecutePipeline.prototype.getOperation = function (jobId) {
var node = this.nodes[jobId],
children = this.core.getChildrenPaths(node).map(id => this.nodes[id]);
// Currently, jobs
return children.find(child => this.isMetaTypeOf(child, this.META.Operation));
};
ExecutePipeline.prototype.executeOperation = function (jobId) {
var node = this.getOperation(jobId),
name = this.core.getAttribute(node, 'name'),
localTypeId = this.getLocalOperationType(node),
artifact,
artifactName,
files,
data = {},
inputs;
// Execute any special operation types here - not on an executor
this.logger.debug(`Executing operation "${name}"`);
if (localTypeId !== null) {
return this.executeLocalOperation(localTypeId, node);
} else {
// Generate all execution files
return this.createOperationFiles(node).then(results => {
this.logger.info('Created operation files!');
files = results;
artifactName = `${name}_${jobId.replace(/\//g, '_')}-execution-files`;
artifact = this.blobClient.createArtifact(artifactName);
// Add the input assets
// - get the metadata (name)
// - add the given inputs
inputs = Object.keys(files.inputAssets);
return Q.all(
inputs.map(input => { // Get the metadata for each input
var hash = files.inputAssets[input];
// data asset for "input"
return this.blobClient.getMetadata(hash);
})
);
})
.then(mds => {
// get (input, filename) tuples
mds.forEach((metadata, i) => {
// add the hashes for each input
var input = inputs[i],
name = metadata.name,
hash = files.inputAssets[input];
data['inputs/' + input + '/' + name] = hash;
});
delete files.inputAssets;
// Add pointer assets
Object.keys(files.ptrAssets)
.forEach(path => data[path] = files.ptrAssets[path]);
delete files.ptrAssets;
// Add the executor config
return this.getOutputs(node);
})
.then(outputArgs => {
var config,
outputs,
file;
outputs = outputArgs.map(pair => pair[0])
.map(name => {
return {
name: name,
resultPatterns: [`outputs/${name}`]
};
});
outputs.push({
name: 'stdout',
resultPatterns: [STDOUT_FILE]
});
if (this.debug) {
outputs.push({
name: name + '-all-files',
resultPatterns: []
});
}
config = {
cmd: 'bash',
args: ['run.sh'],
outputInterval: OUTPUT_INTERVAL,
resultArtifacts: outputs
};
files['executor_config.json'] = JSON.stringify(config, null, 4);
files['run.sh'] = Templates.BASH;
// Save the artifact
// Remove empty hashes
for (file in data) {
if (!data[file]) {
this.logger.warn(`Empty data hash has been found for file "${file}". Removing it...`);
delete data[file];
}
}
return artifact.addObjectHashes(data);
})
.then(() => {
this.logger.info(`Added ptr/input data hashes for "${artifactName}"`);
return artifact.addFiles(files);
})
.then(() => {
this.logger.info(`Added execution files for "${artifactName}"`);
return artifact.save();
})
.then(hash => {
this.logger.info(`Saved execution files "${artifactName}"`);
this.result.addArtifact(hash); // Probably only need this for debugging...
this.executeDistOperation(jobId, node, hash);
})
.fail(e => {
this.core.setAttribute(this.nodes[jobId], 'status', 'fail');
this.logger.info(`Setting ${jobId} status to "fail"`);
this.onPipelineComplete(`Distributed operation "${name}" failed ${e}`);
});
}
};
ExecutePipeline.prototype.executeDistOperation = function (jobId, opNode, hash) {
var name = this.core.getAttribute(opNode, 'name'),
opId = this.core.getPath(opNode),
executor = new ExecutorClient({
logger: this.logger,
serverPort: this.gmeConfig.server.port
});
this.logger.info(`Executing operation "${name}"`);
this.outputLineCount[jobId] = 0;
// Set the job status to 'running'
this.core.setAttribute(this.nodes[jobId], 'status', 'queued');
this.core.setAttribute(this.nodes[jobId], 'stdout', '');
this.logger.info(`Setting ${jobId} status to "queued" (${this.currentHash})`);
this.logger.debug(`Making a commit from ${this.currentHash}`);
this.save(`Queued "${name}" operation in ${this.pipelineName}`)
.then(() => executor.createJob({hash}))
.then(() => this.watchOperation(executor, hash, opId, jobId))
.catch(err => this.logger.error(`Could not execute "${name}": ${err}`));
};
ExecutePipeline.prototype.watchOperation = function (executor, hash, opId, jobId) {
var job = this.nodes[jobId],
info,
name;
return executor.getInfo(hash)
.then(_info => { // Update the job's stdout
var actualLine, // on executing job
currentLine = this.outputLineCount[jobId];
info = _info;
actualLine = info.outputNumber;
if (actualLine !== null && actualLine >= currentLine) {
this.outputLineCount[jobId] = actualLine + 1;
return executor.getOutput(hash, currentLine, actualLine+1)
.then(outputLines => {
var stdout = this.core.getAttribute(job, 'stdout'),
output = outputLines.map(o => o.output).join(''),
jobName = this.core.getAttribute(job, 'name');
// Handle the \b
// TODO
stdout += output;
this.core.setAttribute(job, 'stdout', stdout);
return this.save(`Received stdout for ${jobName}`);
});
}
})
.then(() => {
if (info.status === 'CREATED' || info.status === 'RUNNING') {
if (info.status === 'RUNNING' &&
this.core.getAttribute(this.nodes[jobId], 'status') !== 'running') {
name = this.core.getAttribute(this.nodes[jobId], 'name');
this.core.setAttribute(this.nodes[jobId], 'status', 'running');
this.save(`Started "${name}" operation in ${this.pipelineName}`);
}
setTimeout(
this.watchOperation.bind(this, executor, hash, opId, jobId),
ExecutePipeline.UPDATE_INTERVAL
);
return;
}
name = this.core.getAttribute(job, 'name');
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
return this.blobClient.getArtifact(info.resultHashes.stdout)
.then(artifact => {
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
return this.blobClient.getObjectAsString(stdoutHash);
})
.then(stdout => {
this.core.setAttribute(job, 'stdout', stdout);
if (info.status !== 'SUCCESS') {
// Download all files
this.result.addArtifact(info.resultHashes[name + '-all-files']);
// Set the job to failed! Store the error
this.core.setAttribute(this.nodes[jobId], 'status', 'fail');
this.logger.info(`Setting ${jobId} status to "fail"`);
this.onPipelineComplete(`Operation "${opId}" failed! ${JSON.stringify(info)}`); // Failed
} else {
if (this.debug) {
this.result.addArtifact(info.resultHashes[name + '-all-files']);
}
this.onDistOperationComplete(opId, info);
}
});
})
.catch(err => this.logger.error(`Could not get op info for ${opId}: ${err}`));
};
ExecutePipeline.prototype.onDistOperationComplete = function (nodeId, result) {
var node = this.nodes[nodeId],
outputMap = {},
outputs;
// Match the output names to the actual nodes
// Create an array of [name, node]
// For now, just match by type. Later we may use ports for input/outputs
// Store the results in the outgoing ports
this.getOutputs(node)
.then(outputPorts => {
outputs = outputPorts.map(tuple => [tuple[0], tuple[2]]);
outputs.forEach(output => outputMap[output[0]] = output[1]);
// this should not be in directories -> flatten the data!
return Q.all(outputs.map(tuple => // [ name, node ]
this.blobClient.getArtifact(result.resultHashes[tuple[0]])
));
})
.then(artifacts => {
this.logger.info(`preparing outputs -> retrieved ${artifacts.length} objects`);
// Create new metadata for each
artifacts.forEach((artifact, i) => {
var name = outputs[i][0],
hash = artifact.descriptor.content[`outputs/${name}`].content;
this.core.setAttribute(outputMap[name], 'data', hash);
this.logger.info(`Setting ${nodeId} data to ${hash}`);
});
return this.onOperationComplete(node);
})
.fail(e => this.onPipelineComplete(`Operation ${nodeId} failed: ${e}`));
};
ExecutePipeline.prototype.onOperationComplete = function (opNode) {
var name = this.core.getAttribute(opNode, 'name'),
nextPortIds = this.getOperationOutputIds(opNode),
@@ -577,6 +355,7 @@ define([
hasReadyOps;
// Set the operation to 'success'!
this.clearOldMetadata(jNode);
this.runningJobs--;
this.core.setAttribute(jNode, 'status', 'success');
this.logger.info(`Setting ${jobId} status to "success"`);
@@ -634,305 +413,5 @@ define([
return this.getOperationOutputIds(node).map(id => this.nodes[id]);
};
//////////////////////////// Operation File/Dir Creators ////////////////////////////
ExecutePipeline.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');
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);
});
};
ExecutePipeline.prototype.createClasses = function (node, files) {
var isClass = {},
metaDict = this.core.getAllMetaNodes(this.rootNode),
metanodes,
classNodes,
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
// Get all the custom layers
metanodes.forEach(node => {
if (this.core.getAttribute(node, 'name') === 'Complex') {
isClass[this.core.getPath(node)] = true;
}
});
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base);
return isClass[baseId];
});
// Get the code definitions for each
code = classNodes.map(node =>
`require './${this.core.getAttribute(node, 'name')}.lua'`
).join('\n');
// Create the class files
classNodes.forEach(node => {
var name = this.core.getAttribute(node, 'name');
files[`classes/${name}.lua`] = this.core.getAttribute(node, 'code');
});
// Create the custom layers file
files['classes/init.lua'] = code;
};
ExecutePipeline.prototype.createCustomLayers = function (node, files) {
var isCustomLayer = {},
metaDict = this.core.getAllMetaNodes(this.rootNode),
metanodes,
customLayers,
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
// Get all the custom layers
metanodes.forEach(node => {
if (this.core.getAttribute(node, 'name') === 'CustomLayer') {
isCustomLayer[this.core.getPath(node)] = true;
}
});
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.core.getAttribute(node, 'code')).join('\n');
// Create the custom layers file
files['custom-layers.lua'] = code;
};
ExecutePipeline.prototype.createInputs = function (node, files) {
var tplContents;
this.logger.info('Retrieving inputs and deserialize fns...');
return this.getInputs(node)
.then(inputs => {
// 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 = inputs
.filter(pair => !!this.core.getAttribute(pair[2], 'data')); // remove empty inputs
files.inputAssets = {}; // data assets
tplContents = inputs.map(pair => {
var name = pair[0],
node = pair[2],
deserFn = this.core.getAttribute(node, 'deserialize'),
base,
className;
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// (static) deserialize factory method
base = this.core.getBase(node);
className = this.core.getAttribute(base, 'name');
deserFn = `return ${className}.deserialize(path)`;
}
return {
name: name,
code: deserFn
};
});
var hashes = inputs
// storing the hash for now...
.map(pair =>
files.inputAssets[pair[0]] = this.core.getAttribute(pair[2], 'data')
);
return Q.all(hashes.map(h => this.blobClient.getMetadata(h)));
})
.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;
});
};
ExecutePipeline.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.core.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.core.getAttribute(node, 'name')}: ${JSON.stringify(e)}`);
return cb(e);
});
};
ExecutePipeline.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.core.getAttribute(node, 'serialize');
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// serialize methods
serFn = 'data:serialize(path)';
}
return [tuple[1], serFn];
});
files['outputs/init.lua'] = _.template(Templates.SERIALIZE)({types: outputTypes});
});
};
ExecutePipeline.prototype.getOutputs = function (node) {
return this.getOperationData(node, this.META.Outputs);
};
ExecutePipeline.prototype.getInputs = function (node) {
return this.getOperationData(node, this.META.Inputs);
};
ExecutePipeline.prototype.getOperationData = function (node, metaType) {
// Load the children and the output's children
return this.core.loadChildren(node)
.then(containers => {
var outputs = containers.find(c => this.core.isTypeOf(c, metaType));
return outputs ? this.core.loadChildren(outputs) : [];
})
.then(outputs => {
var bases = outputs.map(node => this.core.getMetaType(node));
// return [[arg1, Type1, node1], [arg2, Type2, node2]]
return outputs.map((node, i) => [
this.core.getAttribute(node, 'name'),
this.core.getAttribute(bases[i], 'name'),
node
]);
});
};
ExecutePipeline.prototype.createEntryFile = function (node, files) {
this.logger.info('Creating entry files...');
return this.getOutputs(node)
.then(outputs => {
var name = this.core.getAttribute(node, 'name'),
content = {};
// sort the outputs by the return values?
if (outputs.length > 1) {
this.logger.error('Multiple outputs not yet supported!');
}
// inputs and outputs
content.name = name;
content.outputs = outputs;
files['init.lua'] = _.template(Templates.ENTRY)(content);
});
};
ExecutePipeline.prototype.createMainFile = function (node, files) {
this.logger.info('Creating main file...');
return this.getInputs(node)
.then(inputs => {
var name = this.core.getAttribute(node, 'name'),
code = this.core.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.core.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);
});
};
ExecutePipeline.prototype.createAttributeFile = function (node, files) {
var skip = ['outputs', 'inputs'],
table;
this.logger.info('Creating attributes file...');
table = '{\n\t' + this.core.getAttributeNames(node)
.filter(attr => skip.indexOf(attr) === -1)
.map(name => [name, JSON.stringify(this.core.getAttribute(node, name))])
.map(pair => pair.join(' = '))
.join(',\n\t') + '\n}';
files['attributes.lua'] = `-- attributes of ${this.core.getAttribute(node, 'name')}\nreturn ${table}`;
};
//////////////////////////// Special Operations ////////////////////////////
ExecutePipeline.prototype.executeLocalOperation = function (type, node) {
// Retrieve the given LOCAL_OP type
if (!this[type]) {
this.logger.error(`No local operation handler for ${type}`);
}
this.logger.info(`Running local operation ${type}`);
return this[type](node);
};
_.extend(
ExecutePipeline.prototype,
LocalExecutor.prototype,
PtrCodeGen.prototype
);
return ExecutePipeline;
});
+3 -3
Ver Arquivo
@@ -1,14 +1,14 @@
{
"id": "ExecutePipeline",
"name": "ExecutePipeline",
"name": "Execute Pipeline",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"class": "glyphicon glyphicon-random",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"disableBrowserSideExecution": true,
"configStructure": [
{
"name": "snapshot",
+2 -2
Ver Arquivo
@@ -1,11 +1,11 @@
{
"id": "GenerateArchitecture",
"name": "Generate Architecture",
"name": "Generate Torch Code",
"version": "0.1.0",
"description": "Generate torch architecture code",
"icon": {
"src": "",
"class": "glyphicon glyphicon-ok-circle"
"class": "glyphicon glyphicon-file"
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
@@ -0,0 +1,69 @@
/*globals define*/
/*jshint node:true, browser:true*/
define([
'text!./metadata.json',
'plugin/PluginBase'
], function (
pluginMetadata,
PluginBase
) {
'use strict';
pluginMetadata = JSON.parse(pluginMetadata);
/**
* Initializes a new instance of GenerateCriterion.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin GenerateCriterion.
* @constructor
*/
var GenerateCriterion = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
};
/**
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
* This is also available at the instance at this.pluginMetadata.
* @type {object}
*/
GenerateCriterion.metadata = pluginMetadata;
// Prototypical inheritance from PluginBase.
GenerateCriterion.prototype = Object.create(PluginBase.prototype);
GenerateCriterion.prototype.constructor = GenerateCriterion;
/**
* Main function for the plugin to execute. This will perform the execution.
* Notes:
* - Always log with the provided logger.[error,warning,info,debug].
* - Do NOT put any user interaction logic UI, etc. inside this method.
* - callback always has to be called even if error happened.
*
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
GenerateCriterion.prototype.main = function (callback) {
// Generate the code for the criterion layer and return a file
var name = this.core.getAttribute(this.activeNode, 'name'),
code = `require 'nn'\nreturn nn.${name}()`,
filename = `${name}.lua`;
// Using the logger.
this.logger.debug(`Generating code for ${name} criterion layer.`);
// Save the file
this.blobClient.putFile(filename, code)
.then(hash => {
this.result.setSuccess(true);
this.result.addArtifact(hash);
callback(null, this.result);
})
.catch(err => callback(err, this.result));
};
return GenerateCriterion;
});
+14
Ver Arquivo
@@ -0,0 +1,14 @@
{
"id": "GenerateCriterion",
"name": "Generate Criterion Code",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"writeAccessRequired": false,
"configStructure": []
}
+33 -21
Ver Arquivo
@@ -78,29 +78,32 @@ define([
}
// Get the base node
dataNode = this.core.createNode({
base: baseType,
parent: this.activeNode
});
this.core.setAttribute(dataNode, 'data', hash);
baseName = this.core.getAttribute(baseType, 'name');
var getName;
if (config.name) {
getName = Q().then(() => config.name);
} else {
getName = this.blobClient.getMetadata(hash)
.then(md => {
name = baseName[0].toLowerCase() + baseName.substring(1);
if (md) {
name = md.name.replace(/\.[^\.]*?$/, '');
}
return name;
this.getArtifactsDir()
.then(targetDir => {
dataNode = this.core.createNode({
base: baseType,
parent: targetDir
});
}
getName.then(name => this.core.setAttribute(dataNode, 'name', name))
this.core.setAttribute(dataNode, 'data', hash);
baseName = this.core.getAttribute(baseType, 'name');
var getName;
if (config.name) {
getName = Q().then(() => config.name);
} else {
getName = this.blobClient.getMetadata(hash)
.then(md => {
name = baseName[0].toLowerCase() + baseName.substring(1);
if (md) {
name = md.name.replace(/\.[^\.]*?$/, '');
}
return name;
});
}
return getName;
})
.then(name => this.core.setAttribute(dataNode, 'name', name))
.then(() => this.save(`Uploaded "${name}" data`))
.then(function () {
self.result.setSuccess(true);
@@ -112,5 +115,14 @@ define([
};
ImportArtifact.prototype.getArtifactsDir = function() {
// Find the artifacts dir
return this.core.loadChildren(this.rootNode)
.then(children => children
.find(child => this.core.getAttribute(child, 'name') === 'MyArtifacts') ||
this.activeNode
);
};
return ImportArtifact;
});
+2 -2
Ver Arquivo
@@ -1,10 +1,10 @@
{
"id": "ImportArtifact",
"name": "ImportArtifact",
"name": "Import Artifact",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"class": "glyphicon glyphicon-cloud-upload",
"src": ""
},
"disableServerSideExecution": false,
+13 -8
Ver Arquivo
@@ -57,12 +57,17 @@ define([
this.blobClient.getMetadata(srcHash)
.then(mdata => { // Create the new model
var name = mdata.name.replace('.lua', '');
this.tgtNode = this.core.createNode({
base: this.META.Architecture,
parent: this.activeNode
});
this.core.setAttribute(this.tgtNode, 'name', name);
// If the current node is an architecture, assume we are just extending it
this.importedName = mdata.name.replace('.lua', '');
if (this.isMetaTypeOf(this.activeNode, this.META.Architecture)) {
this.tgtNode = this.activeNode;
} else { // Create a new architecture
this.tgtNode = this.core.createNode({
base: this.META.Architecture,
parent: this.activeNode
});
this.core.setAttribute(this.tgtNode, 'name', this.importedName);
}
return this.blobClient.getObjectAsString(srcHash);
})
.then(src => { // Retrieved the source code
@@ -81,7 +86,7 @@ define([
return this.save('ImportTorch updated model.');
})
.then(() => { // changes saved successfully
var name = this.core.getAttribute(this.tgtNode, 'name');
var name = this.importedName;
this.result.setSuccess(true);
this.createMessage(this.tgtNode,
`Successfully imported ${name} architecture`);
@@ -96,7 +101,7 @@ define([
ImportTorch.prototype.loadNNMock = function () {
// This needs a refactor...
// createNN(this)
var lib = createNNSearcher(this).bind(this.context);
var lib = createNNSearcher(this, this.context).bind(this.context);
// Create a "searcher" to allow this 'nn' to be in the lib path
this.context._G.get('package').set('searchers', [function(name) {
+24 -2
Ver Arquivo
@@ -11,12 +11,23 @@ define([
) {
'use strict';
var createSearcher = function(plugin) {
var createSearcher = function(plugin, context) {
var core = plugin.core,
META = plugin.META,
logger = plugin.logger.fork('nn'),
parent = plugin.tgtNode,
LayerDict = createLayerDict(core, META);
LayerDict = createLayerDict(core, META),
helpers = context.__helpers,
oldSet = helpers.__set,
isSetting = false;
// Override the helper's '__set' method to detect
// if the code is in the middle of a "set".
helpers.__set = function() {
isSetting = true;
oldSet.apply(this, arguments);
isSetting = false;
};
var connect = function(src, dst) {
var conn = core.createNode({
@@ -145,6 +156,7 @@ define([
var CreateLayer = function(type) {
var res = luajs.newContext()._G,
attrs = [].slice.call(arguments, 1),
ltGet = luajs.types.LuaTable.prototype.get,
node;
if (LAYERS[type]) {
@@ -165,6 +177,16 @@ define([
}
}
}
// Override get
res.get = function noNilGet(value) {
var result = ltGet.call(this, value);
if (!result && !isSetting) {
throw Error(`"${value}" is not supported for ${type}`);
}
return result;
};
return res;
};
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
+26 -38
Ver Arquivo
@@ -31,26 +31,8 @@
},
{
"id": "RootViz",
"title": "RootViz",
"panel": "panels/RootViz/RootVizPanel",
"DEBUG_ONLY": false
},
{
"id": "TilingViz",
"title": "TilingViz",
"panel": "panels/TilingViz/TilingVizPanel",
"DEBUG_ONLY": false
},
{
"id": "OperationCodeEditor",
"title": "OperationCodeEditor",
"panel": "panels/OperationCodeEditor/OperationCodeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "OperationInterfaceEditor",
"title": "OperationInterfaceEditor",
"panel": "panels/OperationInterfaceEditor/OperationInterfaceEditorPanel",
"title": "MainView",
"panel": "panels/MainView/MainViewPanel",
"DEBUG_ONLY": false
},
{
@@ -59,24 +41,6 @@
"panel": "panels/DataTypeEditor/DataTypeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "SerializeEditor",
"title": "SerializeEditor",
"panel": "panels/SerializeEditor/SerializeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "DeserializeEditor",
"title": "DeserializeEditor",
"panel": "panels/DeserializeEditor/DeserializeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "Footer",
"title": "Footer",
"panel": "panels/Footer/FooterPanel",
"DEBUG_ONLY": false
},
{
"id": "LogViewer",
"title": "LogViewer",
@@ -100,5 +64,29 @@
"title": "ClassEditor",
"panel": "panels/ClassEditor/ClassEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "PipelineIndex",
"title": "PipelineIndex",
"panel": "panels/PipelineIndex/PipelineIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "JobEditor",
"title": "JobEditor",
"panel": "panels/JobEditor/JobEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "OutputViewer",
"title": "OutputViewer",
"panel": "panels/OutputViewer/OutputViewerPanel",
"DEBUG_ONLY": false
},
{
"id": "LineGraph",
"title": "LineGraph",
"panel": "panels/LineGraph/LineGraphPanel",
"DEBUG_ONLY": false
}
]
@@ -1,15 +1,14 @@
/*globals define */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 17 2016 11:25:46 GMT-0400 (EDT).
*/
define([
'deepforge/globals',
'panels/EasyDAG/EasyDAGControl',
'js/NodePropertyNames',
'js/Utils/ComponentSettings',
'underscore'
], function (
DeepForge,
EasyDAGControl,
nodePropertyNames,
ComponentSettings,
@@ -43,6 +42,16 @@ define([
return 'ArchEditor';
};
ArchEditorControl.prototype.selectedObjectChanged = function(id) {
EasyDAGControl.prototype.selectedObjectChanged.call(this, id);
DeepForge.last.Architecture = id;
if (typeof id === 'string') {
var name = this._client.getNode(id).getAttribute('name');
this._widget.setTitle(name);
}
};
ArchEditorControl.prototype._getObjectDescriptor = function(id) {
var desc = EasyDAGControl.prototype._getObjectDescriptor.call(this, id);
@@ -84,6 +93,7 @@ define([
return desc;
};
////////////////////////// Layer Selection Logic //////////////////////////
ArchEditorControl.prototype._getValidInitialNodes = function() {
return this._client.getChildrenMeta(this._currentNodeId).items
// For now, anything is possible!
@@ -95,7 +105,67 @@ define([
return !this._client.getNode(nodeId).isAbstract();
})
.map(id => this._getObjectDescriptor(id))
.filter(obj => !obj.isConnection && obj.name !== 'Connection');
.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,
criterionId,
allLayerIds = [],
layers = [],
i;
for (i = metanodes.length; i--;) {
if (metanodes[i].getAttribute('name') === 'Layer') {
layerId = metanodes[i].getId();
break;
}
}
for (i = metanodes.length; i--;) {
if (layerId) {
if (!metanodes[i].isAbstract() &&
this._client.isTypeOf(metanodes[i].getId(), layerId)) {
if (metanodes[i].getAttribute('name') === 'Criterion') {
criterionId = metanodes[i].getId();
} else {
allLayerIds.push(metanodes[i].getId());
}
}
}
}
// Remove all criterion layers and abstract layers
for (i = allLayerIds.length; i--;) {
if (!this._client.isTypeOf(allLayerIds[i], criterionId)) {
layers.push({node: this._getObjectDescriptor(allLayerIds[i])});
}
}
return layers;
};
ArchEditorControl.prototype._isValidTerminalNode = function() {
return true;
};
// Widget extensions
ArchEditorControl.prototype._initWidgetEventHandlers = function() {
EasyDAGControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getCreateNewDecorator = this.getCreateNewDecorator.bind(this);
};
ArchEditorControl.prototype.getCreateNewDecorator = function() {
return this._client.decoratorManager.getDecoratorForWidget(
'EllipseDecorator',
'EasyDAG'
);
};
return ArchEditorControl;
@@ -5,13 +5,11 @@
*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'deepforge/viz/RenameablePanel',
'widgets/ArchEditor/ArchEditorWidget',
'./ArchEditorControl'
], function (
PanelBaseWithHeader,
IActivePanel,
RenameablePanel,
ArchEditorWidget,
ArchEditorControl
) {
@@ -22,11 +20,11 @@ define([
ArchEditorPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArchEditorPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
options[RenameablePanel.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArchEditorPanel';
options[RenameablePanel.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
RenameablePanel.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
@@ -37,9 +35,7 @@ define([
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ArchEditorPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(ArchEditorPanel.prototype, IActivePanel.prototype);
_.extend(ArchEditorPanel.prototype, RenameablePanel.prototype);
ArchEditorPanel.prototype._initialize = function () {
var self = this;
@@ -60,6 +56,7 @@ define([
widget: this.widget
});
this.initializeRenameable();
this.onActivate();
};
@@ -67,7 +64,7 @@ define([
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ArchEditorPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
RenameablePanel.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
@@ -81,7 +78,7 @@ define([
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
RenameablePanel.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
@@ -29,7 +29,7 @@ define([
// input/output updates are actually activeNode updates
ClassCodeEditorControl.prototype._onUpdate = function (id) {
if (id === this._currentNodeId) {
TextEditorControl.prototype._onUpdate.call(this, this._currentNodeId);
TextEditorControl.prototype._onUpdate.call(this, id);
}
};
@@ -2,9 +2,11 @@
/*jshint browser: true*/
define([
'panels/SerializeEditor/SerializeEditorControl',
'panels/TextEditor/TextEditorControl',
'underscore'
], function (
SerializeEditorControl,
TextEditorControl,
_
) {
@@ -20,15 +22,8 @@ define([
_.extend(
DeserializeEditorControl.prototype,
TextEditorControl.prototype
SerializeEditorControl.prototype
);
// input/output updates are actually activeNode updates
DeserializeEditorControl.prototype._onUpdate = function (id) {
if (id === this._currentNodeId) {
TextEditorControl.prototype._onUpdate.call(this, this._currentNodeId);
}
};
return DeserializeEditorControl;
});
@@ -68,58 +68,6 @@ define([
return null;
};
var UPLOAD_PLUGIN = 'ImportArtifact',
DATA_TYPE_CONFIG = {
name: 'dataTypeId',
displayName: 'Data Type Id',
valueType: 'string',
valueItems: []
};
var uploadArtifact = function() {
// Get the data types
var dataBase,
dataBaseId,
metanodes = this.client.getAllMetaNodes(),
dataTypes = []; // TODO
dataBase = metanodes.find(n => n.getAttribute('name') === 'Data');
if (!dataBase) {
this.logger.error('Could not find the base Data node!');
return;
}
dataBaseId = dataBase.getId();
dataTypes = metanodes.filter(n => this.client.isTypeOf(n.getId(), dataBaseId))
.map(node => node.getAttribute('name'));
this.logger.info(`Found ${dataTypes.length} data types`);
// Add the target type to the pluginMetadata... hacky :/
// FIXME: this should create it's own plugin dialog which allows
// users to select the data type
var metadata = WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN],
config = metadata.configStructure
.find(opt => opt.name === DATA_TYPE_CONFIG.name);
if (!config) {
config = DATA_TYPE_CONFIG;
WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN].configStructure.push(config);
}
config.valueItems = dataTypes;
config.value = dataTypes[0];
WebGMEGlobal.InterpreterManager.configureAndRun(metadata, (result) => {
if (!result) {
Materialize.toast('Artifact upload failed!', 2000);
return;
}
this.logger.info('Finished uploading ' + UPLOAD_PLUGIN);
Materialize.toast('Artifact upload complete!', 2000);
});
};
var importTorch = function() {
var pluginId = 'ImportTorch',
context = this.client.getCurrentPluginContext(pluginId),
@@ -144,20 +92,62 @@ define([
fileInput.click();
};
var returnToLastPipeline = () => {
var returnId = DeepForge.lastPipeline || DeepForge.places.MyPipelines;
var returnToLast = (place) => {
var returnId = DeepForge.last[place];
WebGMEGlobal.State.registerActiveObject(returnId);
};
return {
// Meta nodes
MyPipelines_META: [
var prototypeButtons = function(type, fromType) {
return [
{
name: 'Create new pipeline',
icon: 'queue',
action: DeepForge.create.Pipeline
name: `Return to ${fromType}`,
icon: 'input',
priority: 2,
filter: () => {
return DeepForge.last[fromType];
},
action: returnToLast.bind(null, fromType)
},
{
name: `Delete ${type} Definition`,
icon: 'delete',
priority: 1,
action: function() {
// Delete and go to the last pipeline?
var node = this.client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
msg = `Deleted ${type} Definition for "${name}"`;
this.deleteCurrentNode(msg);
setTimeout(() => Materialize.toast(msg, 2000), 10);
returnToLast(fromType);
}
}
],
];
};
var MyPipelinesButtons = [
{
name: 'Create new pipeline',
icon: 'queue',
action: DeepForge.create.Pipeline
}
];
var makeRestartButton = function(name, pluginId) {
return {
name: 'Restart ' + name,
icon: 'replay',
priority: 1000,
action: function(event) {
this.runExecutionPlugin(pluginId, event.shiftKey);
}
};
};
return {
HOME: MyPipelinesButtons,
MyPipelines_META: MyPipelinesButtons,
MyArchitectures_META: [
{
name: 'Create new architecture',
@@ -200,17 +190,16 @@ define([
{
name: 'Upload artifact',
icon: 'swap_vert',
action: uploadArtifact
}
],
Operation_META: [
{
name: 'Return to Pipeline',
icon: 'input',
action: returnToLastPipeline
action: DeepForge.create.Artifact
}
],
// Creating prototypes
Operation_META: prototypeButtons('Operation', 'Pipeline'),
Layer_META: prototypeButtons('Layer', 'Architecture'),
Complex_META: prototypeButtons('Class', 'Operation'),
Primitive_META: prototypeButtons('Primitive Type', 'Operation'),
// Instances
Data: [
{
@@ -220,12 +209,15 @@ define([
}
],
Job: [
makeRestartButton('Job', 'ExecuteJob'),
{
name: 'Download Execution Files',
icon: 'play_for_work',
priority: 1,
href: download.execFiles
}
],
Execution: [makeRestartButton('Execution', 'ExecutePipeline')],
Pipeline: [
{
name: 'Create new node',
@@ -234,14 +226,13 @@ define([
action: function() {
this.addOperation();
}
},
}
],
Architecture: [
{
name: 'Create new node',
icon: 'queue',
priority: 2,
action: function() {
this.addOperation();
}
name: 'Import Torch Architecture',
icon: 'swap_vert',
action: importTorch
}
]
};
@@ -1,4 +1,4 @@
/*globals DeepForge, $, define, _ */
/*globals DeepForge, $, Materialize, define, _ */
/*jshint browser: true*/
define([
@@ -7,7 +7,6 @@ define([
'panel/FloatingActionButton/FloatingActionButton',
'deepforge/viz/PipelineControl',
'deepforge/viz/NodePrompter',
'deepforge/viz/AddDecorator',
'./Actions',
'widgets/EasyDAG/AddNodeDialog',
'js/RegistryKeys',
@@ -21,7 +20,6 @@ define([
PluginButton,
PipelineControl,
NodePrompter,
AddDecorator,
ACTIONS,
AddNodeDialog,
REGISTRY_KEYS,
@@ -59,6 +57,13 @@ define([
actions,
basename;
if (!base) { // must be ROOT or FCO
basename = node.getAttribute('name') || 'ROOT_NODE';
actions = (ACTIONS[basename] || [])
.filter(action => !action.filter || action.filter());
return actions;
}
while (base && !(actions && actions.length)) {
basename = base.getAttribute('name') + suffix;
base = this.client.getNode(base.getBaseId());
@@ -183,8 +188,7 @@ define([
ForgeActionButton.prototype.promptLayerType = function() {
// Prompt for the new custom layer's base type
var deferred = Q.defer(),
metanodes = this.client.getAllMetaNodes(),
var metanodes = this.client.getAllMetaNodes(),
baseLayerId = metanodes.find(n => n.getAttribute('name') === 'Layer').getId(),
layerType,
types;
@@ -206,8 +210,7 @@ define([
};
});
AddNodeDialog.prompt(types, deferred.resolve);
return deferred.promise;
return AddNodeDialog.prompt(types);
};
ForgeActionButton.prototype.uploadFile = function(event) {
@@ -249,10 +252,7 @@ define([
/////////////// Expanding containers ///////////////
ForgeActionButton.prototype.addOperation = function() {
var ops = this.getValidInitialNodes(),
newOperation = {
id: NEW_OPERATION_ID,
Decorator: AddDecorator
};
newOperation = this.getNewOpNode();
// Add the 'New op button'
ops.push(newOperation);
@@ -260,15 +260,26 @@ define([
this.promptNode(ops, (selected, prompter) => {
if (selected.id === NEW_OPERATION_ID) {
prompter.destroy();
DeepForge.lastPipeline = this._currentNodeId;
DeepForge.create.Operation();
//WebGMEGlobal.State.registerActiveObject(newId);
} else {
this.createNode(selected.id);
}
});
};
ForgeActionButton.prototype.getNewOpNode = function() {
var Decorator = this.client.decoratorManager.getDecoratorForWidget(
'OperationDecorator', 'EasyDAG');
return {
id: NEW_OPERATION_ID,
class: 'create-node',
name: 'New Operation...',
Decorator: Decorator,
attributes: {}
};
};
ForgeActionButton.prototype.promptNode = function(nodes, selectFn) {
// Get the absolute location of the given button
var mainBtn = this.$el[0].children[0],
@@ -301,5 +312,30 @@ define([
return prompter.prompt(nodes, selectFn);
};
ForgeActionButton.prototype.deleteCurrentNode = function(msg) {
var nodeId = this._currentNodeId;
if (nodeId) {
this.client.startTransaction(msg);
this.client.delMoreNodes([nodeId]);
this.client.completeTransaction(msg);
}
};
ForgeActionButton.prototype.runExecutionPlugin = function(pluginId, useSecondary) {
var context = this.client.getCurrentPluginContext(pluginId),
name = this.client.getNode(this._currentNodeId).getAttribute('name'),
method;
context.managerConfig.namespace = 'pipeline';
method = useSecondary ? 'runBrowserPlugin' : 'runServerPlugin';
this.client[method](pluginId, context, err => {
if (err) {
return Materialize.toast(`${name} failed!`, 4000);
}
Materialize.toast(`${name} executed successfully!`, 2000);
});
};
return ForgeActionButton;
});
@@ -0,0 +1,118 @@
/*globals define, _ */
/*jshint browser: true*/
// This editor will be a split screen view w/ the operation code on the left
// and the terminal on the right.
//
// However, if the job is contained in a "snapshotted" execution, then it will
// be considered read only and only show the terminal output
define([
'panels/TilingViz/TilingVizPanel',
'panels/OutputViewer/OutputViewerPanel',
'panels/OperationCodeEditor/OperationCodeEditorPanel',
'js/Constants'
], function (
TilingViz,
OutputViewer,
OperationCodeEditor,
CONSTANTS
) {
'use strict';
var JobEditorPanel;
JobEditorPanel = function (layoutManager, params) {
TilingViz.call(this, layoutManager, params);
this.readOnly = false;
};
//inherit from PanelBaseWithHeader
_.extend(JobEditorPanel.prototype, TilingViz.prototype);
JobEditorPanel.prototype.getPanels = function () {
if (this.readOnly) {
return [OutputViewer];
} else {
return [OperationCodeEditor, OutputViewer];
}
};
JobEditorPanel.prototype.selectedObjectChanged = function (nodeId) {
var node = this._client.getNode(nodeId),
typeId,
type,
typeName,
executionId,
execution;
if (typeof nodeId === 'string') {
typeId = node.getMetaTypeId();
type = this._client.getNode(typeId);
typeName = type.getAttribute('name');
if (typeName !== 'Job') {
this.logger.error(`Invalid node type for JobEditor: ${typeName}`);
return;
}
executionId = node.getParentId();
execution = this._client.getNode(executionId);
// If the current node is in a snapshotted execution, only show the log
// viewer
if (this.readOnly !== execution.getAttribute('snapshot')) {
this.readOnly = execution.getAttribute('snapshot');
this.logger.info(`readonly set to ${this.readOnly}`);
this.updatePanels();
}
// The OperationCodeEditor should receive the
if (!this.readOnly) {
// Get the operation base node id and pass it to OpCodeEditor selObjChanged
if (this._territoryId) {
this._client.removeUI(this._territoryId);
}
this._territoryId = this._client.addUI(this,
this.onOperationEvents.bind(this));
// Update the territory
this._territory = {};
this._territory[nodeId] = {children: 1};
this._client.updateTerritory(this._territoryId, this._territory);
}
// update the OutputViewer controller
var i = this._panels.length;
this._panels[i-1].control.selectedObjectChanged(nodeId);
}
};
JobEditorPanel.prototype.onOperationEvents = function (events) {
var event = events.find(event => {
if (event.etype === CONSTANTS.TERRITORY_EVENT_LOAD) {
// Check if the eid is an Operation
var typeId = this._client.getNode(event.eid).getMetaTypeId(),
type = this._client.getNode(typeId),
metaBaseId = type && type.getBaseId(),
typeName;
if (metaBaseId) {
typeName = this._client.getNode(metaBaseId).getAttribute('name');
}
return typeName === 'Operation';
}
});
if (event && !this.readOnly) {
var opNode = this._client.getNode(event.eid),
opDefId = opNode.getMetaTypeId();
this._panels[0].control.selectedObjectChanged(opDefId);
this._panels[0].control.offsetNodeChanged(event.eid);
}
};
return JobEditorPanel;
});
@@ -0,0 +1,184 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames'
], function (
CONSTANTS,
GMEConcepts,
nodePropertyNames
) {
'use strict';
var LineGraphControl;
LineGraphControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
this._embedded = options.embedded;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this._currentNodeParentId = undefined;
this._logger.debug('ctor finished');
};
/* * * * * * * * 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).
LineGraphControl.prototype.selectedObjectChanged = function (nodeId) {
var desc = this._getObjectDescriptor(nodeId),
self = this;
self._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
if (self._currentNodeId) {
self._client.removeUI(self._territoryId);
}
self._currentNodeId = nodeId;
self._currentNodeParentId = undefined;
if (typeof self._currentNodeId === 'string') {
// Put new node's info into territory rules
self._selfPatterns = {};
self._selfPatterns[nodeId] = {children: 0}; // Territory "rule"
self._widget.setTitle(desc.name.toUpperCase());
self._currentNodeParentId = desc.parentId;
self._territoryId = self._client.addUI(self, function (events) {
self._eventCallback(events);
});
// Update the territory
self._client.updateTerritory(self._territoryId, self._selfPatterns);
self._selfPatterns[nodeId] = {children: 1};
self._client.updateTerritory(self._territoryId, self._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
LineGraphControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
desc;
if (node) {
desc = {
id: node.getId(),
name: node.getAttribute(nodePropertyNames.Attributes.name)
};
// Check if it is a line
if (desc.id !== this._currentNodeId) {
var points = (node.getAttribute('points') || '').split(';')
.map(pair => {
var nums = pair.split(','),
x = +nums[0],
y = +nums[1];
return {
x: x,
y:y
};
});
desc.type = 'line';
desc.points = points;
}
}
return desc;
};
/* * * * * * * * Node Event Handling * * * * * * * */
LineGraphControl.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');
};
LineGraphControl.prototype._onLoad = function (gmeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.addNode(description);
};
LineGraphControl.prototype._onUpdate = function (gmeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.updateNode(description);
};
LineGraphControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
LineGraphControl.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 * * * * * * * */
LineGraphControl.prototype.destroy = function () {
this._detachClientEventListeners();
};
LineGraphControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this);
};
LineGraphControl.prototype._detachClientEventListeners = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged);
};
LineGraphControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
LineGraphControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return LineGraphControl;
});
@@ -0,0 +1,101 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/LineGraph/LineGraphWidget',
'./LineGraphControl'
], function (
PanelBaseWithHeader,
IActivePanel,
LineGraphWidget,
LineGraphControl
) {
'use strict';
var LineGraphPanel;
LineGraphPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'LineGraphPanel';
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(LineGraphPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(LineGraphPanel.prototype, IActivePanel.prototype);
LineGraphPanel.prototype._initialize = function () {
var self = this;
//set Widget title
this.setTitle('');
this.widget = new LineGraphWidget(this.logger, this.$el);
this.widget.setTitle = function (title) {
self.setTitle(title);
};
this.control = new LineGraphControl({
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 */
LineGraphPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
LineGraphPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
LineGraphPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
LineGraphPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
LineGraphPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return LineGraphPanel;
});
@@ -0,0 +1,225 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'blob/BlobClient',
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames',
'deepforge/globals'
], function (
BlobClient,
CONSTANTS,
GMEConcepts,
nodePropertyNames,
DeepForge
) {
'use strict';
var MainViewControl;
MainViewControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
// Initialize core collections and variables
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;
}
};
};
/* * * * * * * * 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).
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] = {};
this.territory[type][DeepForge.places[dirname]] = {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,128 @@
/*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',
'deepforge/globals'
], function (
PanelBaseWithHeader,
IActivePanel,
MainViewWidget,
MainViewControl,
PipelineIndexPanel,
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.embeddedPanel = new PipelineIndexPanel(layoutManager, params);
this.$embedded = this.embeddedPanel.$el;
this.$embedded.addClass('embedded');
this.$el.append(this.$nav, this.$embedded);
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
});
var controlObjectChanged = this.control.selectedObjectChanged;
this.control.selectedObjectChanged = nodeId => {
this.embeddedPanel.control.selectedObjectChanged(DeepForge.places.MyPipelines);
return controlObjectChanged.call(this.control, nodeId);
};
this.onActivate();
};
/* 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);
};
/* * * * * * * * 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;
});
@@ -1,16 +1,15 @@
/*globals define */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 12:00:46 GMT-0500 (CDT).
*/
define([
'panels/TextEditor/TextEditorControl',
'deepforge/viz/OperationControl',
'deepforge/Constants',
'underscore'
], function (
TextEditorControl,
OperationControl,
CONSTANTS,
_
) {
@@ -59,5 +58,32 @@ define([
}
};
// Line offset handling
OperationCodeEditorControl.prototype.offsetNodeChanged = function (id) {
// Create a territory for this node
if (this._offsetUI) {
this._client.removeUI(this._offsetUI);
}
this._offsetNodeId = id;
this._offsetUI = this._client.addUI(this, this.onOffsetNodeEvents.bind(this));
this._offsetTerritory = {};
this._offsetTerritory[id] = {children: 0};
this._client.updateTerritory(this._offsetUI, this._offsetTerritory);
};
OperationCodeEditorControl.prototype.onOffsetNodeEvents = function () {
var node = this._client.getNode(this._offsetNodeId);
if (node) { // wasn't a 'delete' event
this._widget.setLineOffset(node.getAttribute(CONSTANTS.LINE_OFFSET) || 0);
}
};
OperationCodeEditorControl.prototype.destroy = function () {
TextEditorControl.prototype.destroy.call(this);
if (this._offsetUI) {
this._client.removeUI(this._offsetUI);
}
};
return OperationCodeEditorControl;
});
@@ -1,8 +1,5 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 12:00:46 GMT-0500 (CDT).
*/
define([
'js/PanelBase/PanelBaseWithHeader',
@@ -1,15 +1,21 @@
/*globals define, */
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'deepforge/globals',
'deepforge/viz/RenameablePanel',
'panels/TilingViz/TilingVizPanel',
'panels/OperationCodeEditor/OperationCodeEditorPanel',
'panels/OperationInterfaceEditor/OperationInterfaceEditorPanel',
'js/Constants',
'underscore'
], function (
DeepForge,
RenameablePanel,
TilingViz,
CodeEditor,
InterfaceEditor,
CONSTANTS,
_
) {
'use strict';
@@ -18,13 +24,66 @@ define([
OperationEditorPanel = function (layoutManager, params) {
TilingViz.call(this, layoutManager, params);
this.initialize();
};
OperationEditorPanel.prototype.initialize = function () {
this.territory = {};
this.territoryId = null;
this._currentNodeId = null;
this.control = this;
// Set the editable title on node change
this.initializeRenameable();
};
//inherit from TilingViz
_.extend(OperationEditorPanel.prototype, TilingViz.prototype);
_.extend(
OperationEditorPanel.prototype,
RenameablePanel.prototype,
TilingViz.prototype
);
OperationEditorPanel.prototype.selectedObjectChanged = function (id) {
this._currentNodeId = id;
DeepForge.last.Operation = id;
if (typeof this._currentNodeId === 'string') {
// Setup the territory
this.territory = {};
this.territory[this._currentNodeId] = {children: 0};
this.territoryId = this._client.addUI(this, this._eventCallback.bind(this));
this._client.updateTerritory(this.territoryId, this.territory);
}
TilingViz.prototype.selectedObjectChanged.call(this, id);
};
OperationEditorPanel.prototype._eventCallback = function (events) {
events = events.find(e => e.eid === this._currentNodeId);
this.updateTitle();
};
OperationEditorPanel.prototype.updateTitle = function () {
var id = this._currentNodeId,
node = this._client.getNode(id),
name = node && node.getAttribute('name');
this.setTitle(name || '');
};
OperationEditorPanel.prototype.getPanels = function () {
return [CodeEditor, InterfaceEditor];
return [InterfaceEditor, CodeEditor];
};
OperationEditorPanel.prototype.onDeactivate = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
if (this.territoryId) {
this._client.removeUI(this.territoryId);
}
TilingViz.prototype.onDeactivate.call(this);
};
return OperationEditorPanel;
@@ -0,0 +1,5 @@
/*globals define*/
define({
PRIMITIVE: '#b0bec5',
COMPLEX: '#78909c'
});
@@ -1,6 +1,8 @@
/*globals define*/
define([
'./Colors'
], function(
COLORS
) {
'use strict';
var OperationInterfaceEditorEvents = function() {
@@ -9,6 +11,25 @@ define([
this._widget.addRefTo = this.addRefTo.bind(this);
this._widget.changePtrName = this.changePtrName.bind(this);
this._widget.removePtr = this.removePtr.bind(this);
this._widget.getCreationNode = this.getCreationNode.bind(this);
};
OperationInterfaceEditorEvents.prototype.getCreationNode = function(type, id) {
var typeName = type === 'Complex' ? 'Class' : 'Primitive',
Decorator = this._client.decoratorManager.getDecoratorForWidget(
this.DEFAULT_DECORATOR, 'EasyDAG');
return {
node: {
id: id,
class: 'create-node',
name: `New ${typeName}...`,
Decorator: Decorator,
color: COLORS[type.toUpperCase()],
isPrimitive: type === 'Primitive',
attributes: {}
}
};
};
OperationInterfaceEditorEvents.prototype.allValidReferences = function() {
@@ -19,7 +40,7 @@ define([
var notTypes = ['Data', 'Operation', 'Pipeline'];
return this._client.getAllMetaNodes()
.filter(node => {
var plugins = node.getRegistry('validPlugins');
var plugins = node.getOwnRegistry('validPlugins');
// Convention is enforced; if the plugin generates lua artifacts,
// it should be called `Generate`.. (something)
return plugins && plugins.indexOf('Generate') !== -1;
@@ -34,23 +55,28 @@ define([
});
};
OperationInterfaceEditorEvents.prototype.allDataTypeIds = function() {
return this.allDataTypes().map(node => node.getId());
OperationInterfaceEditorEvents.prototype.allDataTypeIds = function(incAbstract) {
return this.allDataTypes(incAbstract).map(node => node.getId());
};
OperationInterfaceEditorEvents.prototype.allDataTypes = function() {
OperationInterfaceEditorEvents.prototype.allDataTypes = function(incAbstract) {
return this._client.getAllMetaNodes()
.filter(node => this.hasMetaName(node.getId(), 'Data'))
.filter(node => this.hasMetaName(node.getId(), 'Data', incAbstract))
.filter(node => !node.isAbstract());
};
OperationInterfaceEditorEvents.prototype._getValidSuccessorNodes = function(nodeId) {
// Return all data types in the meta
OperationInterfaceEditorEvents.prototype.getValidSuccessors = function(nodeId, isInput) {
var dataTypeIds;
if (nodeId !== this._currentNodeId) {
return [];
}
return this.allDataTypeIds().map(id => {
// Return all data types in the meta
// If input, include abstract types
dataTypeIds = this.allDataTypeIds(isInput);
return dataTypeIds.map(id => {
return {
node: this._getObjectDescriptor(id)
};
@@ -9,14 +9,20 @@
define([
'panels/EasyDAG/EasyDAGControl',
'js/Constants',
'deepforge/Constants',
'deepforge/lua',
'deepforge/viz/OperationControl',
'./OperationInterfaceEditorControl.EventHandlers',
'./Colors',
'underscore'
], function (
EasyDAGControl,
GME_CONSTANTS,
CONSTANTS,
luajs,
OperationControl,
OperationInterfaceEditorControlEvents,
COLORS,
_
) {
@@ -30,6 +36,9 @@ define([
OperationInterfaceEditorControlEvents.call(this);
this._connections = {};
this._pointers = {};
this._usage = {}; // info about input usage
this._inputs = {};
};
_.extend(
@@ -81,13 +90,13 @@ define([
for (var i = 0; i < events.length; i++) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
case GME_CONSTANTS.TERRITORY_EVENT_LOAD:
this._onLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
case GME_CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
case GME_CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
@@ -139,18 +148,48 @@ define([
desc.container = cntr.toLowerCase();
desc.attributes = {};
} else if (desc.id === this._currentNodeId) {
desc.pointers = {};
// Remove DeepForge hidden attributes
delete desc.attributes.code;
delete desc.attributes[CONSTANTS.LINE_OFFSET];
}
// Extra decoration for data
if (this.hasMetaName(desc.id, 'Data', true)) {
desc.color = this.getDescColor(gmeId);
desc.isPrimitive = this.hasMetaName(gmeId, 'Primitive');
var used = desc.container === 'inputs' ?
this.isUsedInput(desc.name) : this.isUsedOutput(desc.name);
if (used !== null) {
desc.used = used;
this._usage[desc.id] = desc.used;
} else {
desc.used = this._usage[desc.id] !== undefined ?
this._usage[desc.id] : true;
}
this._inputs[desc.id] = desc.container === 'inputs';
}
return desc;
};
OperationInterfaceEditorControl.prototype.getDescColor = function(gmeId) {
return !this.hasMetaName(gmeId, 'Primitive', true) ? COLORS.COMPLEX :
COLORS.PRIMITIVE;
};
OperationInterfaceEditorControl.prototype._onUnload = function(gmeId) {
EasyDAGControl.prototype._onUnload.call(this, gmeId);
var conn = this._connections[gmeId];
if (conn) {
this._widget.removeNode(conn.id);
}
delete this._usage[gmeId];
delete this._inputs[gmeId];
};
OperationInterfaceEditorControl.prototype._onLoad = function(gmeId) {
@@ -170,12 +209,40 @@ define([
};
OperationInterfaceEditorControl.prototype._onUpdate = function(gmeId) {
var variableIds,
wasUsed,
isUsed,
name,
ast,
code;
if (gmeId === this._currentNodeId) {
EasyDAGControl.prototype._onUpdate.call(this, gmeId);
// Update the valid pointers
this.updatePtrs();
// Update the remaining usage info
variableIds = Object.keys(this._usage);
code = this._client.getNode(this._currentNodeId).getAttribute('code');
try {
ast = luajs.parser.parse(code);
for (var i = variableIds.length; i--;) {
wasUsed = this._usage[variableIds[i]];
name = this._client.getNode(variableIds[i]).getAttribute('name');
isUsed = this._inputs[variableIds[i]] ?
this.isUsedInput(name, ast) :
this.isUsedOutput(name, ast);
if (isUsed !== wasUsed) {
this._onUpdate(variableIds[i]);
}
}
} catch (e) {
this._logger.debug(`failed parsing lua: ${e}`);
}
} else if (this.containedInCurrent(gmeId) && this.hasMetaName(gmeId, 'Data')) {
EasyDAGControl.prototype._onUpdate.call(this, gmeId);
}
@@ -192,13 +259,20 @@ define([
.items[0].id,
target = this._client.getNode(targetId),
decManager = this._client.decoratorManager,
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG');
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
id = 'ptr_'+name,
used = this.isUsedInput(name);
if (used === null) {
used = this._usage[id] !== undefined ? this._usage[id] : true;
}
return {
id: 'ptr_'+name,
id: id,
isPointer: true,
baseName: target.getAttribute('name'),
Decorator: Decorator,
used: used,
attributes: {},
name: name,
parentId: this._currentNodeId
@@ -217,7 +291,7 @@ define([
// Get the pointers that should exist [name, target]
this.loadMeta();
newPtrs = node.getPointerNames()
.filter(name => name !== CONSTANTS.POINTER_BASE)
.filter(name => name !== GME_CONSTANTS.POINTER_BASE)
.map(name => this.getPtrDescriptor(name));
// Compare them to the existing...
@@ -255,9 +329,13 @@ define([
OperationInterfaceEditorControl.prototype.rmPtr = function(id) {
// Remove the pointer's node
this._widget.removeNode(id);
// and connection
var conn = this._connections[id];
this._widget.removeNode(conn.id);
// and usage info
delete this._usage[id];
};
OperationInterfaceEditorControl.prototype.containedInCurrent = function(id) {
@@ -282,5 +360,79 @@ define([
return conn;
};
////////////////////// Unused input checking //////////////////////
OperationInterfaceEditorControl.prototype.isUsedInput = function(name, ast) {
return this._isUsed(name, true, ast);
};
OperationInterfaceEditorControl.prototype.isUsedOutput = function(name, ast) {
return this._isUsed(name, false, ast);
};
OperationInterfaceEditorControl.prototype._isUsed = function(name, isInput, ast) {
var code = this._client.getNode(this._currentNodeId).getAttribute('code'),
r = new RegExp('\\b' + name + '\\b'),
hasText = code.match(r) !== null;
// verify that it is not used only in the left side of an assignment
if (hasText) {
try {
ast = ast || luajs.parser.parse(code);
return isInput ? this.isUsedVariable(name, ast) : this.isReturnValue(name, ast);
} catch(e) {
this._logger.debug(`failed parsing lua: ${e}`);
return null;
}
}
return false;
};
// Check if it is used in the given ast node
OperationInterfaceEditorControl.prototype.isUsedVariable = function(name, node) {
var isUsed = false,
checker;
checker = luajs.codegen.traverse((curr, parent) => {
if (curr.type === 'variable' && curr.val === name) {
// Ignore if it is being assigned...
if (parent.type === 'stat.assignment') {
isUsed = isUsed || parent.right.indexOf(curr) !== -1;
} else {
isUsed = true;
}
}
return curr;
});
checker(node);
return isUsed;
};
OperationInterfaceEditorControl.prototype.isReturnValue = function(name, ast) {
var firstReturn,
fields,
key,
node;
for (var i = ast.block.stats.length; i--;) {
node = ast.block.stats[i];
if (node.type === 'stat.return') {
// Check that it returns an object w/ a key of the given name
firstReturn = node.nret[0];
if (firstReturn && firstReturn.type === 'expr.constructor') {
fields = firstReturn.fields;
for (var j = fields.length; j--;) {
key = fields[j].key;
if (key.type === 'const.string' && key.val === name) {
return true;
}
}
}
}
}
return false;
};
return OperationInterfaceEditorControl;
});
@@ -0,0 +1,13 @@
.output-viewer .output-pager {
position: absolute;
left: 0.75em;
bottom: 0;
z-index: 100;
}
.output-viewer .empty {
visibility: hidden;
}
.output-viewer .pagination {
margin-bottom: 0.5em;
}
@@ -0,0 +1,301 @@
/*globals define, $, _, WebGMEGlobal*/
/*jshint browser: true*/
// The OutputViewer is a viz which shows the LogViewer and, if the job has
// metadata, provides a pagination bar in the lower left to page through
// the metadata results
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'panels/LogViewer/LogViewerPanel',
'js/Constants',
'js/RegistryKeys',
'text!api/visualizers',
'css!./OutputViewer.css'
], function (
PanelBaseWithHeader,
IActivePanel,
LogViewer,
CONSTANTS,
REGISTRY_KEYS,
VisualizersJSON
) {
'use strict';
var OutputViewerPanel,
Visualizers = JSON.parse(VisualizersJSON);
OutputViewerPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'OutputViewerPanel';
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._currentNodeId = null;
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._layoutManager = layoutManager;
this.dimensions = null;
this._params = params;
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(OutputViewerPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(OutputViewerPanel.prototype, IActivePanel.prototype);
OutputViewerPanel.prototype._initialize = function () {
this.control = this; // implement selectedObjectChanged here
this._panels = {
LogViewer: LogViewer
};
// Create the pagination container
this._pages = {};
this._pageCount = 0;
this.$el.addClass('output-viewer');
this.$pager = $('<nav>', {class: 'output-pager empty'});
this.$pagerList = $('<ul>', {class: 'pagination'});
// Add the console item
var logviewer = $('<li class="active"><a>Console</a></li>');
this.$logviewer = logviewer.find('a');
this.$selected = this.$logviewer;
this.$pagerList.append(logviewer);
this.$pager.append(this.$pagerList);
this.$el.append(this.$pager);
this.$el.css({padding: 0});
// On 'page' clicked, set the activePanel to a new AutoViz and set
// the given nodeId as the active node for it
this.$pager.on('click', 'li', event => {
var element = $(event.target);
this.selectOutput(element);
});
// Set the activePanel
this.activePanel = new LogViewer(this._layoutManager, this._params);
this.$el.append(this.activePanel.$el);
this.onActivate();
};
OutputViewerPanel.prototype.selectOutput = function (element) {
if (this.$selected !== element) {
this.$selected.parent().removeClass('active');
element.parent().addClass('active');
this.$selected = element;
// Update the panel
var dataId = element.data('id');
if (dataId) {
this.loadOutputFor(dataId);
} else { // Set the logviewer
this.loadPanel(LogViewer, this._currentNodeId);
}
}
};
OutputViewerPanel.prototype.loadOutputFor = function (id) {
var node = this._client.getNode(id),
panelId,
panel,
panelPath;
if (!node) {
this.logger.error(`could not load node: ${id}`);
return;
}
// Get the registered visualizer
panelId = (node.getRegistry(REGISTRY_KEYS.VALID_VISUALIZERS) || '')
.split(' ')
.shift();
// Load it (embedded) and set the selected node to 'id'
panel= Visualizers.find(desc => desc.id === panelId);
if (panel) {
panelPath = panel.panel;
if (this._panels[panelPath]) {
this.loadPanel(this._panels[panelPath], id);
} else {
require([panelPath],
function(Panel) {
this._panels[panelPath] = Panel;
this.loadPanel(Panel, id);
}.bind(this),
err =>
this.logger.error(`could not load ${panelPath}: ${err}`)
);
}
} else {
this.logger.warn(`Could not find visualizer: ${panelId}`);
}
};
OutputViewerPanel.prototype.loadPanel = function (Panel, nodeId) {
if (this.activePanel) {
this.activePanel.destroy();
this.activePanel.$el.remove();
}
this.activePanel = new Panel(this._layoutManager, this._params);
this.$el.append(this.activePanel.$el);
if (nodeId) {
this.activePanel.control.selectedObjectChanged(nodeId);
}
if (this.dimensions) {
this.onResize.apply(this, this.dimensions);
}
};
OutputViewerPanel.prototype.clearTerritory = function () {
if (this._territoryUI) {
this._client.removeUI(this._territoryUI);
this._territoryUI = null;
}
};
OutputViewerPanel.prototype.selectedObjectChanged = function (nodeId) {
if (typeof nodeId === 'string') {
this._currentNodeId = nodeId;
this.clearTerritory();
this._territoryUI = this._client.addUI(this, this.handleEvents.bind(this));
// Create the territory (active node and children)
this._territory = {};
this._territory[nodeId] = {children: 1};
this._client.updateTerritory(this._territoryUI, this._territory);
this.activePanel.control.selectedObjectChanged(nodeId);
}
};
OutputViewerPanel.prototype.getMetadataId = function () {
var metanodes = this._client.getAllMetaNodes();
for (var i = metanodes.length; i--;) {
if (metanodes[i].getAttribute('name') === 'Metadata') {
return metanodes[i].getId();
}
}
return null;
};
OutputViewerPanel.prototype.handleEvents = function (events) {
var metadataId = this.getMetadataId(),
event;
if (!metadataId) {
this.logger.error(`No metadata id found! "${metadataId}"`);
return;
}
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) {
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;
}
}
};
OutputViewerPanel.prototype.onUpdate = function (nodeId) {
var name = this._client.getNode(nodeId).getAttribute('name');
if (this._pages[nodeId]) {
this._pages[nodeId].find('a').text(name);
}
};
OutputViewerPanel.prototype.onLoad = function (nodeId) {
var node = this._client.getNode(nodeId),
name = node.getAttribute('name');
this.addToPager(name, nodeId);
};
OutputViewerPanel.prototype.onUnload = function (nodeId) {
// If the current metadata node is deleted, change back to logviewer
if (this._pages[nodeId]) {
var selectedId = this.$selected.data('id');
if (nodeId === selectedId) {
this.selectOutput(this.$logviewer);
}
// Update the pager
this._pages[nodeId].remove();
this._pageCount--;
if (this._pageCount === 0) {
this.$pager.addClass('empty');
}
}
};
OutputViewerPanel.prototype.addToPager = function (name, nodeId) {
var $el = $('<li>'),
$a = $('<a>');
$a.text(name);
$a.attr('data-id', nodeId);
$el.append($a);
this._pages[nodeId] = $el;
this.$pager.removeClass('empty');
this.$pagerList.append($el);
this._pageCount++;
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
OutputViewerPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
OutputViewerPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.dimensions = arguments;
this.$el.css({
width: width,
height: height
});
this.activePanel.onResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
OutputViewerPanel.prototype.destroy = function () {
this.activePanel.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
OutputViewerPanel.prototype.onActivate = function () {
this.activePanel.onActivate();
};
OutputViewerPanel.prototype.onDeactivate = function () {
this.activePanel.onDeactivate();
};
return OutputViewerPanel;
});
@@ -5,6 +5,7 @@ define([
'js/Constants',
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/PipelineControl',
'deepforge/globals',
'common/core/coreQ',
'common/storage/constants',
'q',
@@ -13,6 +14,7 @@ define([
CONSTANTS,
EasyDAGControl,
PipelineControl,
DeepForge,
Core,
STORAGE_CONSTANTS,
Q,
@@ -37,6 +39,7 @@ define([
this.addedIds = {};
this.executionTerritory = {};
this.executionUI = null;
this.invalidated = {};
this._widget.deleteNode = id => {
this._deleteNode(id);
};
@@ -53,6 +56,7 @@ define([
PipelineEditorControl.prototype.TERRITORY_RULE = {children: 3};
PipelineEditorControl.prototype.selectedObjectChanged = function (nodeId) {
DeepForge.last.Pipeline = nodeId;
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
@@ -65,7 +69,7 @@ define([
if (typeof this._currentNodeId === 'string') {
var desc = this._getObjectDescriptor(nodeId);
this._widget.setTitle(desc.name.toUpperCase());
this._widget.setTitle(desc.name);
if (typeof desc.parentId === 'string') {
this.$btnModelHierarchyUp.show();
@@ -80,6 +84,19 @@ define([
}
};
PipelineEditorControl.prototype.hasCurrentNode = function () {
return typeof this._currentNodeId === 'string';
};
PipelineEditorControl.prototype.onNodeNameChanged = function (from, to) {
var msg = `Renaming pipeline "${from}" -> "${to}"`;
if (from !== to && !/^\s*$/.test(to)) {
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, 'name', to);
this._client.completeTransaction();
}
};
PipelineEditorControl.prototype.updateTerritory = function() {
var nodeId = this._currentNodeId;
@@ -119,6 +136,8 @@ define([
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) {
@@ -132,7 +151,10 @@ define([
var desc = this._getObjectDescriptor(gmeId);
if (desc.parentId === this._currentNodeId) {
this.addedIds[desc.id] = true;
return EasyDAGControl.prototype._onLoad.call(this, gmeId);
// Validate any connections
if (this.isValid(desc)) {
return EasyDAGControl.prototype._onLoad.call(this, gmeId);
}
} else if (desc.parentId !== null &&
this.isContainedInActive(desc.parentId) && desc.isDataPort) {
// port added!
@@ -141,8 +163,33 @@ define([
}
};
PipelineEditorControl.prototype.isValid = function (desc) {
// If it is a "dangling connection", remove it!
if (desc.isConnection) {
if (!(desc.src && desc.dst)) {
var node = this._client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
msg = `Removing invalid connection ${desc.id} in "${name}"`;
this.invalidated[desc.id] = true;
this._client.startTransaction(msg);
this._client.delMoreNodes([desc.id]);
this._client.completeTransaction();
return false;
}
}
return true;
};
PipelineEditorControl.prototype._onUnload = function (gmeId) {
// Check if it has been added
if (this.invalidated[gmeId]) {
// No need to notify the widget; this was filtered bc it was
// an invalid connection
delete this.invalidated[gmeId];
return;
}
if(this.addedIds[gmeId]) {
delete this.addedIds[gmeId];
return EasyDAGControl.prototype._onUnload.call(this, gmeId);
@@ -537,5 +584,65 @@ define([
EasyDAGControl.prototype._detachClientEventListeners.call(this);
};
////////////////////// Execution Support END //////////////////////
PipelineEditorControl.prototype.getDecorator = function (nodeId) {
var node = this._client.getNode(nodeId);
if (node) {
return this._getNodeDecorator(node);
} else {
return this._client.decoratorManager.getDecoratorForWidget(
this.DEFAULT_DECORATOR, WIDGET_NAME);
}
};
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
// and the ones in the custom layer dir
var typeIds = this._client.getPointerMeta(id, ptr).items.map(item => item.id),
types = typeIds.map(id => this._client.getNode(id)),
criterion = types.find(node => node.getAttribute('name') === 'Criterion'),
items,
criterionId;
if (criterion) {
// Get all criterion types
criterionId = criterion.getId();
items = this._client.getAllMetaNodes().map(node => node.getId())
.filter(id => this._client.isTypeOf(id, criterionId));
return items.map(id => {
return {
node: this._getObjectDescriptor(id)
};
});
} else {
return EasyDAGControl.prototype._getValidTargetsFor.apply(this, arguments);
}
};
return PipelineEditorControl;
});
@@ -61,9 +61,25 @@ define(['js/PanelBase/PanelBaseWithHeader',
widget: this.widget
});
// Editable pipeline name
this.$panelHeaderTitle.on('dblclick', () => this.editTitle());
this.onActivate();
};
PipelineEditorPanel.prototype.editTitle = function () {
if (this.control.hasCurrentNode()) {
this.$panelHeaderTitle.editInPlace({
css: {
'z-index': 1000
},
onChange: (oldValue, newValue) => {
this.control.onNodeNameChanged(oldValue, newValue);
}
});
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
PipelineEditorPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
@@ -0,0 +1,225 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'js/NodePropertyNames'
], function (
CONSTANTS,
nodePropertyNames
) {
'use strict';
var PipelineIndexControl;
PipelineIndexControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this._embedded = options.embedded;
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
PipelineIndexControl.prototype._initWidgetEventHandlers = function () {
this._widget.deletePipeline = id => {
var node = this._client.getNode(id),
name = node.getAttribute('name'),
msg = `Deleting pipeline "${name}"`;
// Change the current active object
this._client.startTransaction(msg);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
};
this._widget.setName = (id, name) => {
var oldName = this._client.getNode(id).getAttribute('name'),
msg = `Renaming Pipeline: "${oldName}" -> "${name}"`;
if (oldName !== name && !/^\s*$/.test(name)) {
this._client.startTransaction(msg);
this._client.setAttributes(id, 'name', name);
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).
PipelineIndexControl.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._selfPatterns = {};
this._selfPatterns[nodeId] = {children: 1};
this._territoryId = this._client.addUI(this, this._eventCallback.bind(this));
// Update the territory
this._client.updateTerritory(this._territoryId, this._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
PipelineIndexControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
objDescriptor;
if (node) {
objDescriptor = {
id: undefined,
name: undefined,
parentId: undefined,
thumbnail: node.getAttribute('thumbnail'),
executionCount: node.getMemberIds('executions').length
};
objDescriptor.id = node.getId();
objDescriptor.name = node.getAttribute(nodePropertyNames.Attributes.name);
objDescriptor.parentId = node.getParentId();
}
return objDescriptor;
};
/* * * * * * * * Node Event Handling * * * * * * * */
PipelineIndexControl.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');
};
PipelineIndexControl.prototype._onLoad = function (gmeId) {
if (gmeId !== this._currentNodeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.addNode(description);
}
};
PipelineIndexControl.prototype._onUpdate = function (gmeId) {
if (gmeId !== this._currentNodeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.updateNode(description);
}
};
PipelineIndexControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
PipelineIndexControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId !== activeObjectId) {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
PipelineIndexControl.prototype.destroy = function () {
this._detachClientEventListeners();
this._removeToolbarItems();
};
PipelineIndexControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this);
}
};
PipelineIndexControl.prototype._detachClientEventListeners = function () {
if (!this._embedded) {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged);
}
};
PipelineIndexControl.prototype.onActivate = function () {
this._attachClientEventListeners();
this._displayToolbarItems();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
PipelineIndexControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
this._hideToolbarItems();
};
/* * * * * * * * * * Updating the toolbar * * * * * * * * * */
PipelineIndexControl.prototype._displayToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].show();
}
} else {
this._initializeToolbar();
}
};
PipelineIndexControl.prototype._hideToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].hide();
}
}
};
PipelineIndexControl.prototype._removeToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].destroy();
}
}
};
PipelineIndexControl.prototype._initializeToolbar = function () {
this._toolbarItems = [];
this._toolbarInitialized = true;
};
return PipelineIndexControl;
});
@@ -0,0 +1,94 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed Jun 29 2016 16:10:46 GMT-0500 (CDT).
*/
define(['js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/PipelineIndex/PipelineIndexWidget',
'./PipelineIndexControl'
], function (PanelBaseWithHeader,
IActivePanel,
PipelineIndexWidget,
PipelineIndexControl) {
'use strict';
var PipelineIndexPanel;
PipelineIndexPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'PipelineIndexPanel';
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(PipelineIndexPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(PipelineIndexPanel.prototype, IActivePanel.prototype);
PipelineIndexPanel.prototype._initialize = function () {
//set Widget title
this.setTitle('');
this.widget = new PipelineIndexWidget(this.logger, this.$el);
this.control = new PipelineIndexControl({
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 */
PipelineIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
PipelineIndexPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
PipelineIndexPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
PipelineIndexPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
PipelineIndexPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return PipelineIndexPanel;
});
@@ -16,6 +16,7 @@ define([
SerializeEditorControl = function (options) {
options.attributeName = 'serialize';
TextEditorControl.call(this, options);
this._widget.setName = this.setName.bind(this);
};
_.extend(
@@ -1,8 +1,5 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 08:58:20 GMT-0500 (CDT).
*/
define([
'js/Constants',
@@ -47,12 +44,23 @@ define([
`for ${id} - node doesn't have the given attribute!`);
}
};
this._widget.setName = this.setName.bind(this);
};
TextEditorControl.prototype.saveTextFor = function (id, text) {
this._client.setAttributes(id, this.ATTRIBUTE_NAME, text);
};
TextEditorControl.prototype.setName = function (name) {
var node = this._client.getNode(this._currentNodeId),
oldName = node.getAttribute('name'),
msg = `Renaming ${oldName} -> ${name}`;
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, 'name', name);
this._client.completeTransaction();
};
TextEditorControl.prototype.TERRITORY_RULE = {children: 0};
TextEditorControl.prototype.selectedObjectChanged = function (nodeId) {
var self = this;
@@ -178,6 +186,10 @@ define([
TextEditorControl.prototype.destroy = function () {
this._detachClientEventListeners();
this._removeToolbarItems();
if (this._territoryId) {
this._client.removeUI(this._territoryId);
}
};
TextEditorControl.prototype._attachClientEventListeners = function () {
@@ -33,6 +33,7 @@ define([
this._params = params;
this._client = params.client;
this._embedded = params.embedded;
this._resizeArgs = null;
//initialize UI
this._initialize();
@@ -49,19 +50,29 @@ define([
};
TilingVizPanel.prototype._initialize = function () {
var panels = this.getPanels();
// Trigger active object
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
(model, nodeId) => this.selectedObjectChanged(nodeId)
);
}
this.$el.css({padding: 0});
this.updatePanels();
};
TilingVizPanel.prototype.updatePanels = function () {
var panels = this.getPanels();
this.logger.info(`updating panels (${panels.length})`);
if (panels.length > 2) {
this.logger.error(`Unsupported number of panels (${panels.length})`);
}
if (this._panels) {
this._panels.forEach(panel => panel.destroy());
this.$el.empty();
}
// Create the panels and containers
this._panels = panels.map(Panel => new Panel(this._layoutManager, this._params));
this._containers = this._panels.map((p, i) => $('<div>', {id: `panel ${i}`}));
@@ -73,10 +84,11 @@ define([
this._containers[i].append(panel.$el) && panel.onDeactivate()
);
this.control = { // For use in dev mode
selectedObjectChanged: this.selectedObjectChanged.bind(this)
};
this.control = this;
this.onActivate();
if (this._resizeArgs) {
this.onResize.apply(this, this._resizeArgs);
}
};
TilingVizPanel.prototype.selectedObjectChanged = function (nodeId) {
@@ -103,6 +115,7 @@ define([
// Call onResize for each of the tiles
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this._panels.forEach(p => p.onResize(pwidth, height));
this._resizeArgs = [width, height];
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
@@ -1,32 +1,96 @@
/*globals define*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 17 2016 11:25:46 GMT-0400 (EDT).
*/
define([
'deepforge/globals',
'widgets/EasyDAG/EasyDAGWidget',
'widgets/EasyDAG/AddNodeDialog',
'./Layer',
'q',
'underscore',
'css!./styles/ArchEditorWidget.css'
], function (
DeepForge,
EasyDAGWidget,
AddNodeDialog,
Layer,
Q,
_
) {
'use strict';
var ArchEditorWidget;
// WIDGET_CLASS = 'arch-editor',
var CREATE_ID = '__NEW_LAYER__',
ArchEditorWidget,
WIDGET_CLASS = 'arch-editor';
ArchEditorWidget = function (logger, container) {
EasyDAGWidget.call(this, logger, container);
this.$el.addClass(WIDGET_CLASS);
};
_.extend(ArchEditorWidget.prototype, EasyDAGWidget.prototype);
ArchEditorWidget.prototype.ItemClass = Layer;
ArchEditorWidget.prototype.onCreateInitialNode = function() {
var nodes = this.getValidInitialNodes();
return this.promptLayer(nodes)
.then(selected => this.createNode(selected.node.id));
};
ArchEditorWidget.prototype.onAddButtonClicked = function(item, reverse) {
var nodes = this.getValidSuccessors(item.id);
return this.promptLayer(nodes)
.then(selected => this.onAddItemSelected(item, selected, reverse));
};
ArchEditorWidget.prototype.promptLayer = function(nodes) {
var deferred = Q.defer(),
types = {},
Decorator = this.getCreateNewDecorator(),
createNews,
opts = {}; // 'create new' nodes
nodes.map(pair => pair.node)
.forEach(node => types[node.layerType] = node.color);
createNews = Object.keys(types).map(type =>
this._creationNode(type, types[type], Decorator));
nodes = nodes.concat(createNews);
// Sort by layer type
opts.tabs = Object.keys(types);
opts.tabFilter = (tab, pair) => {
return pair.node.layerType === tab;
};
AddNodeDialog.prompt(nodes, opts)
.then(selected => {
if (selected.node.id === CREATE_ID) {
DeepForge.create.Layer(selected.node.layerType);
} else {
deferred.resolve(selected);
}
});
return deferred.promise;
};
ArchEditorWidget.prototype._creationNode = function(type, color, Decorator) {
return {
node: {
id: CREATE_ID,
class: 'create-node',
attributes: {},
name: `New ${type} Layer...`,
baseName: `New ${type} Layer...`,
layerType: type,
color: color,
Decorator: Decorator
}
};
};
return ArchEditorWidget;
});
@@ -29,6 +29,7 @@ define([
this.width = this.decorator.width;
this.height = this.decorator.height;
this.initializeTooltips();
// Set up decorator callbacks
this.setupDecoratorCallbacks();
};
@@ -6,11 +6,11 @@
*/
define([
'widgets/TextEditor/TextEditorWidget',
'widgets/SerializeEditor/SerializeEditorWidget',
'underscore',
'css!./styles/DeserializeEditorWidget.css'
], function (
TextEditorWidget,
SerializeEditorWidget,
_
) {
'use strict';
@@ -19,10 +19,10 @@ define([
//WIDGET_CLASS = 'deserialize-editor';
DeserializeEditorWidget = function (logger, container) {
TextEditorWidget.call(this, logger, container);
SerializeEditorWidget.call(this, logger, container);
};
_.extend(DeserializeEditorWidget.prototype, TextEditorWidget.prototype);
_.extend(DeserializeEditorWidget.prototype, SerializeEditorWidget.prototype);
DeserializeEditorWidget.prototype.getHeader = function(desc) {
return [
@@ -34,8 +34,8 @@ define([
].join('\n');
};
DeserializeEditorWidget.prototype.updateNode = function() {
// nop
DeserializeEditorWidget.prototype.getNameRegex = function() {
return /The deserialization function for (.*)/;
};
return DeserializeEditorWidget;
@@ -24,6 +24,7 @@ define([
context: this._widget,
$pEl: this.$selection,
item: this.selectedItem,
icon: 'monitor',
x: width,
y: 0
});
@@ -0,0 +1,137 @@
/*globals define, d3, nv */
/*jshint browser: true*/
define([
'./lib/nv.d3.min',
'css!./lib/nv.d3.min.css'
], function (
) {
'use strict';
var LineGraphWidget,
WIDGET_CLASS = 'line-graph';
LineGraphWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this.lineData = [];
this._initialize();
this._logger.debug('ctor finished');
};
LineGraphWidget.prototype._initialize = function () {
// set widget class
this.$el.addClass(WIDGET_CLASS);
// Create the chart
this.options = {};
this.options.xAxis = null;
this.options.yAxis = null;
this.chart = null;
this.$chart = d3.select(this.$el[0]).append('svg');
nv.addGraph(() => {
var chart = nv.models.lineChart()
//.margin({left: 100})
.useInteractiveGuideline(true)
.showLegend(true)
.showYAxis(true)
.showXAxis(true);
chart.xAxis
.tickFormat(d3.format(',r'));
if (this.options.xAxis) {
chart.xAxis
.axisLabel(this.options.xAxis);
}
if (this.options.yAxis) {
chart.yAxis
.axisLabel(this.options.yAxis);
}
var myData = this.getData();
this.$chart
.datum(myData)
.call(chart);
//Update the chart when window resizes.
nv.utils.windowResize(() => chart.update());
this.chart = chart;
return chart;
});
};
LineGraphWidget.prototype.getData = function () {
return Object.keys(this.lineData).map(id => this.lineData[id]);
};
// Adding/Removing/Updating items
LineGraphWidget.prototype.addNode = function (desc) {
if (desc) {
// Add node to a table of nodes
if (desc.type === 'line') {
this.lineData[desc.id] = {
key: desc.name,
values: desc.points
};
}
this.updateChartData();
}
};
LineGraphWidget.prototype.removeNode = function (id) {
delete this.lineData[id];
this.updateChartData();
};
LineGraphWidget.prototype.updateNode = function (desc) {
if (desc && this.lineData[desc.id]) {
this.lineData[desc.id].values = desc.points;
this.lineData[desc.id].key = desc.name;
this.updateChartData();
}
};
LineGraphWidget.prototype.onWidgetContainerResize = function(width, height) {
this.$el.css({
width: width,
height: height
});
this.updateChart();
};
LineGraphWidget.prototype.updateChartData = function () {
if (this.$chart && this.chart) {
this.$chart
.datum(this.getData())
.call(this.chart);
}
};
LineGraphWidget.prototype.updateChart = function () {
if (this.chart) {
this.chart.update();
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
LineGraphWidget.prototype.destroy = function () {
};
LineGraphWidget.prototype.onActivate = function () {
this._logger.debug('LineGraphWidget has been activated');
};
LineGraphWidget.prototype.onDeactivate = function () {
this._logger.debug('LineGraphWidget has been deactivated');
};
return LineGraphWidget;
});
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -0,0 +1 @@
{"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"AAqBA,oBAfA,oBAgBI,KAAM,KAmXN,gBAAiB,WAhFrB,kBA+DA,uBAnWA,oBAfA,oBAmYI,gBAAiB,WAmErB,UAAW,UAJX,mBAvcA,eAsbA,uBA8BA,uCACI,eAAgB,KA+DpB,WA7QA,aAoRI,QAAS,MAST,sBAAuB,KAEvB,mBAAoB,KAtiBxB,eAEI,QAAS,EAuCb,2BA4JA,0DACI,QAAS,EAjMb,oBAEI,OAAQ,KACR,eAAgB,IAIpB,2BACI,eAAgB,IAGpB,gCACI,eAAgB,EAGpB,oBAEI,OAAQ,QAIZ,0BACI,0BACA,eAAgB,IAGpB,mCACI,YAAa,IAGjB,sCACA,uCACA,uCACI,YAAa,OAOjB,oBACI,aAAc,IAEd,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAG3C,0BACI,aAAc,EAGlB,2BACI,KAAM,QAGV,oBACI,KAAM,YAGV,2BACI,KAAM,cAKV,sCAFA,mCACA,6CAEI,eAAgB,EAEhB,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAK3C,8CACA,4CAHA,yCACA,mDAGI,aAAc,EAGlB,sCACA,6CACI,YAAa,IACb,KAAM,cACN,OAAQ,YAIZ,yBACE,aAAc,GAGhB,+BAIA,6BAHE,aAAc,EAOhB,6BACE,OAAQ,KAGV,uBACE,aAAc,MAGhB,gBAAkB,KAAM,KAAK,WAC7B,4BAA8B,aAAc,GAC5C,kCAAoC,aAAc,EAClD,2BAA6B,OAAQ,KAAM,aAAc,IACzD,mCAAqC,OAAQ,KAAM,KAAM,KAAM,aAAc,MAC7E,+BAAiC,OAAQ,KAAM,aAAc,MAC7D,8BAAgC,OAAQ,KAAM,aAAc,KAC5D,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,0BAA4B,UAAW,KAAM,YAAa,IAC1D,6BAA+B,KAAM,KAGrC,0BACI,KAAM,QACN,aAAc,GAElB,gCACI,aAAc,GAGlB,2CACI,aAAc,IAGlB,iDACI,aAAc,IAGlB,yDACI,OAAQ,QACR,KAAM,QAGV,yDACI,OAAQ,QACR,KAAM,QAGV,wDACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAIxE,uCACI,OAAQ,KAIZ,eACE,OAAQ,KACR,aAAc,MAEhB,eACE,OAAQ,KACR,eAAgB,GAElB,oBACE,aAAc,EAOhB,4BACI,aAAa,EACb,aAAa,EAGjB,8BACI,aAAa,EACb,aAAa,EAGjB,qDACI,aAAa,EACb,eAAe,EAQnB,kCACI,aAAc,IAGlB,wCACI,aAAc,EAElB,8BACI,KAAM,KAGV,8BACI,OAAQ,KAGZ,oDACI,aAAc,EACd,eAAgB,EAGpB,sDACI,aAAc,aACd,eAAgB,aAIpB,6CACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAKxE,iCADA,4CAEI,aAAc,IACd,aAAc,cACd,eAAgB,cAIpB,2BACI,OAAQ,KACR,eAAgB,EAChB,KAAM,KACN,aAAc,EAKlB,oBACI,OAAQ,UAUZ,aAEI,oBAAqB,KAErB,gBAAiB,KACjB,iBAAkB,KAClB,YAAa,KAEb,MAAM,KACN,OAAO,KAMX,0BAA2B,2BACvB,gBAAiB,EAAE,IAAI,KAAK,eAC5B,mBAAoB,EAAE,IAAI,KAAK,eAC/B,WAAY,EAAE,IAAI,KAAK,eAEvB,sBAAuB,IACvB,mBAAoB,IACpB,cAAe,IAInB,WACI,KAAM,IAAO,KAAK,MAGtB,aACI,KAAM,IAAK,KAAK,MAGpB,qBACI,KAAM,KACN,aAAc,EAGlB,gBACI,UAAW,KACX,YAAa,IAQjB,kBACI,aAAc,KAIlB,uBACI,KAAM,KACN,OAAQ,KAQZ,4BACI,OAAQ,QAGZ,qCACI,aAAc,EAIlB,wBACI,aAAc,YAGlB,+BACI,OAAQ,KACR,aAAc,GACd,KAAM,KACN,aAAc,GAOlB,aACE,WACE,aAAc,EACd,aAAc,GAIlB,oCACI,aAAc,IAGlB,0CACI,aAAc,IAGlB,6CACI,OAAQ,QAGZ,6CACI,OAAQ,QAIZ,uBACI,KAAM,KACN,OAAQ,KACR,eAAgB,GAIpB,uBACI,KAAM,KACN,eAAgB,GAGpB,4CAEI,KAAM,KACN,aAAc,GACd,OAAQ,KACR,gBAAiB,WAGrB,qCACI,aAAc,EACjB,aAAc,IAIf,8BACE,KAAM,KACN,OAAQ,KACR,aAAc,EACd,eAAgB,EAChB,iBAAkB,EAAG,EAUvB,2BACI,UAAW,KACX,KAAM,qBAGV,4BACI,OAAQ,KACR,aAAc,EAGlB,kBAhBI,WAAY,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OACvF,gBAAiB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5F,mBAAoB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAe/F,OAAQ,KACR,aAAc,IACd,eAAgB,EAIhB,aAAc,GAElB,yBACI,aAAc,EAKlB,4BACI,aAAc,EACd,eAAgB,EAIpB,iCACI,aAAc,KACd,eAAgB,GAGpB,kCACI,aAAc,EAWlB,wBACI,KAAM,KAOV,2CACI,OAAQ,KACR,aAAc,MAGlB,uBACA,yBACI,eAAgB,IA4LpB,+BAvIA,WAwII,eAAe,KA1LnB,oBACI,aAAc,EACd,eAAgB,EAGpB,kCACA,kCACI,aAAc,EACd,UAAW,KACX,YAAa,IAGjB,kCACI,OAAQ,KAGZ,oCACI,OAAQ,QACR,KAAM,QAGV,oCACI,OAAQ,QACR,KAAM,QAGV,wCACI,YAAa,IACb,UAAW,MAsEf,cAsCA,wBACI,YAAa,IA1GjB,kCACI,aAAc,GACd,eAAgB,EAChB,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAGxE,wCACI,aAAc,GAIlB,0CACI,eAAgB,EAChB,aAAc,EAIlB,WACI,SAAU,SAEV,MAAO,cACP,QAAS,IAET,QAAS,MAGT,YAAa,MACb,UAAW,KACX,WAAY,KAGZ,YAAa,OAGb,oBAAqB,KAErB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAIb,WAAY,qBACZ,OAAQ,IAAI,MAAM,eAClB,cAAe,IAqBnB,cAgBA,aACI,OAAQ,EAER,WAAY,OAlChB,4BAA6B,6BACzB,WAAY,QAAQ,KAAK,OACzB,gBAAiB,QAAQ,KAAK,OAC9B,mBAAoB,QAAQ,KAAK,OAEjC,iBAAkB,MAClB,sBAAuB,MACvB,yBAA0B,MAG9B,uBACA,uBACI,QAAS,IAGb,cAEI,QAAS,IAAI,KACb,YAAa,KAEb,iBAAkB,sBAClB,MAAO,cAGP,cAAe,IAAI,MAAM,QAEzB,sBAAuB,IAAI,IAAI,EAAE,EACjC,mBAAoB,IAAI,IAAI,EAAE,EAC9B,cAAe,IAAI,IAAI,EAAE,EAG7B,aAEI,QAAS,IAAI,KAIjB,gBACI,QAAS,aACT,OAAQ,IAAI,EAGhB,iBACI,OAAQ,IACR,eAAe,EAInB,oBACI,QAAS,IAAI,IAAI,IAAI,EACrB,eAAgB,OAMpB,8BACI,YAAa,IAEjB,0BACI,WAAY,MACZ,YAAa,IAGjB,4BACI,MAAO,QAGX,iCACI,QAAS,IAAI,IAAI,IAAI,EACrB,oBAAqB,MACrB,oBAAqB,IACrB,iBAAkB,MAClB,iBAAkB,IAGtB,2CAGI,eAAgB,OAIhB,MAAO,KACP,OAAQ,KACR,OAAQ,IAAI,MAAM,KAGtB,mBACI,QAAS,IACT,WAAY,OAGhB,2BACI,eAAgB,KAChB,QAAS,KAUb,wBACI,OAAQ"}
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -100,6 +100,17 @@ define([
};
};
LogViewerWidget.prototype.addNode = function (desc) {
var atEOF = this.editor.getLastVisibleRow()+1 ===
this.editor.session.getLength();
TextEditorWidget.prototype.addNode.call(this, desc);
if (atEOF) { // Scroll to bottom
this.editor.gotoLine(Infinity);
}
};
LogViewerWidget.prototype.getEditorOptions = function() {
return {
fontSize: '10pt'
@@ -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,182 @@
/*globals $, WebGMEGlobal,define */
/*jshint browser: true*/
define([
'deepforge/globals',
'text!./NavBar.html',
'text!./ListItem.ejs',
'underscore',
'css!./styles/MainViewWidget.css'
], function (
DeepForge,
NavBarHTML,
ListItem,
_
) {
'use strict';
var MainViewWidget,
WIDGET_CLASS = 'main-view',
CreateListItem = _.template(ListItem);
MainViewWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this.$el.addClass(WIDGET_CLASS);
this.initialize();
this._logger.debug('ctor finished');
};
MainViewWidget.prototype.initialize = function () {
// Create the nav bar
this.$nav = $(NavBarHTML);
this.$el.append(this.$nav);
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 = {};
};
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;
});
+33
Ver Arquivo
@@ -0,0 +1,33 @@
<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">
<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>
@@ -0,0 +1,276 @@
.main-view .side-nav-control {
padding-right: 1em;
padding-top: 1em;
line-height: inherit !important;
}
.main-view .side-nav-control span {
font-size: 16px;
color: #757575;
}
/* closed */
.main-view .side-nav.closed {
width: 40px;
}
.main-view .hide-list ul {
visibility: hidden;
}
.main-view .side-nav {
transform: translateX(0);
transition: width 0.3s;
}
/* closed END */
.main-view .side-nav .action {
font-style: italic;
}
.main-view .side-nav {
background-color: #f5f5f5 !important;
list-style-type: none;
}
.main-view .side-nav a {
color: #444;
display: block;
font-size: 1.5rem;
height: 64px;
line-height: 64px;
padding: 0 30px;
}
.main-view .side-nav li {
text-align: left;
color: #f5f5f5 !important;
}
.main-view .side-nav .sublist ul {
padding-left: 20px;
color: #757575;
}
.main-view .side-nav .sublist a {
font-size: 1.2rem;
}
.main-view ul {
list-style-type: none;
}
.main-view .valign-wrapper {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.main-view .valign-wrapper .valign {
display: block;
}
.main-view ul {
padding: 0;
}
.main-view ul li {
list-style-type: none;
}
.main-view .clearfix {
clear: both;
}
.main-view .z-depth-1,
.main-view nav,
.main-view .card-panel,
.main-view .card,
.main-view .toast,
.main-view .btn,
.main-view .btn-large,
.main-view .btn-floating,
.main-view .dropdown-content,
.main-view .collapsible,
.main-view .side-nav {
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.main-view .side-nav .collapsible,
.main-view .side-nav.fixed .collapsible {
border: none;
box-shadow: none;
}
.main-view .side-nav .collapsible li,
.main-view .side-nav.fixed .collapsible li {
padding: 0;
}
.main-view .side-nav .collapsible-header,
.main-view .side-nav.fixed .collapsible-header {
background-color: transparent;
border: none;
line-height: inherit;
height: inherit;
padding: 0 30px;
}
.main-view .side-nav .collapsible-header:hover,
.main-view .side-nav.fixed .collapsible-header:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.main-view .side-nav .collapsible-header i,
.main-view .side-nav.fixed .collapsible-header i {
line-height: inherit;
}
.main-view .side-nav .collapsible-body,
.main-view .side-nav.fixed .collapsible-body {
border: 0;
background-color: #fff;
}
.main-view .side-nav .collapsible-body li a,
.main-view .side-nav.fixed .collapsible-body li a {
padding: 0 37.5px 0 45px;
}
.main-view .side-nav {
position: fixed;
width: 200px;
left: 0;
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;
}
.main-view .side-nav .collapsible {
margin: 0;
}
.main-view .side-nav li {
float: none;
line-height: 64px;
}
.main-view .side-nav li.active {
background-color: rgba(0, 0, 0, 0.05);
}
.main-view .side-nav a:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.main-view .side-nav a.btn,
.main-view .side-nav a.btn-large,
.main-view .side-nav a.btn-large,
.main-view .side-nav a.btn-flat,
.main-view .side-nav a.btn-floating {
margin: 10px 15px;
}
.main-view .side-nav a.btn,
.main-view .side-nav a.btn-large,
.main-view .side-nav a.btn-large,
.main-view .side-nav a.btn-floating {
color: #fff;
}
.main-view .side-nav a.btn-flat {
color: #343434;
}
.main-view .side-nav a.btn:hover,
.main-view .side-nav a.btn-large:hover,
.main-view .side-nav a.btn-large:hover {
background-color: #2bbbad;
}
.main-view .side-nav a.btn-floating:hover {
background-color: #26a69a;
}
.main-view .drag-target {
height: 100%;
width: 10px;
position: fixed;
top: 0;
z-index: 998;
}
.main-view .side-nav.fixed a {
display: block;
padding: 0 30px;
color: #444;
}
.main-view .side-nav.fixed {
left: 0;
-webkit-transform: translateX(0);
transform: translateX(0);
position: fixed;
}
.main-view .side-nav .collapsible-body li.active,
.main-view .side-nav.fixed .collapsible-body li.active {
background-color: #ee6e73;
}
.main-view .side-nav .collapsible-body li.active a,
.main-view .side-nav.fixed .collapsible-body li.active a {
color: #fff;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
.main-view a:active,
.main-view a:hover {
outline: 0;
}
.main-view a {
background-color: transparent;
color: #039be5;
text-decoration: none;
-webkit-tap-highlight-color: transparent;
}
.main-view .collapsible.popout {
border: none;
box-shadow: none;
}
.main-view .action a {
font-style: italic;
}
@@ -20,6 +20,7 @@ define([
OperationCodeEditorWidget = function (logger, container) {
TextEditorWidget.call(this, logger, container);
this.lineOffset = 0;
};
_.extend(OperationCodeEditorWidget.prototype, TextEditorWidget.prototype);
@@ -30,11 +31,11 @@ define([
refs = desc.references.map(name => `-- ${name}`).join('\n'),
outputs,
header = [
`-- Editing "${desc.name}"`,
'-- '
`-- Editing "${desc.name}" Implementation`
];
if (inputs.length) {
header.push('--');
header.push('-- Defined variables:');
header.push(inputs);
}
@@ -42,6 +43,7 @@ define([
header.push(refs);
}
header.push('--');
header.push('-- The following will be executed when the operation is run:');
// Add info about outputs
outputs = desc.outputs.map(pair => `-- ${pair[0]} = <some ${pair[1]}>`)
@@ -57,5 +59,26 @@ define([
return header.join('\n');
};
OperationCodeEditorWidget.prototype.addNode = function () {
TextEditorWidget.prototype.addNode.apply(this, arguments);
this.updateOffset();
};
OperationCodeEditorWidget.prototype.setLineOffset = function (offset) {
if (this.lineOffset !== offset) {
this.lineOffset = offset;
this.updateOffset();
}
};
OperationCodeEditorWidget.prototype.updateOffset = function () {
var lines,
actualOffset;
lines = this.currentHeader.match(/\n/g);
actualOffset = this.lineOffset - (lines ? lines.length : 0);
this.editor.setOption('firstLineNumber', actualOffset);
};
return OperationCodeEditorWidget;
});
@@ -1,9 +1,13 @@
/*globals define*/
define([
'deepforge/viz/Buttons',
'widgets/EasyDAG/Buttons',
'widgets/EasyDAG/Icons',
'underscore'
], function(
CommonButtons,
EasyDAGButtons,
Icons,
_
) {
@@ -13,14 +17,13 @@ define([
_.extend(AddOutput.prototype, EasyDAGButtons.Add.prototype);
AddOutput.BORDER = 2;
AddOutput.prototype._render = function() {
var lineRadius = EasyDAGButtons.Add.SIZE - EasyDAGButtons.Add.BORDER,
btnColor = '#90caf9',
lineColor = '#7986cb';
var lineRadius = EasyDAGButtons.Add.SIZE - AddOutput.BORDER,
btnColor = '#90caf9';
if (this.disabled) {
btnColor = '#e0e0e0';
lineColor = '#9e9e9e';
}
this.$el
@@ -28,34 +31,7 @@ define([
.attr('r', EasyDAGButtons.Add.SIZE)
.attr('fill', btnColor);
this.$el
.append('line')
.attr('x1', 0)
.attr('x2', 0)
.attr('y1', -lineRadius)
.attr('y2', lineRadius)
.attr('stroke-width', 2)
.attr('stroke', lineColor);
// Arrow
this.$el
.append('line')
.attr('y1', lineRadius)
.attr('y2', 0)
.attr('x1', 0)
.attr('x2', -lineRadius)
.attr('stroke-width', 2)
.attr('stroke', lineColor);
this.$el
.append('line')
.attr('y1', lineRadius)
.attr('y2', 0)
.attr('x1', 0)
.attr('x2', lineRadius)
.attr('stroke-width', 2)
.attr('stroke', lineColor);
Icons.addIcon('chevron-bottom', this.$el, {radius: lineRadius});
};
var AddInput = function(params) {
@@ -80,12 +56,10 @@ define([
AddRef.prototype._render = function() {
var lineRadius = EasyDAGButtons.Add.SIZE - EasyDAGButtons.Add.BORDER,
btnColor = '#81c784',
lineColor = '#7986cb';
btnColor = '#80deea';
if (this.disabled) {
btnColor = '#e0e0e0';
lineColor = '#9e9e9e';
}
this.$el
@@ -93,24 +67,7 @@ define([
.attr('r', EasyDAGButtons.Add.SIZE)
.attr('fill', btnColor);
this.$el
.append('line')
.attr('x1', 0)
.attr('x2', 0)
.attr('y1', -lineRadius)
.attr('y2', lineRadius)
.attr('stroke-width', 2.5)
.attr('stroke', lineColor);
this.$el
.append('line')
.attr('y1', 0)
.attr('y2', 0)
.attr('x1', -lineRadius)
.attr('x2', lineRadius)
.attr('stroke-width', 2.5)
.attr('stroke', lineColor);
Icons.addIcon('plus', this.$el, {radius: lineRadius});
};
var Delete = function(params) {
@@ -132,6 +89,7 @@ define([
AddOutput: AddOutput,
AddInput: AddInput,
AddRef: AddRef,
GoToBase: CommonButtons.GoToBase,
Delete: Delete
};
});
@@ -1,4 +1,4 @@
/*globals define*/
/*globals define */
define([
'widgets/EasyDAG/DAGItem',
'underscore'
@@ -9,10 +9,60 @@ define([
var Item = function(parentEl, desc) {
DAGItem.call(this, parentEl, desc);
// Show the warnings
this.$warning = null;
this.updateWarnings();
};
_.extend(Item.prototype, DAGItem.prototype);
Item.prototype.update = function(desc) {
DAGItem.prototype.update.call(this, desc);
this.updateWarnings();
};
Item.prototype.updateWarnings = function() {
var isInput = this.desc.container === 'inputs',
msg = 'Unused ' + (isInput ? 'Input' : 'Output') + '!';
if (this.desc.used === false) {
this.warn(msg, isInput ? 'bottom' : 'top');
} else {
this.clearWarning();
}
};
Item.prototype.warn = function(message, tipJoint) {
// Create a temporary div over the given svg element
if (this.$warning) {
this.clearWarning();
}
this.decorator.highlight('#ffeb3b');
this.$warning = this.createTooltip(message, {
showIf: () => !this.isSelected(),
tipJoint: tipJoint,
style: 'standard'
});
};
Item.prototype.clearWarning = function() {
if (this.$warning) {
this.destroyTooltip(this.$warning);
this.$warning = null;
}
this.decorator.unHighlight();
};
Item.prototype.onSelect = function() {
DAGItem.prototype.onSelect.call(this);
if (this.$warning) {
this.$warning.hide();
}
};
Item.prototype.setupDecoratorCallbacks = function() {
DAGItem.prototype.setupDecoratorCallbacks.call(this);
// Add ptr name change
@@ -1,11 +1,8 @@
/*globals define */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 31 2016 09:16:24 GMT-0500 (CDT).
*/
define([
'deepforge/globals',
'widgets/EasyDAG/EasyDAGWidget',
'widgets/EasyDAG/AddNodeDialog',
'./SelectionManager',
@@ -13,6 +10,7 @@ define([
'underscore',
'css!./styles/OperationInterfaceEditorWidget.css'
], function (
DeepForge,
EasyDAG,
AddNodeDialog,
SelectionManager,
@@ -22,10 +20,13 @@ define([
'use strict';
var OperationInterfaceEditorWidget,
WIDGET_CLASS = 'operation-interface-editor';
WIDGET_CLASS = 'operation-interface-editor',
NEW_CLASS_ID = '__NEW_CLASS__',
NEW_PRIM_ID = '__NEW_PRIM__';
OperationInterfaceEditorWidget = function (logger, container) {
EasyDAG.call(this, logger, container);
this.$el.addClass(WIDGET_CLASS);
};
_.extend(OperationInterfaceEditorWidget.prototype, EasyDAG.prototype);
@@ -44,23 +45,31 @@ define([
};
OperationInterfaceEditorWidget.prototype.onAddButtonClicked = function(item, isInput) {
var successorPairs = this.getValidSuccessorNodes(item.id),
successor = successorPairs[0];
var successorPairs = this.getValidSuccessors(item.id, isInput),
newClass = this.getCreationNode('Complex', NEW_CLASS_ID),
newPrim = this.getCreationNode('Primitive', NEW_PRIM_ID),
opts = {};
if (successorPairs.length > 1) {
// Create the modal view with all possible subsequent nodes
var dialog = new AddNodeDialog(),
title = this._getAddSuccessorTitle(item);
// Add the 'Create Class' node
successorPairs.push(newClass);
successorPairs.push(newPrim);
dialog.show(title, successorPairs);
dialog.onSelect = pair => {
if (pair) {
this.onAddItemSelected(pair, isInput);
// Add tabs
opts.tabs = ['Primitive', 'Classes'];
opts.tabFilter = (tab, pair) => {
return pair.node.isPrimitive === (tab === 'Primitive');
};
AddNodeDialog.prompt(successorPairs, opts)
.then(selected => {
if (selected.node.id === NEW_CLASS_ID) {
DeepForge.create.Complex();
} else if (selected.node.id === NEW_PRIM_ID) {
DeepForge.create.Primitive();
} else {
this.onAddItemSelected(selected, isInput);
}
};
} else if (successor) {
this.onAddItemSelected(successor, isInput);
}
});
};
OperationInterfaceEditorWidget.prototype.onDeactivate = function() {
@@ -53,7 +53,7 @@ define([
x: 2*width/3,
y: 0
});
} else { // Data...
} else { // Data or pointer...
new Buttons.Delete({
context: this._widget,
$pEl: this.$selection,
@@ -61,6 +61,16 @@ define([
x: cx,
y: 0
});
if (!this.selectedItem.desc.isPointer) {
new Buttons.GoToBase({
context: this._widget,
$pEl: this.$selection,
item: this.selectedItem,
x: width,
y: 0
});
}
}
};
@@ -1,82 +0,0 @@
/*globals define, WebGMEGlobal*/
define([
'widgets/EasyDAG/Buttons'
], function(
EasyDAGButtons
) {
// Create a GoToBase button
var client = WebGMEGlobal.Client,
LocalOps = {
ArtifactLoader: true,
Save: true
};
var GoToBase = function(params) {
// Check if it should be disabled
var baseId = this._getBaseId(params.item),
base = client.getNode(baseId);
params.disabled = base ? base.isLibraryElement() : false;
EasyDAGButtons.ButtonBase.call(this, params);
};
GoToBase.SIZE = 10;
GoToBase.BORDER = 5;
GoToBase.prototype.BTN_CLASS = 'add';
GoToBase.prototype = new EasyDAGButtons.ButtonBase();
GoToBase.prototype._render = function() {
var lineRadius = GoToBase.SIZE - GoToBase.BORDER,
btnColor = '#90caf9',
lineColor = '#7986cb';
if (this.disabled) {
btnColor = '#e0e0e0';
lineColor = '#9e9e9e';
}
this.$el
.append('circle')
.attr('r', GoToBase.SIZE)
.attr('fill', btnColor);
this.$el
.append('circle')
//.attr('cx', -)
//.attr('cy', 0)
.attr('r', GoToBase.SIZE/3)
.attr('stroke-width', 3)
.attr('stroke', lineColor);
this.$el
.append('line')
.attr('y1', 0)
.attr('y2', 0)
.attr('x1', -lineRadius)
.attr('x2', lineRadius)
.attr('stroke-width', 3)
.attr('stroke', lineColor);
};
GoToBase.prototype._onClick = function(item) {
var node = client.getNode(item.id),
baseId = node.getBaseId();
window.DeepForge = window.DeepForge || {};
window.DeepForge.lastPipeline = item.desc.parentId;
WebGMEGlobal.State.registerActiveObject(baseId);
};
GoToBase.prototype._getBaseId = function(item) {
var n = client.getNode(item.id);
return n.getBaseId();
};
return {
DeleteOne: EasyDAGButtons.DeleteOne,
GoToBase: GoToBase
};
});
@@ -6,16 +6,20 @@
*/
define([
'widgets/EasyDAG/AddNodeDialog',
'widgets/EasyDAG/EasyDAGWidget',
'deepforge/viz/PipelineControl',
'deepforge/globals',
'./OperationNode',
'./Connection',
'./SelectionManager',
'underscore',
'css!./styles/PipelineEditorWidget.css'
], function (
AddNodeDialog,
EasyDAGWidget,
PipelineControl,
DeepForge,
OperationNode,
Connection,
SelectionManager,
@@ -31,6 +35,7 @@ define([
DEFAULT: 'default',
CONNECTING: 'connecting'
},
UPLOAD_ARTIFACT_ID = '__UPLOAD_ARTIFACT__',
STATUS_TO_CLASS = {
running: 'warning',
success: 'success',
@@ -85,6 +90,7 @@ define([
// Update the given port...
dstItem.refreshPorts();
}
this.refreshThumbnail();
};
PipelineEditorWidget.prototype.addNode = function(desc) {
@@ -104,6 +110,7 @@ define([
this.PORT_STATE = STATE.DEFAULT;
this.connectPort.apply(this, this.srcPortToConnectArgs);
}
this.refreshThumbnail();
};
PipelineEditorWidget.prototype._removeConnection = function(id) {
@@ -118,6 +125,7 @@ define([
dst.refreshPorts();
}
EasyDAGWidget.prototype._removeConnection.call(this, id);
this.refreshThumbnail();
};
// May not actually need these port methods
@@ -137,6 +145,7 @@ define([
this.removePort(gmeId);
} else {
EasyDAGWidget.prototype.removeNode.call(this, gmeId);
this.refreshThumbnail();
}
};
@@ -338,5 +347,91 @@ define([
this.updateExecutions();
};
////////////////////////// Action Overrides //////////////////////////
PipelineEditorWidget.prototype.selectTargetFor = function(itemId) {
// If it is an 'ArtifactLoader', then we will need to add 'upload artifact'
// options
if (this.items[itemId].desc.baseName === 'ArtifactLoader') {
this.selectTargetForLoader.apply(this, arguments);
} else {
return EasyDAGWidget.prototype.selectTargetFor.apply(this, arguments);
}
};
PipelineEditorWidget.prototype.selectTargetForLoader = function(itemId, ptr, filter) {
var validTargets = this.getValidTargetsFor(itemId, ptr, filter),
nodeId = validTargets.length ? validTargets[0].node.id : null,
uploadNode;
// Add the 'Upload Artifact' option
uploadNode = {
node: {
id: UPLOAD_ARTIFACT_ID,
name: 'Upload Artifact',
class: 'create-node',
attributes: {},
Decorator: this.getDecorator(nodeId)
}
};
validTargets.push(uploadNode);
AddNodeDialog.prompt(validTargets)
.then(selected => {
if (selected.node.id === UPLOAD_ARTIFACT_ID) {
DeepForge.create.Artifact();
} else {
var item = this.items[itemId];
if (item.decorator.savePointer) {
return item.decorator.savePointer(ptr, selected.node.id);
} else {
this.setPointerForNode(itemId, ptr, selected.node.id);
}
}
});
};
////////////////////////// Action Overrides END //////////////////////////
////////////////////////// Thumbnail updates //////////////////////////
PipelineEditorWidget.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;
};
PipelineEditorWidget.prototype.getSvgWidth = function() {
return this.getSvgDistanceDim('x');
};
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