Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
8ad9142
WIP Add initial commit of DatasetExplorer
brollb May 5, 2020
ae337e6
WIP use artifact name in DataExplorer
brollb May 5, 2020
a164ce2
WIP Add plot editor to dataset explorer
brollb May 7, 2020
277608b
WIP add PlotEditor and css
brollb May 7, 2020
7fe251d
Add UI elements for adding/removing data
brollb May 8, 2020
00e7694
Fix UI issue with editing plotted data
brollb May 8, 2020
9792e13
WIP Add utility for parsing python slices
brollb May 11, 2020
7ef7b6d
Add slice string validation
brollb May 11, 2020
6b39f9b
UI support for validating data slice
brollb May 11, 2020
5a2bb74
Update figure updates given the figure data
brollb May 11, 2020
6be4a6f
Add explorer_helpers.py for DatasetExplorer
brollb May 11, 2020
1c5eb58
Add explorer helpers to session for getting metadata
brollb May 11, 2020
1d1e42a
dynamically create variable names for dropdown
brollb May 11, 2020
6426b71
Add tests for variable name creation from metadata
brollb May 11, 2020
a220061
Plot actual data selected from "Add Data" button
brollb May 11, 2020
831c158
Fix plot height
brollb May 12, 2020
cedad0f
Add basic 3D plot support to DataExplorer
brollb May 12, 2020
e12232f
Fix async issue with multiple lines
brollb May 12, 2020
5bdf1da
Fix x-axis, y-axis labels
brollb May 12, 2020
954212f
Add validation for plotting data
brollb May 12, 2020
96bb01f
Remove .only from PythonSlice test suite
brollb May 12, 2020
61a7e27
Add basic artifact loader to DatasetExplorer
brollb May 12, 2020
5a0ae54
Only show artifacts with data in artifact loader
brollb May 12, 2020
af549f5
Update metadata on artifact load into session
brollb May 12, 2020
15546b9
Removed hardcoded examples from html
brollb May 12, 2020
d434d01
Add some support for colors (uniform only)
brollb May 12, 2020
5bc0cf3
Add color support for individual points
brollb May 12, 2020
6a31f58
Fix selection of keys from artifacts
brollb May 13, 2020
77cfd2f
WIP Use session with queue in dataset explorer
brollb May 13, 2020
c968fc9
WIP code cleanup dataset explorer
brollb May 13, 2020
73a18b9
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb May 14, 2020
d1ad052
Add compute creation (and shield) for DatasetExplorer
brollb May 14, 2020
5f45c75
Don't show slice syntax errors until change event
brollb May 14, 2020
c870763
Fix artifacts with extensions. minor code cleanup
brollb Jun 16, 2020
d1cc2e0
Increase territory for access to initialization code
brollb Jun 16, 2020
6f33b3e
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb Jun 20, 2020
7065d4f
Rename DatasetVisualizer -> TensorPlotter
brollb Jun 22, 2020
4b7c1c1
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb Jul 1, 2020
365677c
Rename scss,css files
brollb Jul 2, 2020
d749c42
Add "save" action to floating action button
brollb Jul 2, 2020
38cfe75
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb Jul 2, 2020
84bc27e
Only load jscolor in the browser
brollb Jul 2, 2020
44cf5da
Skip jscolor library when linting
brollb Jul 2, 2020
226d627
Add InteractiveEditor base class
brollb Jul 3, 2020
cb741a3
Update to use InteractiveEditor base classes
brollb Jul 3, 2020
8abafef
Add getSnapshot to tensor plotter
brollb Jul 6, 2020
1fd7044
Fix setting the data dialog on open
brollb Jul 7, 2020
67ea9ee
WIP working on operation code...
brollb Jul 8, 2020
d554a91
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb Jul 9, 2020
827d49b
Include all artifacts in TensorPlotter
brollb Jul 9, 2020
650697d
Fixed python slice parsing
brollb Jul 9, 2020
196eb67
Merge branch 'master' into 1692-interactive-dataset-exploration
brollb Jul 9, 2020
cf66703
Add InteractiveExplorer base class
brollb Jul 9, 2020
b67e85d
Use inform dialog w/ auth errors
brollb Jul 9, 2020
1fc5bb7
Update TensorPlotter to inherit from InteractiveExplorer
brollb Jul 15, 2020
806578e
fix css linting issue
brollb Jul 15, 2020
249eb4f
Remove TensorPlotter
brollb Jul 15, 2020
c33b6bc
Remove tensor plotter from registries
brollb Jul 15, 2020
043919e
Remove more tensorplotter things
brollb Jul 15, 2020
f8cd0d9
Remove TensorPlotter tests
brollb Jul 15, 2020
96b189f
Remove old comments and minor fixes
brollb Jul 15, 2020
fed1819
remove old comment
brollb Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 218 additions & 0 deletions src/visualizers/panels/InteractiveEditor/InteractiveEditorControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*globals define, WebGMEGlobal*/

