Skip to content

Commit

Permalink
Merge pull request #1195 from briehl/spec-editor
Browse files Browse the repository at this point in the history
TASK-1201 - Simple viewer for App Spec files
  • Loading branch information
briehl committed Jan 24, 2018
2 parents 124b863 + 458789e commit 73621a0
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 47 deletions.
79 changes: 43 additions & 36 deletions nbextensions/appCell2/appCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ define([
if (!cell.metadata.kbase) {
return false;
}
if (cell.metadata.kbase.type === 'app2' || cell.metadata.kbase.type === 'app') {
if (cell.metadata.kbase.type === 'app2' ||
cell.metadata.kbase.type === 'app' ||
cell.metadata.kbase.type === 'devapp') {
return true;
}
return false;
Expand Down Expand Up @@ -228,48 +230,53 @@ define([
});
}

function upgradeToAppCell(appSpec, appTag) {
/**
* appSpec = the appSpec structure
* appTag = a string, one of 'release', 'beta', 'dev'
* appType = a string, typically 'app', also 'devapp' for spec edit mode.
*/
function upgradeToAppCell(appSpec, appTag, appType) {
return Promise.try(function() {
// Create base app cell
// Create base app cell

// TODO: this should capture the entire app spec, so don't need
// to carry appSpec around.
spec = Spec.make({
appSpec: appSpec
});
// TODO: this should capture the entire app spec, so don't need
// to carry appSpec around.
spec = Spec.make({
appSpec: appSpec
});

var meta = {
kbase: {
type: 'app',
attributes: {
id: new Uuid(4).format(),
status: 'new',
created: (new Date()).toUTCString()
var meta = {
kbase: {
type: appType,
attributes: {
id: new Uuid(4).format(),
status: 'new',
created: (new Date()).toUTCString()
},
appCell: {
app: {
id: appSpec.info.id,
gitCommitHash: appSpec.info.git_commit_hash,
version: appSpec.info.ver,
tag: appTag,
// TODO: remove the spec from the cell metadata
spec: appSpec
},
appCell: {
app: {
id: appSpec.info.id,
gitCommitHash: appSpec.info.git_commit_hash,
version: appSpec.info.ver,
tag: appTag,
// TODO: remove the spec from the cell metadata
spec: appSpec
},
params: null,
output: {
byJob: {}
}
params: null,
output: {
byJob: {}
}
}
};
cell.metadata = meta;
}
};
cell.metadata = meta;

// Add the params
utils.setCellMeta(cell, 'kbase.appCell.params', spec.makeDefaultedModel());
// initializeParams(appSpec);
// Complete the cell setup.
return setupCell();
})
// Add the params
utils.setCellMeta(cell, 'kbase.appCell.params', spec.makeDefaultedModel());
// initializeParams(appSpec);
// Complete the cell setup.
return setupCell();
})
.then(function(cellStuff) {
// Initialize the cell to its default state.
// cellStuff.bus.emit('reset-to-defaults');
Expand Down
14 changes: 9 additions & 5 deletions nbextensions/appCell2/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,22 @@ define([
var setupData = payload.data;
var jupyterCellType = payload.type;

if (setupData.type === 'app2') {
setupData.type = 'app';
}

if (jupyterCellType !== 'code' ||
!setupData ||
!(setupData.type === 'app2' ||
setupData.type === 'app')) {
!setupData ||
!(setupData.type === 'app' ||
setupData.type === 'devapp')) {
return;
}

var appCell = AppCell.make({
cell: cell,
workspaceInfo: workspaceInfo
});
appCell.upgradeToAppCell(setupData.appSpec, setupData.appTag)
appCell.upgradeToAppCell(setupData.appSpec, setupData.appTag, setupData.type)
.catch(function(err) {
console.error('ERROR creating cell', err);
Jupyter.notebook.delete_cell(Jupyter.notebook.find_cell_index(cell));
Expand Down Expand Up @@ -218,4 +222,4 @@ define([
};
}, function(err) {
console.error('ERROR loading appCell main', err);
});
});
17 changes: 11 additions & 6 deletions nbextensions/appCell2/widgets/appCellWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -2613,15 +2613,20 @@ define([
// If the app has been run before...
// The app reference is already in the app cell metadata.
return Promise.try(function() {
if (utils.getCellMeta(cell, 'kbase.type') !== 'devapp') {
return getAppSpec();
})
}
return {};
})
.then(function(appSpec) {
// Ensure that the current app spec matches our existing one.
var warning = checkSpec(appSpec);
if (warning && warning.severity === 'warning') {
if (warning.type === 'app-spec-mismatched-commit') {
model.setItem('outdated', true);
model.setItem('newAppName', warning.info.newAppName);
if (appSpec && utils.getCellMeta(cell, 'kbase.type') !== 'devapp') {
var warning = checkSpec(appSpec);
if (warning && warning.severity === 'warning') {
if (warning.type === 'app-spec-mismatched-commit') {
model.setItem('outdated', true);
model.setItem('newAppName', warning.info.newAppName);
}
}
}

Expand Down
46 changes: 46 additions & 0 deletions src/biokbase/narrative/appeditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from IPython.display import Javascript
from jinja2 import Template
from biokbase.narrative import clients
import json


def generate_app_cell(validated_spec=None, spec_tuple=None):
"""Produces an invisible blob of JavaScript that inserts a new cell in the notebook,
and crams the validated_spec in it. It then removes itself, so it won't happen again
on page reload.
For the inputs, validated_spec > spec_tuple. That is, if validated_spec is present,
that's always used. if spec_tuple is there, and validated_spec is not, then the
tuple's used.
Also, the tuple should be (spec_json, display_yaml), all as strings.
"""

if spec_tuple is not None and validated_spec is None:
nms = clients.get("narrative_method_store")
validated = nms.validate_method({
"id": "some_test_app",
"spec_json": spec_tuple[0],
"display_yaml": spec_tuple[1]
})
if validated.get('is_valid', 0) == 1:
validated_spec = validated['method_spec']
elif "errors" in validated and validated['errors']:
raise Exception(validated['errors'])

js_template = """
var outputArea = this,
cellElement = outputArea.element.parents('.cell'),
cellIdx = Jupyter.notebook.get_cell_elements().index(cellElement),
thisCell = Jupyter.notebook.get_cell(cellIdx),
spec_json = '{{spec}}',
cellData = {
type: 'devapp',
appTag: 'dev',
appSpec: JSON.parse(spec_json)
};
Jupyter.narrative.insertAndSelectCell('code', 'below', cellIdx, cellData);
"""
js_code = Template(js_template).render(spec=json.dumps(validated_spec))

return Javascript(data=js_code, lib=None, css=None)
36 changes: 36 additions & 0 deletions src/biokbase/narrative/tests/data/simple_display.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#
# define display information
#
name: Test Simple Inputs
tooltip: |
A simple test spec with a single input.
screenshots: []

icon: icon.png

#
# define a set of similar methods that might be useful to the user
#
suggestions:
apps:
related:
[]
next:
[]
methods:
related:
[]
next:
[]

#
# Configure the display and description of parameters
#
parameters :
simple_string :
ui-name : |
A String
short-hint : |
A description string.
description : |
<p>This is a tiny, simple method intended for testing the Narrative's ability to parse and display specs.</p>
46 changes: 46 additions & 0 deletions src/biokbase/narrative/tests/data/simple_spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"ver": "0.0.1",
"authors": [
"wjriehl"
],
"contact": "help@kbase.us",
"visible": true,
"categories": ["active"],
"app_type": "editor",
"widgets": {
"input": null,
"output": null
},
"parameters": [
{
"id": "simple_string",
"optional": false,
"advanced": false,
"allow_multiple": false,
"default_values": [ "" ],
"field_type": "text",
"text_options": {
}
}
],
"behavior": {
"service-mapping": {
"url": "",
"name": "NarrativeTest",
"method": "generic_test",
"input_mapping": [
{
"input_parameter": "simple_string",
"target_property": "simple_string"
}
],
"output_mapping": [
{
"service_method_output_path": [0,"simple_string"],
"target_property": "simple_string"
}
]
}
},
"job_id_output_field": "docker"
}
2 changes: 2 additions & 0 deletions src/biokbase/narrative/tests/test.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ job_info_file=data/job_test_data.json
[specs]
app_specs_file=data/app_specs.json
type_specs_file=data/type_specs.json
simple_spec_json=data/simple_spec.json
simple_display_yaml=data/simple_display.yaml

[app_tests]
public_ws_name=wjriehl:1475006266615
Expand Down
32 changes: 32 additions & 0 deletions src/biokbase/narrative/tests/test_appeditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Some tests for the App Editor module.
"""
import unittest
from biokbase.narrative.appeditor import (
generate_app_cell
)
import json
from util import TestConfig


class AppEditorTestCase(unittest.TestCase):
@classmethod
def setUpClass(self):
config = TestConfig()
self.specs_list = config.load_json_file(config.get('specs', 'app_specs_file'))
self.spec_json = config.load_json_file(config.get('specs', 'simple_spec_json'))
with open(config.file_path(config.get('specs', 'simple_display_yaml'))) as f:
self.display_yaml = f.read()
f.close()

def test_gen_app_cell_post_validation(self):
js = generate_app_cell(validated_spec=self.specs_list[0])
self.assertIsNotNone(js)

def test_gen_app_cell_pre_valid(self):
js = generate_app_cell(spec_tuple=(json.dumps(self.spec_json), self.display_yaml))
self.assertIsNotNone(js)

def test_gen_app_cell_fail_validation(self):
with self.assertRaises(Exception):
generate_app_cell(spec_tuple=("{}", self.display_yaml))

0 comments on commit 73621a0

Please sign in to comment.