From 93b6ea14bd869b42f4b9b8eb516567ead3b24ad5 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 13 Oct 2020 15:11:23 -0400 Subject: [PATCH 01/24] Fixed bug that was displaying the 'Hide/Show Preview' button while the preview was running. Fixed bug the was showing the 'Show Preview' button when a new preview plot was shown. Fixed bug that was allowing the left hand menu link scopes to extend beyond the link text. --- client/styles/styles.css | 2 +- client/templates/body.pug | 16 ++++++++-------- client/views/model-state-buttons.js | 7 ++++++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/client/styles/styles.css b/client/styles/styles.css index 4e4c0d3505..76e99960ac 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -83,7 +83,7 @@ a.disabled { } .nav-item { - display: inline-block; + width: fit-content; } .nav-link { diff --git a/client/templates/body.pug b/client/templates/body.pug index 206fa084af..a31aa17c0f 100644 --- a/client/templates/body.pug +++ b/client/templates/body.pug @@ -39,16 +39,16 @@ body li.nav-item: a.nav-link(href="stochss/home", title="Users Home Page") | Home - li.nav-item: a.nav-link(href="stochss/project/browser", title="Explore your StochSS projects") - | Projects + li.nav-item + div: a.nav-link(href="stochss/project/browser", title="Explore your StochSS projects") Projects - li.nav-item: a.nav-link(href="stochss/files", title="Explore your StochSS files") - | Files + li.nav-item + div: a.nav-link(href="stochss/files", title="Explore your StochSS files") Files - li.nav-item: a.nav-link(target="_blank", href="tree", title="Browse your files in a Jupyter interface") - | Jupyter + li.nav-item + div: a.nav-link(target="_blank", href="tree", title="Browse your files in a Jupyter interface") Jupyter - li.nav-item: a.nav-link(href="stochss/quickstart", title="Quickstart") - | Tutorial + li.nav-item + div: a.nav-link(href="stochss/quickstart", title="Quickstart") Tutorial main.col-md-10.body(role="main"): div.container-fluid(data-hook="page-container") diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 5f886c2b6b..7674373707 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -58,6 +58,7 @@ module.exports = View.extend({ $(this.parent.queryByHook('model-timeout-message')).collapse('hide'); var el = this.parent.queryByHook('model-run-container'); Plotly.purge(el) + $(this.parent.queryByHook('toggle-preview-plot')).css("display", "none"); this.saveModel(this.runModel.bind(this)); }, clickReturnToProjectHandler: function (e) { @@ -185,7 +186,11 @@ module.exports = View.extend({ el = this.parent.queryByHook('model-run-container'); Plotly.newPlot(el, data); $(this.parent.queryByHook('toggle-preview-plot-container')).css('height', '50px') - $(this.parent.queryByHook('toggle-preview-plot')).css('display', 'block') + let plotBtn = $(this.parent.queryByHook('toggle-preview-plot')) + plotBtn.css('display', 'block') + if(plotBtn.text() === "Show Preview") { + plotBtn.text("Hide Preview") + } window.scrollTo(0, document.body.scrollHeight) }, }); From be09e8dd9535a178e4ca2827c9f9d20159233c94 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 13 Oct 2020 16:43:43 -0400 Subject: [PATCH 02/24] Fixed bug that was incorrectly referencing the workflow group when adding an existing workflow to a project. Refactored the add existing workflow modal to use a select template instead of an input template. Added a xhr request to get the list of viable workflow that can be added. Modified the root filter check to exclude any items with the path in the root instead of just the one with the root == path for both the add existing model and workflow get requests. Added check that only adds the workflow/model file name to the workflows/models list if it was found in '/home/jovyan'. --- client/modals.js | 11 +++--- .../templates/includes/editWorkflowsView.pug | 4 +-- client/views/edit-workflows-view.js | 35 ++++++------------- client/views/file-browser-view.js | 31 +++++----------- stochss/handlers/project.py | 18 +++++----- 5 files changed, 39 insertions(+), 60 deletions(-) diff --git a/client/modals.js b/client/modals.js index 3499e0147a..430559a9a4 100644 --- a/client/modals.js +++ b/client/modals.js @@ -248,14 +248,17 @@ module.exports = { return templates.select(modalID, selectID, title, label, options) }, - addExistingWorkflowToProjectHtml : () => { + addExistingWorkflowToProjectHtml : (options) => { let modalID = "newProjectWorkflowModal" - let inputID = "workflowPathInput" + let selectID = "workflowPathInput" let title = "Add Existing Workflow to Workflow Group" let label = "Path to the workflow" - let value = "" + options = options.map(function (name) { + return `` + }) + options = options.join(" ") - return templates.input(modalID, inputID, title, label, value) + return templates.select(modalID, selectID, title, label, options) }, addExistingWorkflowToProjectSuccessHtml : (message) => { let modalID = "newProjectModelSuccessModal" diff --git a/client/templates/includes/editWorkflowsView.pug b/client/templates/includes/editWorkflowsView.pug index 1f39e028f4..a7cd96aa58 100644 --- a/client/templates/includes/editWorkflowsView.pug +++ b/client/templates/includes/editWorkflowsView.pug @@ -17,7 +17,7 @@ div#edit-project-workflows ul.dropdown-menu(aria-labelledby="add-workflow-btn") li.dropdown-item(id="project-workflow-group-new-workflow" data-hook="project-workflow-group-new-workflow") New Workflow - li.dropdown-divider(style="display: none;") - li.dropdown-item(id="project-workflow-group-add-workflow" data-hook="project-workflow-group-add-workflow" style="display: none;") Existing Workflow + li.dropdown-divider + li.dropdown-item(id="project-workflow-group-add-workflow" data-hook="project-workflow-group-add-workflow") Existing Workflow \ No newline at end of file diff --git a/client/views/edit-workflows-view.js b/client/views/edit-workflows-view.js index 7c41325397..77c862286f 100644 --- a/client/views/edit-workflows-view.js +++ b/client/views/edit-workflows-view.js @@ -32,7 +32,7 @@ module.exports = View.extend({ template: template, events: { 'click [data-hook=project-workflow-group-new-workflow]' : 'handleNewWorkflowClick', - // 'click [data-hook=project-workflow-group-add-workflow]' : 'handleAddWorkflowClick', + 'click [data-hook=project-workflow-group-add-workflow]' : 'handleAddWorkflowClick', }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments) @@ -97,38 +97,25 @@ module.exports = View.extend({ if(document.querySelector("#newProjectWorkflowModal")) { document.querySelector("#newProjectWorkflowModal").remove() } - let modal = $(modals.addExistingWorkflowToProjectHtml()).modal() - let okBtn = document.querySelector("#newProjectWorkflowModal .ok-model-btn") - let input = document.querySelector("#newProjectWorkflowModal #workflowPathInput") - input.addEventListener("keyup", function (event) { - if(event.keyCode === 13){ - event.preventDefault(); - okBtn.click(); - } - }); - input.addEventListener("input", function (e) { - var endErrMsg = document.querySelector('#newProjectWorkflowModal #workflowPathInputEndCharError') - var charErrMsg = document.querySelector('#newProjectWorkflowModal #workflowPathInputSpecCharError') - let error = self.validateName(input.value) - okBtn.disabled = error !== "" - charErrMsg.style.display = error === "both" || error === "special" ? "block" : "none" - endErrMsg.style.display = error === "both" || error === "forward" ? "block" : "none" - }); - okBtn.addEventListener('click', function (e) { - if(Boolean(input.value)) { - let expPath = path.join(self.parent.parent.projectPath, self.model.name)+".wkgp" - let queryString = "?path="+expPath+"&wkflPath="+input.value + let wkflListEP = path.join(app.getApiPath(), "project/add-existing-workflow") + "?path="+self.parent.parent.parent.projectPath + xhr({uri:wkflListEP, json:true}, function (err, response, body) { + let modal = $(modals.addExistingWorkflowToProjectHtml(body.workflows)).modal() + let okBtn = document.querySelector("#newProjectWorkflowModal .ok-model-btn") + let select = document.querySelector("#newProjectWorkflowModal #workflowPathInput") + okBtn.addEventListener('click', function (e) { + let expPath = path.join(self.parent.parent.parent.projectPath, "WorkflowGroup1.wkgp") + let queryString = "?path="+expPath+"&wkflPath="+select.value let endpoint = path.join(app.getApiPath(), "project/add-existing-workflow")+queryString xhr({uri: endpoint, json: true, method: "post"}, function (err, response, body) { if(response.statusCode < 400) { - self.parent.parent.update("workflow-group-editor") + self.parent.parent.parent.update("workflow-group-editor") let successModal = $(modals.addExistingWorkflowToProjectSuccessHtml(body.message)).modal() }else{ let errorModal = $(modals.addExistingWorkflowToProjectErrorHtml(body.Reason, body.Message)).modal() } }); modal.modal('hide') - } + }); }); } }); \ No newline at end of file diff --git a/client/views/file-browser-view.js b/client/views/file-browser-view.js index 668c5c74e1..cc5d75cc3c 100644 --- a/client/views/file-browser-view.js +++ b/client/views/file-browser-view.js @@ -766,26 +766,13 @@ module.exports = View.extend({ if(document.querySelector('#newProjectWorkflowModal')) { document.querySelector('#newProjectWorkflowModal').remove() } - let modal = $(modals.addExistingWorkflowToProjectHtml()).modal() - let okBtn = document.querySelector('#newProjectWorkflowModal .ok-model-btn') - let input = document.querySelector('#newProjectWorkflowModal #workflowPathInput') - input.addEventListener("keyup", function (event) { - if(event.keyCode === 13){ - event.preventDefault(); - okBtn.click(); - } - }); - input.addEventListener("input", function (e) { - var endErrMsg = document.querySelector('#newProjectWorkflowModal #workflowPathInputEndCharError') - var charErrMsg = document.querySelector('#newProjectWorkflowModal #workflowPathInputSpecCharError') - let error = self.validateName(input.value) - okBtn.disabled = error !== "" - charErrMsg.style.display = error === "both" || error === "special" ? "block" : "none" - endErrMsg.style.display = error === "both" || error === "forward" ? "block" : "none" - }); - okBtn.addEventListener("click", function (e) { - if(Boolean(input.value)) { - let queryString = "?path="+o.original._path+"&wkflPath="+input.value.trim() + let wkflListEP = path.join(app.getApiPath(), "project/add-existing-workflow") + "?path="+self.parent.projectPath + xhr({uri:wkflListEP, json:true}, function (err, response, body) { + let modal = $(modals.addExistingWorkflowToProjectHtml(body.workflows)).modal() + let okBtn = document.querySelector('#newProjectWorkflowModal .ok-model-btn') + let select = document.querySelector('#newProjectWorkflowModal #workflowPathInput') + okBtn.addEventListener("click", function (e) { + let queryString = "?path="+o.original._path+"&wkflPath="+select.value let endpoint = path.join(app.getApiPath(), "project/add-existing-workflow")+queryString xhr({uri: endpoint, json: true, method:"post"}, function (err, response, body) { if(response.statusCode < 400) { @@ -796,7 +783,7 @@ module.exports = View.extend({ } }); modal.modal('hide') - } + }); }); }, newModelOrDirectory: function (o, isModel, isSpatial) { @@ -1241,7 +1228,7 @@ module.exports = View.extend({ "New Workflow" : newWorkflow.NewWorkflow, "Existing Workflow" : { "label" : "Existing Workflow", - "_disabled" : true, + "_disabled" : false, "separator_before" : false, "separator_after" : false, "action" : function (data) { diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py index acdb42f013..eb9b304f13 100644 --- a/stochss/handlers/project.py +++ b/stochss/handlers/project.py @@ -340,22 +340,23 @@ def get(self): Attributes ---------- ''' - log.setLevel(logging.DEBUG) user_dir = "/home/jovyan" self.set_header('Content-Type', 'application/json') path = os.path.join(user_dir, self.get_query_argument(name="path")) log.debug("Path to the model: %s", path) models = [] for root, dirs, files in os.walk("/home/jovyan"): - if root != path and "/." not in root and ".wkfl" not in root: + if path not in root and "/." not in root and ".wkfl" not in root: root = root.replace(user_dir+"/", "") files = list(filter(lambda file: (not file.startswith(".") and file.endswith(".mdl")), files)) for file in files: - models.append(os.path.join(root, file)) + if root == user_dir: + models.append(file) + else: + models.append(os.path.join(root, file)) log.debug("List of model that can be added to the project: %s", models) self.write({"models": models}) - log.setLevel(logging.WARNING) self.finish() @@ -418,23 +419,24 @@ def get(self): Attributes ---------- ''' - log.setLevel(logging.DEBUG) user_dir = "/home/jovyan" self.set_header('Content-Type', 'application/json') path = os.path.join(user_dir, self.get_query_argument(name="path")) log.debug("Path to the model: %s", path) workflows = [] for root, dirs, files in os.walk("/home/jovyan"): - if root != path and "/." not in root: + if path not in root and "/." not in root: root = root.replace(user_dir+"/", "") dirs = list(filter(lambda item: (not item.startswith(".") and item.endswith(".wkfl")), dirs)) for item in dirs: - workflows.append(os.path.join(root, item)) + if root == user_dir: + workflows.append(item) + else: + workflows.append(os.path.join(root, item)) log.debug("List of workflows that can be added to the project: \ %s", workflows) self.write({"workflows": workflows}) - log.setLevel(logging.WARNING) self.finish() From bba729a9ebb91d3e7a264ce1897ba6e34f70ecf3 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 13 Oct 2020 16:52:53 -0400 Subject: [PATCH 03/24] Moved the 'Show/Hide Preview' button to the left side of the model state buttons row. --- client/pages/model-editor.js | 1 - client/templates/pages/modelEditor.pug | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 2ab8949d65..4031c02288 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -290,7 +290,6 @@ let ModelEditor = PageView.extend({ }, togglePreviewPlot: function (e) { let action = e.target.innerText - console.log(action) if(action === "Hide Preview") { this.closePlot() }else{ diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index 481ad5509e..09b9787a19 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -51,9 +51,6 @@ section.page div(class="preview-nav") - div(data-hook="toggle-preview-plot-container") - button.btn.btn-outline-secondary.box-shadow.preview-close(data-hook="toggle-preview-plot") Hide Preview - div(data-hook="model-run-container") div.spinner-border(data-hook="plot-loader") @@ -66,5 +63,11 @@ section.page p.text-danger(data-hook="model-run-error-message") - div.model-state-buttons(data-hook="model-state-buttons-container") + div + + div.inline(data-hook="toggle-preview-plot-container") + + button.btn.btn-outline-secondary.box-shadow.preview-close(data-hook="toggle-preview-plot") Hide Preview + + div.model-state-buttons.inline(data-hook="model-state-buttons-container") From 87e92600708588f12eb493ecc40bdfe1a8876430 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 13 Oct 2020 18:03:18 -0400 Subject: [PATCH 04/24] Added a explore model message that only displays when the preview plot is displayed. --- client/pages/model-editor.js | 2 ++ client/styles/styles.css | 4 ++++ client/templates/includes/eventsViewer.pug | 3 +++ client/templates/includes/parametersViewer.pug | 2 ++ client/templates/includes/reactionsViewer.pug | 2 ++ client/templates/includes/rulesViewer.pug | 2 ++ client/templates/includes/speciesViewer.pug | 4 +++- client/templates/includes/viewEvents.pug | 5 ++++- client/templates/includes/viewParameters.pug | 5 ++++- client/templates/includes/viewReactions.pug | 5 ++++- client/templates/includes/viewRules.pug | 5 ++++- client/templates/includes/viewSpecies.pug | 5 ++++- client/templates/pages/modelEditor.pug | 4 ++++ client/views/model-state-buttons.js | 2 ++ 14 files changed, 44 insertions(+), 6 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 4031c02288..96e2af251d 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -301,12 +301,14 @@ let ModelEditor = PageView.extend({ let button = this.queryByHook("toggle-preview-plot") plot.style.display = "none" button.innerText = "Show Preview" + $(this.queryByHook('explore-model-msg')).css('display', 'none'); }, openPlot: function () { let plot = this.queryByHook("model-run-container") let button = this.queryByHook("toggle-preview-plot") plot.style.display = "block" button.innerText = "Hide Preview" + $(this.queryByHook('explore-model-msg')).css('display', 'block'); } }); diff --git a/client/styles/styles.css b/client/styles/styles.css index 4e4c0d3505..6ffdfe77c0 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -587,3 +587,7 @@ span.checkbox { .model-state-buttons { float: right; } + +#explore-model-msg { + display: none; +} diff --git a/client/templates/includes/eventsViewer.pug b/client/templates/includes/eventsViewer.pug index a958d2462d..81b2da4a0c 100644 --- a/client/templates/includes/eventsViewer.pug +++ b/client/templates/includes/eventsViewer.pug @@ -25,6 +25,9 @@ div#events-viewer.card.card-body th(scope="col") Use Values From + if this.containsMdlWithAnn + th.col-md-3-view(scope="col") Annotation + tbody(data-hook="view-events-container") if this.collection.parent.for === "edit" diff --git a/client/templates/includes/parametersViewer.pug b/client/templates/includes/parametersViewer.pug index 7e91269a54..b579141fb2 100644 --- a/client/templates/includes/parametersViewer.pug +++ b/client/templates/includes/parametersViewer.pug @@ -12,6 +12,8 @@ div#parameters-viewer.card.card-body tr th.col-md-3-view(scope="col") Name th.col-md-9-view(scope="col") Value + if this.containsMdlWithAnn + th.col-md-3-view(scope="col") Annotation tbody(data-hook="parameter-list") diff --git a/client/templates/includes/reactionsViewer.pug b/client/templates/includes/reactionsViewer.pug index d8eacdc4f1..136c6c3531 100644 --- a/client/templates/includes/reactionsViewer.pug +++ b/client/templates/includes/reactionsViewer.pug @@ -13,6 +13,8 @@ div#reactions-viewer.card.card-body th.col-md-3-view(scope="col") Name th.col-md-3-view(scope="col") Summary th.col-md-6-view(scope="col") Rate/Propensity + if this.containsMdlWithAnn + th.col-md-3-view(scope="col") Annotation tbody(data-hook="reaction-list") diff --git a/client/templates/includes/rulesViewer.pug b/client/templates/includes/rulesViewer.pug index 96d8871487..487fd54459 100644 --- a/client/templates/includes/rulesViewer.pug +++ b/client/templates/includes/rulesViewer.pug @@ -14,6 +14,8 @@ div#rules-viewer.card.card-body th.col-md-3-view(scope="col") Type th.col-md-3-view(scope="col") Variable th.col-md-3-view(scope="col") Formula + if this.containsMdlWithAnn + th.col-md-3-view(scope="col") Annotation tbody(data-hook="rules-list") diff --git a/client/templates/includes/speciesViewer.pug b/client/templates/includes/speciesViewer.pug index 453b92763b..78e3103d9a 100644 --- a/client/templates/includes/speciesViewer.pug +++ b/client/templates/includes/speciesViewer.pug @@ -15,7 +15,9 @@ div#species-viewer.card.card-body th.col-md-3-view(scope="col") Mode if this.collection.parent.defaultMode === "dynamic" th.col-md-3-view(scope="col") Switch Tolerance/Minimum Value for Switching - + if this.containsMdlWithAnn + th.col-md-3-view(scope="col") Annotation + tbody(data-hook="specie-list") if this.collection.parent.for === "edit" diff --git a/client/templates/includes/viewEvents.pug b/client/templates/includes/viewEvents.pug index cad0780028..ddf2d85142 100644 --- a/client/templates/includes/viewEvents.pug +++ b/client/templates/includes/viewEvents.pug @@ -36,4 +36,7 @@ tr span.inline.horizontal-space(for="assignment-time") Assignment Time - input(type="radio", id="assignment-time", name="use-values-from" data-hook="assignment-time" disabled) \ No newline at end of file + input(type="radio", id="assignment-time", name="use-values-from" data-hook="assignment-time" disabled) + + if this.model.annotation + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file diff --git a/client/templates/includes/viewParameters.pug b/client/templates/includes/viewParameters.pug index acfcb85c82..8e42d9576e 100644 --- a/client/templates/includes/viewParameters.pug +++ b/client/templates/includes/viewParameters.pug @@ -1,4 +1,7 @@ tr td=this.model.name - td=this.model.expression \ No newline at end of file + td=this.model.expression + + if this.model.annotation + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file diff --git a/client/templates/includes/viewReactions.pug b/client/templates/includes/viewReactions.pug index c3fa5ae6b6..dd4eeb3324 100644 --- a/client/templates/includes/viewReactions.pug +++ b/client/templates/includes/viewReactions.pug @@ -3,4 +3,7 @@ tr td: div(data-hook="summary") - td=this.rate \ No newline at end of file + td=this.rate + + if this.model.annotation + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file diff --git a/client/templates/includes/viewRules.pug b/client/templates/includes/viewRules.pug index e4d2847c42..8646ac2a5b 100644 --- a/client/templates/includes/viewRules.pug +++ b/client/templates/includes/viewRules.pug @@ -5,4 +5,7 @@ tr td=this.model.variable.name - td=this.model.expression \ No newline at end of file + td=this.model.expression + + if this.model.annotation + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file diff --git a/client/templates/includes/viewSpecies.pug b/client/templates/includes/viewSpecies.pug index ccc54efe72..39005028b8 100644 --- a/client/templates/includes/viewSpecies.pug +++ b/client/templates/includes/viewSpecies.pug @@ -6,4 +6,7 @@ tr td=this.model.mode if this.model.collection.parent.defaultMode === 'dynamic' - td=this.switchingValWithLabel \ No newline at end of file + td=this.switchingValWithLabel + + if this.model.annotation + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index 09b9787a19..22a3be329c 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -53,6 +53,10 @@ section.page div(data-hook="model-run-container") + div(id="explore-model-msg" data-hook="explore-model-msg") + + p.text-info You can eplore this model further by clicking New Workflow Using Model + div.spinner-border(data-hook="plot-loader") div.collapse(data-hook="model-timeout-message") diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 5f886c2b6b..58e1a9f0df 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -56,6 +56,7 @@ module.exports = View.extend({ clickRunHandler: function (e) { $(this.parent.queryByHook('model-run-error-container')).collapse('hide'); $(this.parent.queryByHook('model-timeout-message')).collapse('hide'); + $(this.parent.queryByHook('explore-model-msg')).css('display', 'none'); var el = this.parent.queryByHook('model-run-container'); Plotly.purge(el) this.saveModel(this.runModel.bind(this)); @@ -186,6 +187,7 @@ module.exports = View.extend({ Plotly.newPlot(el, data); $(this.parent.queryByHook('toggle-preview-plot-container')).css('height', '50px') $(this.parent.queryByHook('toggle-preview-plot')).css('display', 'block') + $(this.parent.queryByHook('explore-model-msg')).css('display', 'block'); window.scrollTo(0, document.body.scrollHeight) }, }); From 92c5bef90264e630ca8e9e8e784a62b392b916f3 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 13 Oct 2020 18:31:29 -0400 Subject: [PATCH 05/24] Added annotation column to the view mode of the model components that only displays if the component has an annotation. Added function to only display the annotation header in a component section if at least one component in that section has an annotation. --- client/templates/includes/viewEvents.pug | 5 ++++- client/templates/includes/viewParameters.pug | 5 ++++- client/templates/includes/viewReactions.pug | 5 ++++- client/templates/includes/viewRules.pug | 5 ++++- client/templates/includes/viewSpecies.pug | 6 +++++- client/views/events-viewer.js | 7 +++++++ client/views/parameters-viewer.js | 7 +++++++ client/views/reactions-viewer.js | 7 +++++++ client/views/rules-viewer.js | 7 +++++++ client/views/species-viewer.js | 7 +++++++ 10 files changed, 56 insertions(+), 5 deletions(-) diff --git a/client/templates/includes/viewEvents.pug b/client/templates/includes/viewEvents.pug index ddf2d85142..44f07db6e7 100644 --- a/client/templates/includes/viewEvents.pug +++ b/client/templates/includes/viewEvents.pug @@ -39,4 +39,7 @@ tr input(type="radio", id="assignment-time", name="use-values-from" data-hook="assignment-time" disabled) if this.model.annotation - td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + if this.parent.containsMdlWithAnn && !this.model.annotation + td: div diff --git a/client/templates/includes/viewParameters.pug b/client/templates/includes/viewParameters.pug index 8e42d9576e..a4cae60444 100644 --- a/client/templates/includes/viewParameters.pug +++ b/client/templates/includes/viewParameters.pug @@ -4,4 +4,7 @@ tr td=this.model.expression if this.model.annotation - td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + if this.parent.containsMdlWithAnn && !this.model.annotation + td: div diff --git a/client/templates/includes/viewReactions.pug b/client/templates/includes/viewReactions.pug index dd4eeb3324..9c14ed8fab 100644 --- a/client/templates/includes/viewReactions.pug +++ b/client/templates/includes/viewReactions.pug @@ -6,4 +6,7 @@ tr td=this.rate if this.model.annotation - td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + if this.parent.containsMdlWithAnn && !this.model.annotation + td: div diff --git a/client/templates/includes/viewRules.pug b/client/templates/includes/viewRules.pug index 8646ac2a5b..f4b039523b 100644 --- a/client/templates/includes/viewRules.pug +++ b/client/templates/includes/viewRules.pug @@ -8,4 +8,7 @@ tr td=this.model.expression if this.model.annotation - td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + if this.parent.containsMdlWithAnn && !this.model.annotation + td: div diff --git a/client/templates/includes/viewSpecies.pug b/client/templates/includes/viewSpecies.pug index 39005028b8..958ddf8959 100644 --- a/client/templates/includes/viewSpecies.pug +++ b/client/templates/includes/viewSpecies.pug @@ -9,4 +9,8 @@ tr td=this.switchingValWithLabel if this.model.annotation - td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") \ No newline at end of file + td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") + + if this.parent.containsMdlWithAnn && !this.model.annotation + td: div + \ No newline at end of file diff --git a/client/views/events-viewer.js b/client/views/events-viewer.js index 614c66d0a4..fe561d9c5b 100644 --- a/client/views/events-viewer.js +++ b/client/views/events-viewer.js @@ -31,10 +31,17 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0 }, render: function () { View.prototype.render.apply(this, arguments); this.renderCollection(this.collection, ViewEvent, this.queryByHook('view-events-container')) + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, switchToEditMode: function (e) { this.parent.renderEventsView("edit", true); diff --git a/client/views/parameters-viewer.js b/client/views/parameters-viewer.js index 4df15eac7d..3ec3b45078 100644 --- a/client/views/parameters-viewer.js +++ b/client/views/parameters-viewer.js @@ -31,10 +31,17 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0 }, render: function () { View.prototype.render.apply(this, arguments); this.renderCollection(this.collection, ViewParameter, this.queryByHook('parameter-list')) + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, switchToEditMode: function (e) { this.parent.renderParametersView("edit", true); diff --git a/client/views/reactions-viewer.js b/client/views/reactions-viewer.js index 75b547a601..86acc195a5 100644 --- a/client/views/reactions-viewer.js +++ b/client/views/reactions-viewer.js @@ -31,10 +31,17 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0 }, render: function () { View.prototype.render.apply(this, arguments); this.renderCollection(this.collection, ViewReactions, this.queryByHook('reaction-list')) + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, switchToEditMode: function (e) { this.parent.renderReactionsView("edit", true); diff --git a/client/views/rules-viewer.js b/client/views/rules-viewer.js index 76d492561b..88377a2033 100644 --- a/client/views/rules-viewer.js +++ b/client/views/rules-viewer.js @@ -31,10 +31,17 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0 }, render: function () { View.prototype.render.apply(this, arguments); this.renderCollection(this.collection, ViewRules, this.queryByHook('rules-list')) + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, switchToEditMode: function (e) { this.parent.renderRulesView("edit", true); diff --git a/client/views/species-viewer.js b/client/views/species-viewer.js index c5ec42017f..9e92ec0048 100644 --- a/client/views/species-viewer.js +++ b/client/views/species-viewer.js @@ -31,10 +31,17 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); + this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0 }, render: function () { View.prototype.render.apply(this, arguments); this.renderCollection(this.collection, ViewSpecie, this.queryByHook('specie-list')) + $(document).ready(function () { + $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').click(function () { + $('[data-toggle="tooltip"]').tooltip("hide"); + }); + }); }, switchToEditMode: function (e) { this.parent.renderSpeciesView(); From 7384447375eecdb27cccaf363ab7c04a278ac4a6 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 14 Oct 2020 14:50:38 -0400 Subject: [PATCH 06/24] Set up a validate function for the model settings that validates the its properties and returns and value representing the validity of the model settings model. Set up a validate function for the model that calls its components validate function to determine the validity of the model. Added a call to the 'updateValid function of the parent of an input view whenever the input changes. Change the event listener for the input field from a 'change' event to an 'input' event. Added model.validate call to the success function of the model.fetch function. Added a value error check to the run preview functionality to catch any value errors generated by gillespy2. --- client/models/model-settings.js | 6 ++++++ client/models/model.js | 10 ++++++++++ client/pages/model-editor.js | 1 + client/views/input.js | 3 ++- client/views/model-settings.js | 3 ++- client/views/model-state-buttons.js | 11 ++++++++++- stochss/handlers/util/run_model.py | 2 ++ 7 files changed, 33 insertions(+), 3 deletions(-) diff --git a/client/models/model-settings.js b/client/models/model-settings.js index f77fb8d42f..37a2f126c4 100644 --- a/client/models/model-settings.js +++ b/client/models/model-settings.js @@ -27,5 +27,11 @@ module.exports = State.extend({ }, initialize: function (attrs, options) { State.prototype.initialize.apply(this, arguments) + }, + validate: function () { + if(this.endSim == 0 || isNaN(this.endSim)) return false; + if(this.timeStep == 0 || isNaN(this.timeStep)) return false; + if(this.volume == 0 || isNaN(this.volume)) return false; + return true; } }); \ No newline at end of file diff --git a/client/models/model.js b/client/models/model.js index 9c5d9e102e..de51a2eb9f 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -61,10 +61,20 @@ module.exports = Model.extend({ directory: 'string', isPreview: 'boolean', for: 'string', + valid: 'boolean' }, initialize: function (attrs, options){ Model.prototype.initialize.apply(this, arguments); }, + validate: function () { + if(this.modelSettings.validate() === false) { + console.log("The model settings are invalid") + this.valid = false; + }else{ + console.log("The model is valid") + this.valid = true; + } + }, getDefaultID: function () { var id = this.defaultID; this.defaultID += 1; diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 2ab8949d65..282e7660a3 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -89,6 +89,7 @@ let ModelEditor = PageView.extend({ if(!self.model.functionDefinitions.length) { self.queryByHook('sbml-component-container').style.display = "none"; } + self.model.validate() } }); this.model.reactions.on("change", function (reactions) { diff --git a/client/views/input.js b/client/views/input.js index 89ef1cac9a..bcb150dfa0 100644 --- a/client/views/input.js +++ b/client/views/input.js @@ -26,7 +26,7 @@ module.exports = AmpersandInputView.extend({ valueType: 'string', }, events: { - 'change input' : 'changeInputHandler', + 'input input' : 'changeInputHandler', }, initialize: function (attrs, options) { AmpersandInputView.prototype.initialize.apply(this, arguments); @@ -59,6 +59,7 @@ module.exports = AmpersandInputView.extend({ if(this.modelKey){ var value = this.valueType === 'number' ? Number(e.target.value.trim()) : e.target.value.trim(); this.parent.model[this.modelKey] = value; + this.parent.updateValid() } }, }); \ No newline at end of file diff --git a/client/views/model-settings.js b/client/views/model-settings.js index 426d8d6247..59a35d67fc 100644 --- a/client/views/model-settings.js +++ b/client/views/model-settings.js @@ -40,9 +40,10 @@ module.exports = View.extend({ render: function () { View.prototype.render.apply(this, arguments); }, - update: function () { + update: function (e) { }, updateValid: function () { + this.model.parent.validate() }, changeCollapseButtonText: function (e) { let source = e.target.dataset.hook diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 7674373707..5c958a0927 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -30,6 +30,13 @@ var template = require('../templates/includes/modelStateButtons.pug'); module.exports = View.extend({ template: template, + bindings: { + 'model.invalid': { + hook: 'run', + type: 'booleanAttribute', + name: 'disabled', + }, + }, events: { 'click [data-hook=save]' : 'clickSaveHandler', 'click [data-hook=run]' : 'clickRunHandler', @@ -42,6 +49,7 @@ module.exports = View.extend({ this.model.reactions.on('add remove', this.togglePreviewWorkflowBtn, this); this.model.eventsCollection.on('add remove', this.togglePreviewWorkflowBtn, this); this.model.rules.on('add remove', this.togglePreviewWorkflowBtn, this); + this.model.on('change', this.togglePreviewWorkflowBtn, this) }, render: function () { View.prototype.render.apply(this, arguments); @@ -87,7 +95,8 @@ module.exports = View.extend({ var numReactions = this.model.reactions.length var numEvents = this.model.eventsCollection.length var numRules = this.model.rules.length - $(this.queryByHook('run')).prop('disabled', (!numSpecies || (!numReactions && !numEvents && !numRules))) + let disabled = !(this.model.valid && numSpecies && (numReactions || numEvents || numRules)) + $(this.queryByHook('run')).prop('disabled', disabled) }, saveModel: function (cb) { this.saving(); diff --git a/stochss/handlers/util/run_model.py b/stochss/handlers/util/run_model.py index 057ccc8b34..d8c9f1ca7e 100755 --- a/stochss/handlers/util/run_model.py +++ b/stochss/handlers/util/run_model.py @@ -704,6 +704,8 @@ def get_parsed_args(): resp['errors'] = "{0}".format(error) except SimulationError as error: resp['errors'] = "{0}".format(error) + except ValueError as error: + resp['errors'] = "{0}".format(error) with open(outfile, "w") as fd: json.dump(resp, fd, cls=plotly.utils.PlotlyJSONEncoder) open(outfile + ".done", "w").close() From d40ef64b757d32846ec65b16778bfdba5e5a35b3 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 14 Oct 2020 15:18:31 -0400 Subject: [PATCH 07/24] Refactored the models validate function to return a boolean to make it consistant with other validate functions. Added an update valid function that re-validates the model and sets the valid session property. Moved the validation functions for minimum components to the model file. Removed the event listeners from the model-state-buttons view file. --- client/models/events.js | 2 ++ client/models/model.js | 14 +++++++------- client/models/reactions.js | 2 ++ client/models/rules.js | 2 ++ client/models/species.js | 2 ++ client/pages/model-editor.js | 2 +- client/views/model-settings.js | 2 +- client/views/model-state-buttons.js | 4 ---- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/client/models/events.js b/client/models/events.js index f839e3e824..8b928e06aa 100644 --- a/client/models/events.js +++ b/client/models/events.js @@ -39,6 +39,7 @@ module.exports = Collection.extend({ useValuesFromTriggerTime: false, }); event.eventAssignments.addEventAssignment() + this.parent.updateValid() return event }, getDefaultName: function () { @@ -53,5 +54,6 @@ module.exports = Collection.extend({ }, removeEvent: function (event) { this.remove(event); + this.parent.updateValid() }, }); \ No newline at end of file diff --git a/client/models/model.js b/client/models/model.js index de51a2eb9f..713a9d4ae1 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -67,13 +67,13 @@ module.exports = Model.extend({ Model.prototype.initialize.apply(this, arguments); }, validate: function () { - if(this.modelSettings.validate() === false) { - console.log("The model settings are invalid") - this.valid = false; - }else{ - console.log("The model is valid") - this.valid = true; - } + if(this.species.length <= 0) return false; + if(this.reactions.length <= 0 && this.eventsCollection.length <= 0 && this.rules.length <= 0) return false + if(this.modelSettings.validate() === false) return false; + return true; + }, + updateValid: function () { + this.valid = this.validate() }, getDefaultID: function () { var id = this.defaultID; diff --git a/client/models/reactions.js b/client/models/reactions.js index 03383330e5..72b201c48a 100644 --- a/client/models/reactions.js +++ b/client/models/reactions.js @@ -49,6 +49,7 @@ Reactions = Collection.extend({ reaction.rate = this.getDefaultRate(); reaction.buildSummary() this.add(reaction); + this.parent.updateValid() return reaction; }, getDefaultName: function () { @@ -76,6 +77,7 @@ Reactions = Collection.extend({ }, removeReaction: function (reaction) { this.remove(reaction); + this.parent.updateValid() }, }); diff --git a/client/models/rules.js b/client/models/rules.js index 7ebc5dc512..97f2683293 100644 --- a/client/models/rules.js +++ b/client/models/rules.js @@ -37,9 +37,11 @@ module.exports = Collection.extend({ }); rule.variable = variable; this.add(rule); + this.parent.updateValid() }, removeRule: function (rule) { this.remove(rule); + this.parent.updateValid() }, getDefaultName: function () { var i = this.length + 1; diff --git a/client/models/species.js b/client/models/species.js index a6b249216e..de359c0ec8 100644 --- a/client/models/species.js +++ b/client/models/species.js @@ -39,6 +39,7 @@ module.exports = Collection.extend({ diffusionCoeff: 0.0, subdomains: subdomains }); + this.parent.updateValid() }, getDefaultName: function () { var i = this.length + 1; @@ -52,5 +53,6 @@ module.exports = Collection.extend({ }, removeSpecie: function (specie) { this.remove(specie); + this.parent.updateValid() }, }); \ No newline at end of file diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 282e7660a3..81252d854b 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -89,7 +89,7 @@ let ModelEditor = PageView.extend({ if(!self.model.functionDefinitions.length) { self.queryByHook('sbml-component-container').style.display = "none"; } - self.model.validate() + self.model.updateValid() } }); this.model.reactions.on("change", function (reactions) { diff --git a/client/views/model-settings.js b/client/views/model-settings.js index 59a35d67fc..e5297b4e79 100644 --- a/client/views/model-settings.js +++ b/client/views/model-settings.js @@ -43,7 +43,7 @@ module.exports = View.extend({ update: function (e) { }, updateValid: function () { - this.model.parent.validate() + this.model.parent.updateValid() }, changeCollapseButtonText: function (e) { let source = e.target.dataset.hook diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 5c958a0927..1e2a6e40fb 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -45,10 +45,6 @@ module.exports = View.extend({ }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); - this.model.species.on('add remove', this.togglePreviewWorkflowBtn, this); - this.model.reactions.on('add remove', this.togglePreviewWorkflowBtn, this); - this.model.eventsCollection.on('add remove', this.togglePreviewWorkflowBtn, this); - this.model.rules.on('add remove', this.togglePreviewWorkflowBtn, this); this.model.on('change', this.togglePreviewWorkflowBtn, this) }, render: function () { From 8f569457551ab31f00dea9ef1b26be9a54ed8420 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 14 Oct 2020 16:29:16 -0400 Subject: [PATCH 08/24] Fixed the typo in the new explore method. Modified the css for the left nav bar to transition from a column to a row when the view port becomes smaller than 768px. Fixed the center styling for the preview plot loading spinner. Removed the col-md-10 class from the user-home page. --- client/styles/styles.css | 17 ++++++++++++++--- client/templates/body.pug | 8 ++++---- client/templates/pages/modelEditor.pug | 2 +- client/templates/pages/usersHome.pug | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/client/styles/styles.css b/client/styles/styles.css index 6ffdfe77c0..f15e1494f1 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -16,10 +16,20 @@ img.quickstart { .sidebar { padding-top: 20px; margin-top: 48px; - min-height: 8em; + padding-left: 10px } +@media (min-width: 768px) { + .sidebar { + min-height: 8em; + } + .nav-flex-column { + -ms-flex-direction: column !important; + flex-direction: column !important; + } +} + [role="main"] { padding-top: 20px; margin-top: 48px; @@ -318,8 +328,9 @@ input[type="file"]::-ms-browse { .spinner-border { display: none; position: relative; - margin: 15px; - left: 40%; + margin: 15px auto; + left: 0; + right: 0; width: 90px; height: 90px; border: 12px solid rgba(0, 0, 0, 0.125); diff --git a/client/templates/body.pug b/client/templates/body.pug index 206fa084af..871cf129a1 100644 --- a/client/templates/body.pug +++ b/client/templates/body.pug @@ -31,11 +31,11 @@ body | Sign Out div.container-fluid - div.row.flex-nowrap - div.col-md-2 + div.row + div.col-xs-12.col-md-2 nav.sidebar.d-md-block div.sidebar-sticky.tools - ul.nav.flex-column + ul.nav.nav-flex-column li.nav-item: a.nav-link(href="stochss/home", title="Users Home Page") | Home @@ -51,4 +51,4 @@ body li.nav-item: a.nav-link(href="stochss/quickstart", title="Quickstart") | Tutorial - main.col-md-10.body(role="main"): div.container-fluid(data-hook="page-container") + main.col-xs-12.col-md-10.body(role="main"): div.container-fluid(data-hook="page-container") diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index 22a3be329c..7ff528c0f5 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -55,7 +55,7 @@ section.page div(id="explore-model-msg" data-hook="explore-model-msg") - p.text-info You can eplore this model further by clicking New Workflow Using Model + p.text-info You can explore this model further by clicking New Workflow Using Model div.spinner-border(data-hook="plot-loader") diff --git a/client/templates/pages/usersHome.pug b/client/templates/pages/usersHome.pug index 249b37f645..83046269d8 100644 --- a/client/templates/pages/usersHome.pug +++ b/client/templates/pages/usersHome.pug @@ -1,6 +1,6 @@ selction.page - div#home-wrapper.card.card-body.col-md-10 + div#home-wrapper.card.card-body div.logo(id="stochss-logo" data-hook="stochss-logo") From 78673f36949b8396a19b5e0c980c833aa896662e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Wed, 14 Oct 2020 17:04:06 -0400 Subject: [PATCH 09/24] Fixed styling for the switching class to use min-height instead of height. Change the name of the models validate function to validateModel. --- client/models/model.js | 4 ++-- client/styles/styles.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/models/model.js b/client/models/model.js index 713a9d4ae1..47f2c14463 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -66,14 +66,14 @@ module.exports = Model.extend({ initialize: function (attrs, options){ Model.prototype.initialize.apply(this, arguments); }, - validate: function () { + validateModel: function () { if(this.species.length <= 0) return false; if(this.reactions.length <= 0 && this.eventsCollection.length <= 0 && this.rules.length <= 0) return false if(this.modelSettings.validate() === false) return false; return true; }, updateValid: function () { - this.valid = this.validate() + this.valid = this.validateModel() }, getDefaultID: function () { var id = this.defaultID; diff --git a/client/styles/styles.css b/client/styles/styles.css index 76e99960ac..93bc26c5ff 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -444,7 +444,7 @@ span.checkbox { .switching { vertical-align: middle; margin-bottom: 5px; - height: 29px; + min-height: 29px; } #home-wrapper { From ef61855a0b6328e3da92a2cea92985597086a0ab Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 15 Oct 2020 10:14:23 -0400 Subject: [PATCH 10/24] Updated the 'Variable' header in event assignments and rules to be 'Target'. Added the 'or Parameters' to the rules description. --- client/templates/includes/eventAssignmentsEditor.pug | 2 +- client/templates/includes/eventAssignmentsViewer.pug | 2 +- client/templates/includes/ruleEditor.pug | 4 ++-- client/templates/includes/rulesViewer.pug | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/templates/includes/eventAssignmentsEditor.pug b/client/templates/includes/eventAssignmentsEditor.pug index 7d7f7cd9a0..022cef0cd7 100644 --- a/client/templates/includes/eventAssignmentsEditor.pug +++ b/client/templates/includes/eventAssignmentsEditor.pug @@ -8,7 +8,7 @@ div th(scope="col") div - div.inline Variable + div.inline Target div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.parent.tooltips.variable) diff --git a/client/templates/includes/eventAssignmentsViewer.pug b/client/templates/includes/eventAssignmentsViewer.pug index fcd60f345f..4a3aa846c8 100644 --- a/client/templates/includes/eventAssignmentsViewer.pug +++ b/client/templates/includes/eventAssignmentsViewer.pug @@ -4,7 +4,7 @@ table.table tr - th(scope="col") Variable + th(scope="col") Target th(scope="col") Expression diff --git a/client/templates/includes/ruleEditor.pug b/client/templates/includes/ruleEditor.pug index 65311b84c6..7065291d4e 100644 --- a/client/templates/includes/ruleEditor.pug +++ b/client/templates/includes/ruleEditor.pug @@ -8,7 +8,7 @@ div#rules-editor.card.card-body div.collapse(id="collapse-rules" data-hook="rules-list-container") p - | Equations that determine the value (assignment rule) or rates of change (rate rule) of Variables. + | Equations that determine the value (assignment rule) or rates of change (rate rule) of Variables or Parameter. table.table @@ -30,7 +30,7 @@ div#rules-editor.card.card-body th(scope="col") div - div.inline Variable + div.inline Target div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.variable) diff --git a/client/templates/includes/rulesViewer.pug b/client/templates/includes/rulesViewer.pug index 487fd54459..1451df8482 100644 --- a/client/templates/includes/rulesViewer.pug +++ b/client/templates/includes/rulesViewer.pug @@ -12,7 +12,7 @@ div#rules-viewer.card.card-body tr th.col-md-3-view(scope="col") Name th.col-md-3-view(scope="col") Type - th.col-md-3-view(scope="col") Variable + th.col-md-3-view(scope="col") Target th.col-md-3-view(scope="col") Formula if this.containsMdlWithAnn th.col-md-3-view(scope="col") Annotation From 79876c58d15524a93e5c9e92c6a8fbc27ac2cb47 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 15 Oct 2020 11:13:56 -0400 Subject: [PATCH 11/24] Adjusted css for the main div to only have the margin if the view port width is 768px or larger. Moved the .sidebar-sticky css block into the @media block. --- client/styles/styles.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/styles/styles.css b/client/styles/styles.css index f15e1494f1..df0dc2b42f 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -16,25 +16,29 @@ img.quickstart { .sidebar { padding-top: 20px; margin-top: 48px; - padding-left: 10px } +[role="main"] { + padding-top: 20px; +} + @media (min-width: 768px) { + [role="main"] { + margin-top: 48px; + } .sidebar { min-height: 8em; } + .sidebar-sticky { + position: fixed; + } .nav-flex-column { -ms-flex-direction: column !important; flex-direction: column !important; } } -[role="main"] { - padding-top: 20px; - margin-top: 48px; -} - .inline{ display: inline-block; } @@ -203,10 +207,6 @@ input[type="file"]::-ms-browse { font-size: 16px; } -.sidebar-sticky { - position: fixed; -} - .tools { min-width: 12em; } From 6444102b4353e358b6f987d97fe138355952269b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 15 Oct 2020 12:48:23 -0400 Subject: [PATCH 12/24] Fixed the modal backdrop and the modal position. Re-design the events viewer to better fit smaller screens. --- client/styles/styles.css | 14 +++++++++++++ client/templates/includes/eventsViewer.pug | 8 ++------ client/templates/includes/viewEvents.pug | 24 +++++++++++----------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/client/styles/styles.css b/client/styles/styles.css index df0dc2b42f..d571d3d4a6 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -314,6 +314,14 @@ input[type="file"]::-ms-browse { width: 75%; min-width: 487.5px; max-width: 750px; + left: 0; + right: 0; + margin: 0.5rem auto; +} + +.modal-backdrop { + width: 100%; + height: 100%; } .modal-content { @@ -602,3 +610,9 @@ span.checkbox { #explore-model-msg { display: none; } + +.event-adv-header { + border-bottom-color: rgb(222, 226, 230); + border-bottom-style: solid; + border-left-width: 1px; +} diff --git a/client/templates/includes/eventsViewer.pug b/client/templates/includes/eventsViewer.pug index 81b2da4a0c..e2354b9340 100644 --- a/client/templates/includes/eventsViewer.pug +++ b/client/templates/includes/eventsViewer.pug @@ -15,15 +15,11 @@ div#events-viewer.card.card-body th(scope="col") Name - th(scope="col") Delay - - th(scope="col") Priority - - th(scope="col") Triggger + th(scope="col") Triggger Expression th(scope="col") Assignments - th(scope="col") Use Values From + th(scope="col") Advanced if this.containsMdlWithAnn th.col-md-3-view(scope="col") Annotation diff --git a/client/templates/includes/viewEvents.pug b/client/templates/includes/viewEvents.pug index 44f07db6e7..b6aa236271 100644 --- a/client/templates/includes/viewEvents.pug +++ b/client/templates/includes/viewEvents.pug @@ -1,14 +1,16 @@ tr - td=this.model.name + td: div.name=this.model.name - td=this.delay + td=this.model.triggerExpression - td=this.model.priority + td: div(data-hook="assignment-viewer") + + td - td + div="Delay: "+this.delay - div="Expression: " + this.model.triggerExpression + div="Priority: "+this.model.priority div @@ -22,22 +24,20 @@ tr input(type="checkbox", id="persistent", data-hook="event-trigger-persistent" disabled) - td: div(data-hook="assignment-viewer") - - td + div.event-adv-header Use Values From div - span.inline.horizontal-space(for="trigger-time") Trggier Time - input(type="radio", id="trigger-time", name="use-values-from" data-hook="trigger-time" disabled) - div + span.inline.horizontal-space(for="trigger-time") Trggier Time - span.inline.horizontal-space(for="assignment-time") Assignment Time + div input(type="radio", id="assignment-time", name="use-values-from" data-hook="assignment-time" disabled) + span.inline.horizontal-space(for="assignment-time") Assignment Time + if this.model.annotation td: div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation") From 469ab668a1ec8eae210c95776ec897d2aae6988b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 15 Oct 2020 15:12:24 -0400 Subject: [PATCH 13/24] Added a check to disable the new model modals ok button if the input field is empty. Added function to check if a model already exists under the name of the proposed new name. --- client/pages/project-manager.js | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js index efa1a267f3..7cb70bef63 100644 --- a/client/pages/project-manager.js +++ b/client/pages/project-manager.js @@ -278,19 +278,40 @@ let ProjectManager = PageView.extend({ let okBtn = document.querySelector('#newModalModel .ok-model-btn'); let input = document.querySelector('#newModalModel #modelNameInput'); okBtn.addEventListener('click', function (e) { + modal.modal('hide') if (Boolean(input.value)) { let modelName = input.value.split("/").pop() + '.mdl'; let message = modelName.split(".")[0] !== input.value ? "Warning: Models are saved directly in StochSS Projects and cannot be saved to the "+input.value.split("/")[0]+" directory in the project.

Your model will be saved directly in your project.

" : "" let modelPath = path.join(self.projectPath, modelName) - let endpoint = path.join(app.getBasePath(), app.routePrefix, 'models/edit')+"?path="+modelPath+"&message="+message + let queryString = "?path="+modelPath+"&message="+message + let endpoint = path.join(app.getBasePath(), app.routePrefix, 'models/edit')+queryString + let existEP = path.join(app.getApiPath(), "model/exists")+queryString if(message){ - modal.modal('hide') let warningModal = $(modals.newProjectModelWarningHtml(message)).modal() let yesBtn = document.querySelector('#newProjectModelWarningModal .yes-modal-btn'); - yesBtn.addEventListener('click', function (e) {window.location.href = endpoint;}) + yesBtn.addEventListener('click', function (e) { + warningModal.modal('hide') + xhr({uri: existEP, json: true}, function (err, response, body) { + if(body.exists) { + let title = "Model Already Exists" + let message = "A model already exists with that name" + let errorModel = $(modals.newProjectOrWorkflowGroupErrorHtml(title, message)).modal() + }else{ + window.location.href = endpoint + } + }) + }) }else{ - window.location.href = endpoint; + xhr({uri: existEP, json: true}, function (err, response, body) { + if(body.exists) { + let title = "Model Already Exists" + let message = "A model already exists with that name" + let errorModel = $(modals.newProjectOrWorkflowGroupErrorHtml(title, message)).modal() + }else{ + window.location.href = endpoint + } + }); } } }); @@ -298,7 +319,7 @@ let ProjectManager = PageView.extend({ var endErrMsg = document.querySelector('#newModalModel #modelNameInputEndCharError') var charErrMsg = document.querySelector('#newModalModel #modelNameInputSpecCharError') let error = self.validateName(input.value) - okBtn.disabled = error !== "" + okBtn.disabled = error !== "" || input.value.trim() === "" charErrMsg.style.display = error === "both" || error === "special" ? "block" : "none" endErrMsg.style.display = error === "both" || error === "forward" ? "block" : "none" }); From ae731f066438f46f7b9b22d374b5999683de1219 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Thu, 15 Oct 2020 16:37:20 -0400 Subject: [PATCH 14/24] Fixed typos with event viewer. --- client/templates/includes/eventsViewer.pug | 2 +- client/templates/includes/viewEvents.pug | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/templates/includes/eventsViewer.pug b/client/templates/includes/eventsViewer.pug index e2354b9340..bf9bed0f61 100644 --- a/client/templates/includes/eventsViewer.pug +++ b/client/templates/includes/eventsViewer.pug @@ -15,7 +15,7 @@ div#events-viewer.card.card-body th(scope="col") Name - th(scope="col") Triggger Expression + th(scope="col") Trigger th(scope="col") Assignments diff --git a/client/templates/includes/viewEvents.pug b/client/templates/includes/viewEvents.pug index b6aa236271..a26dfb151f 100644 --- a/client/templates/includes/viewEvents.pug +++ b/client/templates/includes/viewEvents.pug @@ -30,7 +30,7 @@ tr input(type="radio", id="trigger-time", name="use-values-from" data-hook="trigger-time" disabled) - span.inline.horizontal-space(for="trigger-time") Trggier Time + span.inline.horizontal-space(for="trigger-time") Trigger Time div From edaf665b16fb7ee0544555bb00a1134dac33373f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 14:07:36 -0400 Subject: [PATCH 15/24] Added a button the next to the 'Show/Hide Preview' button that provides the plotly download option in a more convenient location. Adjusted styling and display function to only display the button when a preview has been generated. Added function to hook into the plotly 'download as a png' function. --- client/pages/model-editor.js | 8 +++++++- client/styles/styles.css | 6 ++---- client/templates/pages/modelEditor.pug | 19 +++++++++++++++---- client/views/model-state-buttons.js | 3 +-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 96e2af251d..dfb25be1e8 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -54,7 +54,8 @@ let ModelEditor = PageView.extend({ }, 'click [data-hook=collapse-me-advanced-section]' : 'changeCollapseButtonText', 'click [data-hook=project-breadcrumb-link]' : 'handleProjectBreadcrumbClick', - 'click [data-hook=toggle-preview-plot]' : 'togglePreviewPlot' + 'click [data-hook=toggle-preview-plot]' : 'togglePreviewPlot', + 'click [data-hook=download-png]' : 'clickDownloadPNGButton' }, initialize: function (attrs, options) { PageView.prototype.initialize.apply(this, arguments); @@ -309,6 +310,11 @@ let ModelEditor = PageView.extend({ plot.style.display = "block" button.innerText = "Hide Preview" $(this.queryByHook('explore-model-msg')).css('display', 'block'); + }, + clickDownloadPNGButton: function (e) { + let pngButton = $('div[data-hook=model-run-container] a[data-title*="Download plot as a png"]')[0] + console.log(pngButton) + pngButton.click() } }); diff --git a/client/styles/styles.css b/client/styles/styles.css index d571d3d4a6..a30a7c6792 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -596,11 +596,9 @@ span.checkbox { padding: 0px 5px; } -.preview-close { - position: relative; +.preview-buttons { display: none; - float: right; - top: 8px; + height: 48px; } .model-state-buttons { diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index 7ff528c0f5..66901d3330 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -69,9 +69,20 @@ section.page div - div.inline(data-hook="toggle-preview-plot-container") + div.preview-buttons(data-hook="preview-plot-buttons") - button.btn.btn-outline-secondary.box-shadow.preview-close(data-hook="toggle-preview-plot") Hide Preview - - div.model-state-buttons.inline(data-hook="model-state-buttons-container") + button.btn.btn-outline-secondary.box-shadow.inline.mx-2(data-hook="toggle-preview-plot") Hide Preview + + button.btn.btn-outline-secondary.box-shadow.inline.dropdown-toggle( + id="preview-options", + data-toggle="dropdown", + aria-haspopup="true", + aria-expanded="false", + type="button" + ) Preview Options + + ul.dropdown-menu(aria-labelledby="preview-options") + li.dropdown-item(data-hook="download-png") Download as PNG + + div.model-state-buttons(data-hook="model-state-buttons-container") diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 58e1a9f0df..b09131063b 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -185,8 +185,7 @@ module.exports = View.extend({ this.ran(true) el = this.parent.queryByHook('model-run-container'); Plotly.newPlot(el, data); - $(this.parent.queryByHook('toggle-preview-plot-container')).css('height', '50px') - $(this.parent.queryByHook('toggle-preview-plot')).css('display', 'block') + $(this.parent.queryByHook('preview-plot-buttons')).css('display', 'inline-block') $(this.parent.queryByHook('explore-model-msg')).css('display', 'block'); window.scrollTo(0, document.body.scrollHeight) }, From 96079c0058d77717e93cea780a174e826bcb2dec Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 14:16:39 -0400 Subject: [PATCH 16/24] Updated the tooltips for the model component names. Fixed spacing around preview buttons. --- client/templates/pages/modelEditor.pug | 2 +- client/tooltips.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index 66901d3330..ee9e765e79 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -69,7 +69,7 @@ section.page div - div.preview-buttons(data-hook="preview-plot-buttons") + div.mt-1.preview-buttons(data-hook="preview-plot-buttons") button.btn.btn-outline-secondary.box-shadow.inline.mx-2(data-hook="toggle-preview-plot") Hide Preview diff --git a/client/tooltips.js b/client/tooltips.js index c86a02e088..23cb38ed53 100644 --- a/client/tooltips.js +++ b/client/tooltips.js @@ -18,7 +18,7 @@ along with this program. If not, see . module.exports = { speciesEditor: { - name: "Names for variables, parameters, reactions, events, and rules must be unique.", + name: "Unique identifier for Variable. Cannot share a name with other model components.", initialValue: "Initial population of a variables.", @@ -37,7 +37,7 @@ module.exports = { "at which variables will be represented as Concentration." }, parametersEditor: { - name: "Names for variables, parameters, reactions, events, and rules must be unique.", + name: "Unique identifier for Parameter. Cannot share a name with other model components.", expression: "A parameter value.", @@ -46,7 +46,7 @@ module.exports = { remove: "A parameter may only be removed if it is not used in any reaction, event assignment, or rule." }, reactionsEditor: { - name: "Names for variables, parameters, reactions, events, and rules must be unique.", + name: "Unique identifier for Reaction. Cannot share a name with other model components.", annotation: "An optional note about the reaction.", @@ -59,7 +59,7 @@ module.exports = { product: "The variables that are created by the reaction event, with stoichiometry.", }, eventsEditor: { - name: "Names for variables, parameters, reactions, events, and rules must be unique.", + name: "Unique identifier for Event. Cannot share a name with other model components.", annotation: "An optional note about an event.", @@ -90,7 +90,7 @@ module.exports = { "upon event execution." }, rulesEditor: { - name: "Names for variables, parameters, reactions, events, and rules must be unique.", + name: "Unique identifier for Rule. Cannot share a name with other model components.", type: "Assignment Rules: An assignment rule describes a change to a Variables or Parameter as a function whose left-hand side is a scalar (i.e. x = f(V), where V is a "+ "vector of symbols, not including x).
Rate Rules: A rate rule describes a change to a Variables or Parameter as a function whose left-hand side is a rate of "+ From 65c1eb352a4e1aaa4d19c94092660e232d0b27aa Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 14:50:08 -0400 Subject: [PATCH 17/24] replaced the 'Run Preview' and 'New Workflow Using Model' buttons with a 'Simulate' dropdown button. Added function the navigates the user directly to the workflow manager page if the user selects 'Ensemble Simulation' or 'Parameter Sweep' options in the new button. --- client/templates/includes/modelStateButtons.pug | 15 +++++++++++++-- client/views/model-state-buttons.js | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/client/templates/includes/modelStateButtons.pug b/client/templates/includes/modelStateButtons.pug index 33f8d2fc80..a9e69c9938 100644 --- a/client/templates/includes/modelStateButtons.pug +++ b/client/templates/includes/modelStateButtons.pug @@ -12,9 +12,20 @@ div.mdl-edit-btn button.btn.btn-primary.box-shadow(data-hook="save") Save - button.btn.btn-primary.box-shadow(data-hook="run") Run Preview + button.btn.btn-primary.box-shadow.dropdown-toggle( + id="simulate-model", + data-toggle="dropdown", + aria-haspopup="true", + aria-expanded="false", + type="button" + ) Simulate - button.btn.btn-primary.box-shadow(data-hook="new-workflow") New Workflow Using Model + ul.dropdown-menu(aria-labelledby="preview-options") + li.dropdown-item(data-hook="run") Preview + li.dropdown-divider + li.dropdown-item(id="stochss-es" data-hook="stochss-es") Ensemble Simulation + li.dropdown-item(id="stochss-ps" data-hook="stochss-ps") Parameter Sweep + li.dropdown-item(data-hook="new-workflow") Jupyter Notebook button.btn.btn-primary.box-shadow(data-hook="return-to-project-btn" style="display: none;") Return to Project diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index b09131063b..8b1347f32d 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -35,6 +35,8 @@ module.exports = View.extend({ 'click [data-hook=run]' : 'clickRunHandler', 'click [data-hook=new-workflow]' : 'clickNewWorkflowHandler', 'click [data-hook=return-to-project-btn]' : 'clickReturnToProjectHandler', + "click [data-hook=stochss-es]" : "handleEnsembleSimulationClick", + "click [data-hook=stochss-ps]" : "handleParameterSweepClick" }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); @@ -189,4 +191,16 @@ module.exports = View.extend({ $(this.parent.queryByHook('explore-model-msg')).css('display', 'block'); window.scrollTo(0, document.body.scrollHeight) }, + handleEnsembleSimulationClick: function (e) { + this.launchStochssWorkflow("gillespy") + }, + handleParameterSweepClick: function (e) { + this.launchStochssWorkflow("parameterSweep") + }, + launchStochssWorkflow: function (type) { + let parentPath = path.join(path.dirname(this.model.directory), "WorkflowGroup1.wkgp") + let queryString = "?type=" + type + "&path=" + this.model.directory + "&parentPath=" + parentPath + let endpoint = path.join(app.getBasePath(), "stochss/workflow/edit")+queryString + window.location.href = endpoint + } }); From b21c1a5e548c2fde9d5ce8ae0c771bfb6c2ec8d1 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 15:55:14 -0400 Subject: [PATCH 18/24] updated the togglePreviewWorkflowBtn function to use the new 'valid' session variable. Added function to save models prior to navigating to the workflow manager page. Added check to only add the workflow group to the parentPath if the model is in a project. --- .../templates/includes/modelStateButtons.pug | 1 + client/views/model-state-buttons.js | 41 +++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/client/templates/includes/modelStateButtons.pug b/client/templates/includes/modelStateButtons.pug index a9e69c9938..9f77902f92 100644 --- a/client/templates/includes/modelStateButtons.pug +++ b/client/templates/includes/modelStateButtons.pug @@ -14,6 +14,7 @@ div.mdl-edit-btn button.btn.btn-primary.box-shadow.dropdown-toggle( id="simulate-model", + data-hook="simulate-model", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false", diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index 52819f2dff..a6af6f78bd 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -30,13 +30,6 @@ var template = require('../templates/includes/modelStateButtons.pug'); module.exports = View.extend({ template: template, - bindings: { - 'model.invalid': { - hook: 'run', - type: 'booleanAttribute', - name: 'disabled', - }, - }, events: { 'click [data-hook=save]' : 'clickSaveHandler', 'click [data-hook=run]' : 'clickRunHandler', @@ -48,6 +41,7 @@ module.exports = View.extend({ initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); this.model.on('change', this.togglePreviewWorkflowBtn, this) + this.model.parameters.on('add remove', this.togglePreviewWorkflowBtn, this) }, render: function () { View.prototype.render.apply(this, arguments); @@ -90,12 +84,20 @@ module.exports = View.extend({ }) }, togglePreviewWorkflowBtn: function () { - var numSpecies = this.model.species.length; - var numReactions = this.model.reactions.length - var numEvents = this.model.eventsCollection.length - var numRules = this.model.rules.length - let disabled = !(this.model.valid && numSpecies && (numReactions || numEvents || numRules)) - $(this.queryByHook('run')).prop('disabled', disabled) + let disabled = !this.model.valid + $(this.queryByHook('simulate-model')).prop('disabled', disabled) + if(this.model.valid) { + if(this.model.parameters.length <= 0) { + $(this.queryByHook("stochss-ps")).addClass("disabled") + }else{ + $(this.queryByHook("stochss-ps")).removeClass("disabled") + } + $(".disabled").click(function(event) { + event.preventDefaults(); + event.stopPropagation(); + return false; + }); + } }, saveModel: function (cb) { this.saving(); @@ -208,9 +210,16 @@ module.exports = View.extend({ this.launchStochssWorkflow("parameterSweep") }, launchStochssWorkflow: function (type) { - let parentPath = path.join(path.dirname(this.model.directory), "WorkflowGroup1.wkgp") - let queryString = "?type=" + type + "&path=" + this.model.directory + "&parentPath=" + parentPath + let queryString = "?type=" + type + "&path=" + this.model.directory + if(this.model.directory.includes('.proj')) { + var parentPath = path.join(path.dirname(this.model.directory), "WorkflowGroup1.wkgp") + }else{ + var parentPath = path.dirname(this.model.directory) + } + queryString += "&parentPath=" + parentPath let endpoint = path.join(app.getBasePath(), "stochss/workflow/edit")+queryString - window.location.href = endpoint + this.saveModel(function () { + window.location.href = endpoint + }); } }); From 58c682a7c2adf37d7b8af884022da895c9da4081 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 16:23:22 -0400 Subject: [PATCH 19/24] Moved 'volume' from the model settings model to the model. Setup backwards compatibility for volume existing in the model settings. --- client/models/model-settings.js | 4 +--- client/models/model.js | 4 +++- stochss/handlers/models.py | 3 +++ stochss/handlers/util/generate_notebook_cells.py | 5 ++++- stochss/handlers/util/run_model.py | 2 +- stochss_templates/nonSpatialModelTemplate.json | 4 ++-- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/client/models/model-settings.js b/client/models/model-settings.js index 37a2f126c4..13247996f3 100644 --- a/client/models/model-settings.js +++ b/client/models/model-settings.js @@ -22,8 +22,7 @@ var State = require('ampersand-state'); module.exports = State.extend({ props: { endSim: 'number', - timeStep: 'number', - volume: 'number' + timeStep: 'number' }, initialize: function (attrs, options) { State.prototype.initialize.apply(this, arguments) @@ -31,7 +30,6 @@ module.exports = State.extend({ validate: function () { if(this.endSim == 0 || isNaN(this.endSim)) return false; if(this.timeStep == 0 || isNaN(this.timeStep)) return false; - if(this.volume == 0 || isNaN(this.volume)) return false; return true; } }); \ No newline at end of file diff --git a/client/models/model.js b/client/models/model.js index 47f2c14463..79f346d099 100644 --- a/client/models/model.js +++ b/client/models/model.js @@ -40,7 +40,8 @@ module.exports = Model.extend({ is_spatial: 'boolean', defaultID: 'number', defaultMode: 'string', - annotation: 'string' + annotation: 'string', + volume: 'number' }, collections: { species: Species, @@ -67,6 +68,7 @@ module.exports = Model.extend({ Model.prototype.initialize.apply(this, arguments); }, validateModel: function () { + if(this.volume == 0 || isNaN(this.volume)) return false; if(this.species.length <= 0) return false; if(this.reactions.length <= 0 && this.eventsCollection.length <= 0 && this.rules.length <= 0) return false if(this.modelSettings.validate() === false) return false; diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index 913e43d778..e707cc4ba3 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -68,6 +68,9 @@ async def get(self): if os.path.exists(full_path): with open(full_path, 'r') as f: data = json.load(f) + if "volume" not in data.keys(): + data['volume'] = data['modelSettings']['volume'] + del data['modelSettings']['volume'] log.debug("Contents of the json file: {0}".format(data)) if full_path.endswith(".mdl"): self.update_model_data(data) diff --git a/stochss/handlers/util/generate_notebook_cells.py b/stochss/handlers/util/generate_notebook_cells.py index bace32ab2f..84494761fa 100644 --- a/stochss/handlers/util/generate_notebook_cells.py +++ b/stochss/handlers/util/generate_notebook_cells.py @@ -199,12 +199,15 @@ def generate_model_cell(json_data, name): raise Exception('Spatial not yet implemented.') else: # Non-Spatial + if "volume" not in json_data.keys(): + json_data['volume'] = json_data['modelSettings']['volume'] + model_cell += 'class {0}(Model):\n'.format(name) model_cell += ' def __init__(self, parameter_values=None):\n' padding = ' ' model_cell += padding + 'Model.__init__(self, name="{0}")\n'.format(name) model_cell += padding + 'self.volume = {0}\n'.format( - json_data['modelSettings']['volume']) + json_data['volume']) model_cell += create_parameter_strings(json_data, padding) model_cell += create_species_strings(json_data, padding) diff --git a/stochss/handlers/util/run_model.py b/stochss/handlers/util/run_model.py index d8c9f1ca7e..d593b6fdb8 100755 --- a/stochss/handlers/util/run_model.py +++ b/stochss/handlers/util/run_model.py @@ -238,7 +238,7 @@ def __init__(self, data, is_ode): name = data['name'] timeStep = (data['modelSettings']['timeStep']) endSim = data['modelSettings']['endSim'] - volume = data['modelSettings']['volume'] + volume = data['volume'] self.species = list(map(lambda s: self.build_specie(s, is_ode), data['species'])) self.parameters = list(map(lambda p: self.build_parameter(p), data['parameters'])) self.reactions = list(map(lambda r: self.build_reaction(r, self.parameters), data['reactions'])) diff --git a/stochss_templates/nonSpatialModelTemplate.json b/stochss_templates/nonSpatialModelTemplate.json index 894fb677c0..0f9d0838d7 100644 --- a/stochss_templates/nonSpatialModelTemplate.json +++ b/stochss_templates/nonSpatialModelTemplate.json @@ -3,10 +3,10 @@ "defaultID": 1, "defaultMode": "", "annotation": "", + "volume": 1, "modelSettings": { "endSim": 20, - "timeStep": 0.05, - "volume": 1 + "timeStep": 0.05 }, "meshSettings": { "count": 2 From 9e8e72848d177470bea5300d37f743ab83923c6f Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 17:10:15 -0400 Subject: [PATCH 20/24] Moved the volume input field to the model editor and added a 'System Volume: ' label. Moved the volume div for the viewer to the model viewer. Added check to hide volume is the model has a default mode of continuous. Removed the explore model message and all functions that manipulated it. --- client/pages/model-editor.js | 27 ++++++++++++++++--- client/styles/styles.css | 4 --- client/templates/includes/modelSettings.pug | 8 ------ .../includes/modelSettingsViewer.pug | 4 --- client/templates/includes/modelViewer.pug | 2 ++ client/templates/pages/modelEditor.pug | 10 ++++--- client/views/model-settings.js | 15 ----------- client/views/model-state-buttons.js | 2 -- client/views/species-editor.js | 5 ++++ 9 files changed, 36 insertions(+), 41 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 13715d412f..17c19a327a 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -21,9 +21,11 @@ var $ = require('jquery'); let path = require('path'); //support files var app = require('../app'); -var modals = require('../modals') +var modals = require('../modals'); +var tests = require('../views/tests'); //views var PageView = require('../pages/base'); +var InputView = require('../views/input'); var MeshEditorView = require('../views/mesh-editor'); var SpeciesEditorView = require('../views/species-editor'); var SpeciesViewer = require('../views/species-viewer'); @@ -209,6 +211,7 @@ let ModelEditor = PageView.extend({ this.renderReactionsView(); this.renderEventsView(); this.renderRulesView(); + this.renderSystemVolumeView(); this.registerRenderSubview(sbmlComponentView, 'sbml-component-container'); this.registerRenderSubview(modelSettings, 'model-settings-container'); this.registerRenderSubview(this.modelStateButtons, 'model-state-buttons-container'); @@ -281,6 +284,25 @@ let ModelEditor = PageView.extend({ } this.registerRenderSubview(this.rulesEditor, 'rules-editor-container'); }, + renderSystemVolumeView: function () { + if(this.systemVolumeView) { + this.systemVolumeView.remove() + } + this.systemVolumeView = new InputView ({ + parent: this, + required: true, + name: 'system-volume', + label: 'System Volume: ', + tests: tests.valueTests, + modelKey: 'volume', + valueType: 'number', + value: this.model.volume, + }); + this.registerRenderSubview(this.systemVolumeView, 'volume') + if(this.model.defaultMode === "continuous") { + $(this.queryByHook("system-volume-container")).collapse("hide") + } + }, changeCollapseButtonText: function (e) { let source = e.target.dataset.hook let collapseContainer = $(this.queryByHook(source).dataset.target) @@ -303,18 +325,15 @@ let ModelEditor = PageView.extend({ let button = this.queryByHook("toggle-preview-plot") plot.style.display = "none" button.innerText = "Show Preview" - $(this.queryByHook('explore-model-msg')).css('display', 'none'); }, openPlot: function () { let plot = this.queryByHook("model-run-container") let button = this.queryByHook("toggle-preview-plot") plot.style.display = "block" button.innerText = "Hide Preview" - $(this.queryByHook('explore-model-msg')).css('display', 'block'); }, clickDownloadPNGButton: function (e) { let pngButton = $('div[data-hook=model-run-container] a[data-title*="Download plot as a png"]')[0] - console.log(pngButton) pngButton.click() } }); diff --git a/client/styles/styles.css b/client/styles/styles.css index d974873cfc..9d92e850fd 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -605,10 +605,6 @@ span.checkbox { float: right; } -#explore-model-msg { - display: none; -} - .event-adv-header { border-bottom-color: rgb(222, 226, 230); border-bottom-style: solid; diff --git a/client/templates/includes/modelSettings.pug b/client/templates/includes/modelSettings.pug index 3ae8a573a2..cb3c785019 100644 --- a/client/templates/includes/modelSettings.pug +++ b/client/templates/includes/modelSettings.pug @@ -24,12 +24,6 @@ div#preview-settings.card.card-body div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.timeUnits) - th(scope="col") - div - div.inline Volume - - div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.volume) - tbody tr @@ -37,5 +31,3 @@ div#preview-settings.card.card-body td: div(data-hook="preview-time") td: div(data-hook="time-units") - - td: div(data-hook="volume") \ No newline at end of file diff --git a/client/templates/includes/modelSettingsViewer.pug b/client/templates/includes/modelSettingsViewer.pug index 4e7a260a05..22fc72168c 100644 --- a/client/templates/includes/modelSettingsViewer.pug +++ b/client/templates/includes/modelSettingsViewer.pug @@ -17,8 +17,6 @@ div#model-settings-viewer.card.card-body th(scope="col") Sample Frequency - th(scope="col") Volume - tbody tr @@ -26,5 +24,3 @@ div#model-settings-viewer.card.card-body td=this.model.endSim td=this.model.timeStep - - td=this.model.volume \ No newline at end of file diff --git a/client/templates/includes/modelViewer.pug b/client/templates/includes/modelViewer.pug index a40e0504e7..d4e117dcf8 100644 --- a/client/templates/includes/modelViewer.pug +++ b/client/templates/includes/modelViewer.pug @@ -17,4 +17,6 @@ div.card.card-body div(data-hook="rules-viewer-container") + div.card.card-body="System Volume: "+this.model.volume + div(data-hook="model-settings-viewer-container") \ No newline at end of file diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index ee9e765e79..f9e4efb999 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -45,6 +45,12 @@ section.page div(data-hook="sbml-component-container") + div.card.card-body.collapse.show(data-hook="system-volume-container") + + p System volume affects custom propensities or stochastic reactions with two reactants. The volume sets the implicit parameter 'vol' which can be used in custom propensity functions. A single well-mixed volume is assumed. Compartments are not currently supported. + + div(data-hook="volume") + div(data-hook="model-settings-container") div(style="height:425px;") @@ -53,10 +59,6 @@ section.page div(data-hook="model-run-container") - div(id="explore-model-msg" data-hook="explore-model-msg") - - p.text-info You can explore this model further by clicking New Workflow Using Model - div.spinner-border(data-hook="plot-loader") div.collapse(data-hook="model-timeout-message") diff --git a/client/views/model-settings.js b/client/views/model-settings.js index e5297b4e79..26ff96fcba 100644 --- a/client/views/model-settings.js +++ b/client/views/model-settings.js @@ -85,20 +85,5 @@ module.exports = View.extend({ }); }, }, - inputVolume: { - hook: 'volume', - prepareView: function (el) { - return new InputView ({ - parent: this, - required: true, - name: 'volume', - label: '', - tests: tests.valueTests, - modelKey: 'volume', - valueType: 'number', - value: this.model.volume, - }); - }, - }, }, }); \ No newline at end of file diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js index a6af6f78bd..e4fc4c2c27 100644 --- a/client/views/model-state-buttons.js +++ b/client/views/model-state-buttons.js @@ -56,7 +56,6 @@ module.exports = View.extend({ clickRunHandler: function (e) { $(this.parent.queryByHook('model-run-error-container')).collapse('hide'); $(this.parent.queryByHook('model-timeout-message')).collapse('hide'); - $(this.parent.queryByHook('explore-model-msg')).css('display', 'none'); var el = this.parent.queryByHook('model-run-container'); Plotly.purge(el) $(this.parent.queryByHook('preview-plot-buttons')).css("display", "none"); @@ -196,7 +195,6 @@ module.exports = View.extend({ el = this.parent.queryByHook('model-run-container'); Plotly.newPlot(el, data); $(this.parent.queryByHook('preview-plot-buttons')).css('display', 'inline-block') - $(this.parent.queryByHook('explore-model-msg')).css('display', 'block'); let plotBtn = $(this.parent.queryByHook('toggle-preview-plot')) if(plotBtn.text() === "Show Preview") { plotBtn.text("Hide Preview") diff --git a/client/views/species-editor.js b/client/views/species-editor.js index 8297d08ea7..51b355b806 100644 --- a/client/views/species-editor.js +++ b/client/views/species-editor.js @@ -135,6 +135,11 @@ module.exports = View.extend({ }, setAllSpeciesModes: function (defaultMode, cb) { this.collection.parent.defaultMode = defaultMode; + if(defaultMode === "continuous") { + $(this.parent.queryByHook("system-volume-container")).collapse("hide") + }else{ + $(this.parent.queryByHook("system-volume-container")).collapse("show") + } this.collection.map(function (specie) { specie.mode = defaultMode cb(specie) From 43fd1800df09d8eb0d68e761379fa4f5c90ed370 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 19 Oct 2020 17:41:15 -0400 Subject: [PATCH 21/24] Fixed bug that was preventing the collapse button text from updating when the collapse button for the events viewer was clicked --- client/views/events-viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/events-viewer.js b/client/views/events-viewer.js index fe561d9c5b..c9e3b35611 100644 --- a/client/views/events-viewer.js +++ b/client/views/events-viewer.js @@ -46,7 +46,7 @@ module.exports = View.extend({ switchToEditMode: function (e) { this.parent.renderEventsView("edit", true); }, - changeSettingsCollapseButtonText: function () { + changeSettingsCollapseButtonText: function (e) { let source = e.target.dataset.hook let collapseContainer = $(this.queryByHook(source).dataset.target) if(!collapseContainer.length || !collapseContainer.attr("class").includes("collapsing")) { From f76b49caf13a0711e645677b1b62b4e85ba4868c Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 20 Oct 2020 10:52:28 -0400 Subject: [PATCH 22/24] Adjusted style for page columns to be consistent for all pages. --- client/styles/styles.css | 17 +++++++++++++++++ client/templates/body.pug | 4 ++-- client/templates/pages/projectBrowser.pug | 2 +- client/templates/pages/projectManager.pug | 2 +- client/templates/pages/quickstart.pug | 4 ++-- client/templates/pages/workflowSelection.pug | 2 +- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/client/styles/styles.css b/client/styles/styles.css index 9d92e850fd..0c403ec5f1 100644 --- a/client/styles/styles.css +++ b/client/styles/styles.css @@ -39,6 +39,19 @@ img.quickstart { } } +@media (min-width: 1450px) { + .col-xxl-1 { + -ms-flex: 0 0 12.5%; + flex: 0 0 12.5%; + max-width: 12.5%; + } + .col-xxl-6 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; + } +} + .inline{ display: inline-block; } @@ -610,3 +623,7 @@ span.checkbox { border-bottom-style: solid; border-left-width: 1px; } + +#model-run-margin { + height: 350px; +} diff --git a/client/templates/body.pug b/client/templates/body.pug index 30cb6ced6f..cb1641d077 100644 --- a/client/templates/body.pug +++ b/client/templates/body.pug @@ -32,7 +32,7 @@ body div.container-fluid div.row - div.col-xs-12.col-md-2 + div.col-sm-12.col-md-2.col-xxl-1 nav.sidebar.d-md-block div.sidebar-sticky.tools ul.nav.nav-flex-column @@ -51,4 +51,4 @@ body li.nav-item div: a.nav-link(href="stochss/quickstart", title="Quickstart") Tutorial - main.col-xs-12.col-md-10.body(role="main"): div.container-fluid(data-hook="page-container") + main.col-sm-12.col-md-10.col-xl-9.col-xxl-6.body(role="main"): div.container-fluid(data-hook="page-container") diff --git a/client/templates/pages/projectBrowser.pug b/client/templates/pages/projectBrowser.pug index fda8ef1435..9fb26fdafc 100644 --- a/client/templates/pages/projectBrowser.pug +++ b/client/templates/pages/projectBrowser.pug @@ -1,4 +1,4 @@ -section.page.col-md-10 +section.page h2 Project Browser diff --git a/client/templates/pages/projectManager.pug b/client/templates/pages/projectManager.pug index fa945e6aef..6781f04051 100644 --- a/client/templates/pages/projectManager.pug +++ b/client/templates/pages/projectManager.pug @@ -4,7 +4,7 @@ section.page h2.inline(id="page-title" data-hook="page-title")= "Project: "+this.projectName - div.col-md-12.col-lg-10.no-gutters-padding + div.no-gutters-padding if !this.annotation div.verticle-space-2 diff --git a/client/templates/pages/quickstart.pug b/client/templates/pages/quickstart.pug index d4099cfb51..f673e2e131 100644 --- a/client/templates/pages/quickstart.pug +++ b/client/templates/pages/quickstart.pug @@ -1,9 +1,9 @@ section.page - div.row.no-gutters + div.no-gutters - div.col-md-10 + div h2 Tutorial diff --git a/client/templates/pages/workflowSelection.pug b/client/templates/pages/workflowSelection.pug index c4de55d0b6..312b277be6 100644 --- a/client/templates/pages/workflowSelection.pug +++ b/client/templates/pages/workflowSelection.pug @@ -1,4 +1,4 @@ -section.page.col-md-10 +section.page h3="Workflow Selection for " + this.modelFile From 3c7b56159d7229be460df58c2396d8603af2d058 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 20 Oct 2020 12:19:57 -0400 Subject: [PATCH 23/24] Added section header for system volume section. Removed 'System' from system volume input label. Repositioned the return to project button to the left of the simulate button. --- client/pages/model-editor.js | 5 +++-- client/templates/includes/modelStateButtons.pug | 7 +++---- client/templates/pages/modelEditor.pug | 13 +++++++++++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js index 17c19a327a..5284b4cade 100644 --- a/client/pages/model-editor.js +++ b/client/pages/model-editor.js @@ -57,7 +57,8 @@ let ModelEditor = PageView.extend({ 'click [data-hook=collapse-me-advanced-section]' : 'changeCollapseButtonText', 'click [data-hook=project-breadcrumb-link]' : 'handleProjectBreadcrumbClick', 'click [data-hook=toggle-preview-plot]' : 'togglePreviewPlot', - 'click [data-hook=download-png]' : 'clickDownloadPNGButton' + 'click [data-hook=download-png]' : 'clickDownloadPNGButton', + 'click [data-hook=collapse-system-volume]' : 'changeCollapseButtonText' }, initialize: function (attrs, options) { PageView.prototype.initialize.apply(this, arguments); @@ -292,7 +293,7 @@ let ModelEditor = PageView.extend({ parent: this, required: true, name: 'system-volume', - label: 'System Volume: ', + label: 'Volume: ', tests: tests.valueTests, modelKey: 'volume', valueType: 'number', diff --git a/client/templates/includes/modelStateButtons.pug b/client/templates/includes/modelStateButtons.pug index 9f77902f92..00e219bbb3 100644 --- a/client/templates/includes/modelStateButtons.pug +++ b/client/templates/includes/modelStateButtons.pug @@ -12,6 +12,8 @@ div.mdl-edit-btn button.btn.btn-primary.box-shadow(data-hook="save") Save + button.btn.btn-primary.box-shadow(data-hook="return-to-project-btn" style="display: none;") Return to Project + button.btn.btn-primary.box-shadow.dropdown-toggle( id="simulate-model", data-hook="simulate-model", @@ -27,7 +29,4 @@ div.mdl-edit-btn li.dropdown-item(id="stochss-es" data-hook="stochss-es") Ensemble Simulation li.dropdown-item(id="stochss-ps" data-hook="stochss-ps") Parameter Sweep li.dropdown-item(data-hook="new-workflow") Jupyter Notebook - - button.btn.btn-primary.box-shadow(data-hook="return-to-project-btn" style="display: none;") Return to Project - - + \ No newline at end of file diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug index f9e4efb999..d937351506 100644 --- a/client/templates/pages/modelEditor.pug +++ b/client/templates/pages/modelEditor.pug @@ -47,9 +47,18 @@ section.page div.card.card-body.collapse.show(data-hook="system-volume-container") - p System volume affects custom propensities or stochastic reactions with two reactants. The volume sets the implicit parameter 'vol' which can be used in custom propensity functions. A single well-mixed volume is assumed. Compartments are not currently supported. + div - div(data-hook="volume") + h3.inline System Volume + button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-system-volume", data-hook="collapse-system-volume") + + + div.collapse(id="collapse-system-volume") + + p System volume affects custom propensities or stochastic reactions with two reactants. The volume sets the implicit parameter 'vol' which can be used in custom propensity functions. A single well-mixed volume is assumed. Compartments are not currently supported. + + hr + + div(data-hook="volume") div(data-hook="model-settings-container") From 9235ef30b7e9b1fc9aa4db55fb6ab15cbe13cb68 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Tue, 20 Oct 2020 12:29:01 -0400 Subject: [PATCH 24/24] Updated the model settings section to timespan to reflect not having volume in it. --- client/templates/includes/modelSettings.pug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/templates/includes/modelSettings.pug b/client/templates/includes/modelSettings.pug index cb3c785019..cde1d2030b 100644 --- a/client/templates/includes/modelSettings.pug +++ b/client/templates/includes/modelSettings.pug @@ -2,13 +2,13 @@ div#preview-settings.card.card-body div - h3.inline Model Settings + h3.inline Timespan button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-preview-settings", data-hook="collapse") - div.collapse(class="show", id="collapse-preview-settings") - p Model settings are used for the preview and all workflows created using this model. + p Timespan settings are used for the preview and all workflows created using this model. table.table