define([
'deepforge/viz/ConfigDialog',
'js/Constants',
], function (
ConfigDialog,
CONSTANTS,
) {

'use strict';

class InteractiveEditorControl {
constructor(options) {
this._logger = options.logger.fork('Control');
this.client = options.client;
this._embedded = options.embedded;
this._widget = options.widget;
this.initializeWidgetHandlers(this._widget);
this.territoryEventFilters = [];

this._currentNodeId = null;

this._logger.debug('ctor finished');
}

initializeWidgetHandlers (widget) {
const features = widget.getCapabilities();
if (features.save) {
widget.save = () => this.save();
}
widget.getConfigDialog = () => new ConfigDialog(this.client);
}

selectedObjectChanged (nodeId) {
const desc = this.getObjectDescriptor(nodeId);

this._logger.debug('activeObject nodeId \'' + nodeId + '\'');

if (this._currentNodeId) {
this.client.removeUI(this._territoryId);
}

this._currentNodeId = nodeId;

if (typeof this._currentNodeId === 'string') {
const territory = this.getTerritory(nodeId);
this._widget.setTitle(desc.name.toUpperCase());

this._territoryId = this.client
.addUI(this, events => this._eventCallback(events));

this.client.updateTerritory(this._territoryId, territory);
}
}

getTerritory(nodeId) {
const territory = {};
territory[nodeId] = {children: 0};
return territory;
}

getMetaNode(name) {
const metanodes = this.client.getAllMetaNodes();
return metanodes
.find(node => {
const namespace = node.getNamespace();
const fullName = namespace ? namespace + '.' + node.getAttribute('name') :
node.getAttribute('name');

return fullName === name;
});
}

createNode(desc, parentId) {
if (!parentId) {
parentId = this._currentNodeId;
}
desc.pointers = desc.pointers || {};
desc.attributes = desc.attributes || {};

const base = this.getMetaNode(desc.type) || this.client.getNode(desc.pointers.base);
const nodeId = this.client.createNode({
parentId: parentId,
baseId: base.getId()
});

const attributes = Object.entries(desc.attributes);
attributes.forEach(entry => {
const [name, value] = entry;
this.client.setAttribute(nodeId, name, value);
});

const pointers = Object.entries(desc.pointers);
pointers.forEach(entry => {
const [name, id] = entry;
this.client.setPointer(nodeId, name, id);
});

return nodeId;
}

save() {
this.client.startTransaction();
const dataId = this.createNode(this._widget.getSnapshot());
const implicitOpId = this.createNode(this._widget.getEditorState(), dataId);
this.client.setPointer(dataId, 'provenance', implicitOpId);
const operationId = this.createNode(this._widget.getOperation(), implicitOpId);
this.client.setPointer(implicitOpId, 'operation', operationId);
this.client.completeTransaction();
}

getObjectDescriptor (nodeId) {
const node = this.client.getNode(nodeId);

if (node) {
return {
id: node.getId(),
name: node.getAttribute('name'),
childrenIds: node.getChildrenIds(),
parentId: node.getParentId(),
};
}
}

/* * * * * * * * Node Event Handling * * * * * * * */
_eventCallback (events=[]) {
this._logger.debug('_eventCallback \'' + events.length + '\' items');

events
.filter(event => this.isRelevantEvent(event))
.forEach(event => {
switch (event.etype) {

case CONSTANTS.TERRITORY_EVENT_LOAD:
this.onNodeLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this.onNodeUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this.onNodeUnload(event.eid);
break;
default:
break;
}
});

this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
}

onNodeLoad (gmeId) {
const description = this.getObjectDescriptor(gmeId);
this._widget.addNode(description);
}

onNodeUpdate (gmeId) {
const description = this.getObjectDescriptor(gmeId);
this._widget.updateNode(description);
}

onNodeUnload (gmeId) {
this._widget.removeNode(gmeId);
}

isRelevantEvent (event) {
return this.territoryEventFilters
.reduce((keep, fn) => keep && fn(event), true);
}

_stateActiveObjectChanged (model, activeObjectId) {
if (this._currentNodeId === activeObjectId) {
// The same node selected as before - do not trigger
} else {
this.selectedObjectChanged(activeObjectId);
}
}

/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
destroy () {
this._detachClientEventListeners();
}

_attachClientEventListeners () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on(
'change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged,
this
);
}
}

_detachClientEventListeners () {
if (!this._embedded) {
WebGMEGlobal.State.off(
'change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged
);
}
}

onActivate () {
this._attachClientEventListeners();

if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerActiveObject(this._currentNodeId, {suppressVisualizerFromNode: true});
}
}

onDeactivate () {
this._detachClientEventListeners();
}
}

return InteractiveEditorControl;
});
97 changes: 97 additions & 0 deletions src/visualizers/panels/InteractiveEditor/InteractiveEditorPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*globals define, _, WebGMEGlobal*/

define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/InteractiveEditor/InteractiveEditorWidget',
'./InteractiveEditorControl'
], function (
PanelBaseWithHeader,
IActivePanel,
InteractiveEditorWidget,
InteractiveEditorControl
) {
'use strict';

function InteractiveEditorPanel(layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'InteractiveEditorPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;

//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);

this._client = params.client;
this._embedded = params.embedded;

this.initialize();

this.logger.debug('ctor finished');
}

//inherit from PanelBaseWithHeader
_.extend(InteractiveEditorPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(InteractiveEditorPanel.prototype, IActivePanel.prototype);

InteractiveEditorPanel.prototype.initialize = function () {
var self = this;

//set Widget title
this.setTitle('');

this.widget = new InteractiveEditorWidget(this.logger, this.$el);

this.widget.setTitle = function (title) {
self.setTitle(title);
};

this.control = new InteractiveEditorControl({
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 */
InteractiveEditorPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);

};

InteractiveEditorPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};

/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
InteractiveEditorPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();

PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};

InteractiveEditorPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};

InteractiveEditorPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};

return InteractiveEditorPanel;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*globals define */

define([
'panels/InteractiveEditor/InteractiveEditorControl',
], function (
InteractiveEditorControl,
) {

'use strict';

class InteractiveExplorerControl extends InteractiveEditorControl {
ensureValidSnapshot(desc) {
const metadata = this.getMetaNode('pipeline.Metadata');
const type = this.getMetaNode(desc.type);

if (!type) {
throw new Error(`Invalid metadata type: ${type}`);
}

if (!type.isTypeOf(metadata.getId())) {
throw new Error('Explorer can only create artifact metadata');
}
}

save() {
const snapshotDesc = this._widget.getSnapshot();
this.ensureValidSnapshot(snapshotDesc);

const features = this._widget.getCapabilities();
this.client.startTransaction();
const data = this.createNode(snapshotDesc);
if (features.provenance) {
const implicitOp = this.createNode(this._widget.getEditorState(), data);
this.client.setPointer(data.getId(), 'provenance', implicitOp.getId());
const operation = this.createNode(this._widget.getOperation(), implicitOp);
this.client.setPointer(implicitOp.getId(), 'operation', operation.getId());
}
this.client.completeTransaction();
}

}

return InteractiveExplorerControl;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*globals define */

define([
'panels/InteractiveEditor/InteractiveEditorPanel',
'widgets/InteractiveExplorer/InteractiveExplorerWidget',
'./InteractiveExplorerControl',
], function (
InteractiveEditorPanel,
InteractiveExplorerWidget,
InteractiveExplorerControl,
) {
'use strict';

class InteractiveExplorerPanel extends InteractiveEditorPanel {

initialize() {
this.setTitle('');
this.widget = new InteractiveExplorerWidget(this.logger, this.$el);
this.widget.setTitle = title => this.setTitle(title);

this.control = new InteractiveExplorerControl({
logger: this.logger,
client: this._client,
embedded: this._embedded,
widget: this.widget
});

this.onActivate();
}
}

return InteractiveExplorerPanel;
});
Loading