diff --git a/COPYRIGHT b/COPYRIGHT
index 99000953fe..7d089c27ab 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,5 +1,5 @@
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/Makefile b/Makefile
index 2bbfecc7e1..ed4b61a4e7 100644
--- a/Makefile
+++ b/Makefile
@@ -114,7 +114,7 @@ build: deps webpack
--build-arg JUPYTER_CONFIG_DIR=$(JUPYTER_CONFIG_DIR) \
-t $(DOCKER_STOCHSS_IMAGE):latest .
-test: build
+test: create_working_dir
docker run --rm \
--name $(DOCKER_STOCHSS_IMAGE) \
--env-file .env \
@@ -124,6 +124,8 @@ test: build
$(DOCKER_STOCHSS_IMAGE):latest \
/stochss/stochss/tests/run_tests.py
+build_and_test: build test
+
run: create_working_dir
docker run --rm \
--name $(DOCKER_STOCHSS_IMAGE) \
diff --git a/client/app.js b/client/app.js
index 9aac1d1023..e809e61721 100644
--- a/client/app.js
+++ b/client/app.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/config.js b/client/config.js
index 8fb86111be..824477f41d 100644
--- a/client/config.js
+++ b/client/config.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/graphics.js b/client/graphics.js
index 3f0299ce16..33042874c4 100644
--- a/client/graphics.js
+++ b/client/graphics.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/modals.js b/client/modals.js
index c55db1f6b8..93a5e044d9 100644
--- a/client/modals.js
+++ b/client/modals.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -424,15 +424,26 @@ module.exports = {
return templates.select(modalID, selectID, title, label, options)
},
- selectSpeciesHTML : (species) => {
- let modalID = "speciesSelectModal";
- let selectID = "speciesSelectList";
- let title = "Preview Variable Selection";
- let label = "Select a variable to preview: ";
+ selectPreviewTargetHTML : (species) => {
+ let modalID = "previewTargetSelectModal";
+ let selectID = "previewTargetSelectList";
+ let title = "Preview Target Selection";
+ let label = "Select a variable or property to preview: ";
var options = species.map(function (name) {
return ``
});
- options = options.join(" ");
+ options = `
+ `;
return templates.select(modalID, selectID, title, label, options)
},
diff --git a/client/views/view-domain-types.js b/client/models/boundary-condition.js
similarity index 74%
rename from client/views/view-domain-types.js
rename to client/models/boundary-condition.js
index 5b2d8906fa..d8e893bfec 100644
--- a/client/views/view-domain-types.js
+++ b/client/models/boundary-condition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,11 +16,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-//views
-var View = require('ampersand-view');
-//templates
-var template = require('../templates/includes/domainTypesViewer.pug');
+//models
+var State = require('ampersand-state');
-module.exports = View.extend({
- template: template,
+module.exports = State.extend({
+ props: {
+ compID: 'number',
+ name: 'string',
+ expression: 'string',
+ annotation: 'string'
+ }
});
\ No newline at end of file
diff --git a/client/views/view-rules.js b/client/models/boundary-conditions.js
similarity index 58%
rename from client/views/view-rules.js
rename to client/models/boundary-conditions.js
index c4939f45d4..667af7cd85 100644
--- a/client/views/view-rules.js
+++ b/client/models/boundary-conditions.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,11 +16,20 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-//views
-var View = require('ampersand-view');
-//templates
-var template = require('../templates/includes/viewRules.pug');
+//collections
+var Collection = require('ampersand-collection');
+//models
+var BoundaryCondition = require('./boundary-condition');
-module.exports = View.extend({
- template: template,
+module.exports = Collection.extend({
+ model: BoundaryCondition,
+ addNewBoundaryCondition: function (name, expression) {
+ let id = this.parent.getDefaultID();
+ let boundaryCondition = this.add({
+ compID: id,
+ name: name,
+ expression: expression,
+ annotation: ""
+ });
+ }
});
\ No newline at end of file
diff --git a/client/models/creator.js b/client/models/creator.js
index ee9d3be24d..d39dd3cf98 100644
--- a/client/models/creator.js
+++ b/client/models/creator.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/creators.js b/client/models/creators.js
index df67172530..7b23fb84e7 100644
--- a/client/models/creators.js
+++ b/client/models/creators.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/domain-type.js b/client/models/domain-type.js
index 2362909609..9c88aa284f 100644
--- a/client/models/domain-type.js
+++ b/client/models/domain-type.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/domain-types.js b/client/models/domain-types.js
index 0b4ad9e1bf..693625ae8a 100644
--- a/client/models/domain-types.js
+++ b/client/models/domain-types.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/domain.js b/client/models/domain.js
index 73c34cbe6a..725212644a 100644
--- a/client/models/domain.js
+++ b/client/models/domain.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/event-assignment.js b/client/models/event-assignment.js
index 7e621a7caf..b1452025b4 100644
--- a/client/models/event-assignment.js
+++ b/client/models/event-assignment.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/event-assignments.js b/client/models/event-assignments.js
index 62733ea5bf..21ed3349f1 100644
--- a/client/models/event-assignments.js
+++ b/client/models/event-assignments.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/event.js b/client/models/event.js
index a20050481e..6f30f26b6c 100644
--- a/client/models/event.js
+++ b/client/models/event.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/events.js b/client/models/events.js
index 25729358f1..904df78a1d 100644
--- a/client/models/events.js
+++ b/client/models/events.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/function-definition.js b/client/models/function-definition.js
index eef7d7caae..1ebd991677 100644
--- a/client/models/function-definition.js
+++ b/client/models/function-definition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/function-definitions.js b/client/models/function-definitions.js
index 4dab2ad8bc..824c2634ad 100644
--- a/client/models/function-definitions.js
+++ b/client/models/function-definitions.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/initial-condition.js b/client/models/initial-condition.js
index 8f4801b10f..97c03bbec8 100644
--- a/client/models/initial-condition.js
+++ b/client/models/initial-condition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,11 +23,12 @@ var Specie = require('./specie');
module.exports = State.extend({
props: {
icType: 'string',
- count: 'number',
+ annotation: 'string',
+ count: 'any',
types: 'object',
- x: 'number',
- y: 'number',
- z: 'number',
+ x: 'any',
+ y: 'any',
+ z: 'any',
},
children: {
specie: Specie,
diff --git a/client/models/initial-conditions.js b/client/models/initial-conditions.js
index c6984f1a16..72b22b87eb 100644
--- a/client/models/initial-conditions.js
+++ b/client/models/initial-conditions.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@ module.exports = Collection.extend({
addInitialCondition: function (initialConditionType, types) {
var initialCondition = new InitialCondition({
icType: initialConditionType,
+ annotation: "",
types: types,
count: 0,
x: 0,
diff --git a/client/models/job.js b/client/models/job.js
index d519da4f3c..33e0a37883 100644
--- a/client/models/job.js
+++ b/client/models/job.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/jobs.js b/client/models/jobs.js
index 01ecde1afb..9699ee7a10 100644
--- a/client/models/jobs.js
+++ b/client/models/jobs.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/me.js b/client/models/me.js
index 5fdbe15e6c..4bc370dc9d 100644
--- a/client/models/me.js
+++ b/client/models/me.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/metadata.js b/client/models/metadata.js
index 2a80da336c..873e4c9e96 100644
--- a/client/models/metadata.js
+++ b/client/models/metadata.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/model.js b/client/models/model.js
index b8b59ab441..9799e6e4f2 100644
--- a/client/models/model.js
+++ b/client/models/model.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+let _ = require('underscore');
+//support files
var app = require('../app');
var path = require('path');
//models
@@ -30,6 +32,7 @@ var Reactions = require('./reactions');
var Rules = require('./rules');
var Events = require('./events');
var FunctionDefinitions = require('./function-definitions');
+var BoundaryConditions = require('./boundary-conditions');
module.exports = Model.extend({
url: function () {
@@ -49,7 +52,8 @@ module.exports = Model.extend({
reactions: Reactions,
rules: Rules,
eventsCollection: Events,
- functionDefinitions: FunctionDefinitions
+ functionDefinitions: FunctionDefinitions,
+ boundaryConditions: BoundaryConditions
},
children: {
modelSettings: TimespanSettings,
@@ -91,12 +95,12 @@ module.exports = Model.extend({
this.rules.on('add change remove', this.updateValid, this);
},
validateModel: function () {
- if(!this.species.validateCollection()) return false;
+ if(!this.species.validateCollection(this.is_spatial)) return false;
if(!this.parameters.validateCollection()) return false;
if(!this.reactions.validateCollection()) return false;
if(!this.eventsCollection.validateCollection()) return false;
if(!this.rules.validateCollection()) return false;
- if(this.reactions.length <= 0 && this.eventsCollection.length <= 0 && this.rules.length <= 0) {
+ if(!this.is_spatial && this.reactions.length <= 0 && this.eventsCollection.length <= 0 && this.rules.length <= 0) {
this.error = {"type":"process"}
return false;
}
@@ -124,7 +128,10 @@ module.exports = Model.extend({
return id;
},
autoSave: function () {
- //TODO: implement auto save
+ let self = this;
+ setTimeout(function () {
+ app.postXHR(self.url(), self.toJSON(), { success: _.bind(self.autoSave, self) });
+ }, 120000);
},
//called when save button is clicked
saveModel: function (cb=null) {
diff --git a/client/models/parameter-sweep-settings.js b/client/models/parameter-sweep-settings.js
index 1b746a5b2e..e1a09f5b93 100644
--- a/client/models/parameter-sweep-settings.js
+++ b/client/models/parameter-sweep-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/parameter.js b/client/models/parameter.js
index e8d0c0c5fe..1d460ecfa5 100644
--- a/client/models/parameter.js
+++ b/client/models/parameter.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/parameters.js b/client/models/parameters.js
index 5091fa2a45..76848f5a00 100644
--- a/client/models/parameters.js
+++ b/client/models/parameters.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/particle.js b/client/models/particle.js
index 5cb54d5e06..948633c14c 100644
--- a/client/models/particle.js
+++ b/client/models/particle.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/particles.js b/client/models/particles.js
index ec599b1024..388f50fe24 100644
--- a/client/models/particles.js
+++ b/client/models/particles.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/project.js b/client/models/project.js
index 404e84bc9f..6a168b6a12 100644
--- a/client/models/project.js
+++ b/client/models/project.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/reaction.js b/client/models/reaction.js
index 8802ef112d..94bfff06c4 100644
--- a/client/models/reaction.js
+++ b/client/models/reaction.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/reactions.js b/client/models/reactions.js
index e225df46fb..10b26f5d1b 100644
--- a/client/models/reactions.js
+++ b/client/models/reactions.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/results-settings.js b/client/models/results-settings.js
index ffae215597..e7d13203fe 100644
--- a/client/models/results-settings.js
+++ b/client/models/results-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/rule.js b/client/models/rule.js
index 9113bd7ea5..afe82692b8 100644
--- a/client/models/rule.js
+++ b/client/models/rule.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/rules.js b/client/models/rules.js
index cc6c9afac8..955c85a9fb 100644
--- a/client/models/rules.js
+++ b/client/models/rules.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/settings.js b/client/models/settings.js
index fe6911dcaa..9817082956 100644
--- a/client/models/settings.js
+++ b/client/models/settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/simulation-settings.js b/client/models/simulation-settings.js
index a67ede077b..af8c55a560 100644
--- a/client/models/simulation-settings.js
+++ b/client/models/simulation-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/specie.js b/client/models/specie.js
index d2c4f99d4b..8f1f8375b5 100644
--- a/client/models/specie.js
+++ b/client/models/specie.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/species.js b/client/models/species.js
index 5ba9377b71..8cde7ff383 100644
--- a/client/models/species.js
+++ b/client/models/species.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,8 +55,8 @@ module.exports = Collection.extend({
this.remove(specie);
this.parent.updateValid()
},
- validateCollection: function () {
- if(this.length <= 0) {
+ validateCollection: function (isSpatial) {
+ if(this.length <= 0 && !isSpatial) {
this.parent.error = {'type':'species'}
return false;
}
diff --git a/client/models/stoich-specie.js b/client/models/stoich-specie.js
index a11311f9f5..6e109c8dc4 100644
--- a/client/models/stoich-specie.js
+++ b/client/models/stoich-specie.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/stoich-species.js b/client/models/stoich-species.js
index 53d398197f..0bfdbb44f9 100644
--- a/client/models/stoich-species.js
+++ b/client/models/stoich-species.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/sweep-parameter.js b/client/models/sweep-parameter.js
index e9efdf0a38..288c68c832 100644
--- a/client/models/sweep-parameter.js
+++ b/client/models/sweep-parameter.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/sweep-parameters.js b/client/models/sweep-parameters.js
index eb60b7f7c0..c421f54339 100644
--- a/client/models/sweep-parameters.js
+++ b/client/models/sweep-parameters.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/timespan-settings.js b/client/models/timespan-settings.js
index 98ab1d7879..0978e7eb46 100644
--- a/client/models/timespan-settings.js
+++ b/client/models/timespan-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,8 @@ var State = require('ampersand-state');
module.exports = State.extend({
props: {
endSim: 'any',
- timeStep: 'any'
+ timeStep: 'any',
+ timestepSize: 'number'
},
initialize: function (attrs, options) {
State.prototype.initialize.apply(this, arguments)
diff --git a/client/models/workflow-group.js b/client/models/workflow-group.js
index 2ba66cc014..364ac6f49b 100644
--- a/client/models/workflow-group.js
+++ b/client/models/workflow-group.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/workflow-groups.js b/client/models/workflow-groups.js
index a33b2dce18..3f416dedbd 100644
--- a/client/models/workflow-groups.js
+++ b/client/models/workflow-groups.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/workflow.js b/client/models/workflow.js
index 36427fdfd9..b015eb1389 100644
--- a/client/models/workflow.js
+++ b/client/models/workflow.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/models/workflows.js b/client/models/workflows.js
index 194fe9b0da..ac1af588a4 100644
--- a/client/models/workflows.js
+++ b/client/models/workflows.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/page-help.js b/client/page-help.js
index 855a2618fc..6207aaa081 100644
--- a/client/page-help.js
+++ b/client/page-help.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/base.js b/client/pages/base.js
index 4e295992ed..05cb8dec34 100644
--- a/client/pages/base.js
+++ b/client/pages/base.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/domain-editor.js b/client/pages/domain-editor.js
index 4160ab3d44..ef6bc1e3ab 100644
--- a/client/pages/domain-editor.js
+++ b/client/pages/domain-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/file-browser.js b/client/pages/file-browser.js
index 94dc7d5c75..080cc866dd 100644
--- a/client/pages/file-browser.js
+++ b/client/pages/file-browser.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/home.js b/client/pages/home.js
index 4b1b4121f4..039614d8b2 100644
--- a/client/pages/home.js
+++ b/client/pages/home.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/loading-page.js b/client/pages/loading-page.js
index f6ba556d4f..1710f889b0 100644
--- a/client/pages/loading-page.js
+++ b/client/pages/loading-page.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/model-editor.js b/client/pages/model-editor.js
index bdb85123e5..dea04098a6 100644
--- a/client/pages/model-editor.js
+++ b/client/pages/model-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,26 +23,23 @@ let path = require('path');
var app = require('../app');
var modals = require('../modals');
var tests = require('../views/tests');
+let Tooltips = require("../tooltips");
//views
var PageView = require('../pages/base');
var InputView = require('../views/input');
var DomainViewer = require('../views/domain-viewer');
var SpeciesEditorView = require('../views/species-editor');
-var SpeciesViewer = require('../views/species-viewer');
var InitialConditionsEditorView = require('../views/initial-conditions-editor');
-var InitialConditionsViewer = require('../views/initial-conditions-viewer');
var ParametersEditorView = require('../views/parameters-editor');
var ParticleViewer = require('../views/view-particle');
var ReactionsEditorView = require('../views/reactions-editor');
-var ReactionsViewer = require('../views/reactions-viewer');
var EventsEditorView = require('../views/events-editor');
-var EventsViewer = require('../views/events-viewer');
var RulesEditorView = require('../views/rules-editor');
-var RulesViewer = require('../views/rules-viewer');
var SBMLComponentView = require('../views/sbml-component-editor');
var TimespanSettingsView = require('../views/timespan-settings');
var ModelStateButtonsView = require('../views/model-state-buttons');
var QuickviewDomainTypes = require('../views/quickview-domain-types');
+let BoundaryConditionsView = require('../views/boundary-conditions-editor');
//models
var Model = require('../models/model');
var Domain = require('../models/domain');
@@ -54,9 +51,13 @@ import initPage from './page.js';
let ModelEditor = PageView.extend({
template: template,
events: {
+ 'change [data-hook=all-continuous]' : 'setDefaultMode',
+ 'change [data-hook=all-discrete]' : 'setDefaultMode',
+ 'change [data-hook=advanced]' : 'setDefaultMode',
'click [data-hook=edit-model-help]' : function () {
let modal = $(modals.operationInfoModalHtml('model-editor')).modal();
},
+ 'change [data-hook=edit-volume]' : 'updateVolumeViewer',
'click [data-hook=collapse-me-advanced-section]' : 'changeCollapseButtonText',
'click [data-hook=project-breadcrumb-link]' : 'handleProjectBreadcrumbClick',
'click [data-hook=toggle-preview-plot]' : 'togglePreviewPlot',
@@ -66,6 +67,7 @@ let ModelEditor = PageView.extend({
},
initialize: function (attrs, options) {
PageView.prototype.initialize.apply(this, arguments);
+ this.tooltips = Tooltips.modelEditor
var self = this;
let urlParams = new URLSearchParams(window.location.search)
var directory = urlParams.get('path');
@@ -218,6 +220,12 @@ let ModelEditor = PageView.extend({
}
},
renderSubviews: function () {
+ if(this.model.defaultMode === "" && !this.model.is_spatial){
+ this.getInitialDefaultMode();
+ }else{
+ let dataHooks = {'continuous':'all-continuous', 'discrete':'all-discrete', 'dynamic':'advanced'}
+ $(this.queryByHook(dataHooks[this.model.defaultMode])).prop('checked', true)
+ }
this.modelSettings = new TimespanSettingsView({
parent: this,
model: this.model.modelSettings,
@@ -231,10 +239,12 @@ let ModelEditor = PageView.extend({
app.registerRenderSubview(this, this.modelSettings, 'model-settings-container');
app.registerRenderSubview(this, this.modelStateButtons, 'model-state-buttons-container');
if(this.model.is_spatial) {
- $(this.queryByHook("model-editor-advanced-container")).css("display", "none");
+ $(this.queryByHook("system-volume-container")).css("display", "none");
+ $(this.queryByHook("advaced-model-mode")).css("display", "none");
$(this.queryByHook("spatial-beta-message")).css("display", "block");
this.renderDomainViewer();
this.renderInitialConditions();
+ this.renderBoundaryConditionsView();
$(this.queryByHook("toggle-preview-domain")).css("display", "inline-block");
this.openDomainPlot();
}else {
@@ -242,14 +252,14 @@ let ModelEditor = PageView.extend({
this.renderRulesView();
if(this.model.functionDefinitions.length) {
var sbmlComponentView = new SBMLComponentView({
- functionDefinitions: this.model.functionDefinitions,
- viewModel: false
+ functionDefinitions: this.model.functionDefinitions
});
app.registerRenderSubview(this, sbmlComponentView, 'sbml-component-container');
}
this.renderSystemVolumeView();
}
- $(document).ready(function () {
+ this.model.autoSave();
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
@@ -259,6 +269,15 @@ let ModelEditor = PageView.extend({
e.target.remove()
});
},
+ renderBoundaryConditionsView: function() {
+ if(this.boundaryConditionsView) {
+ this.boundaryConditionsView.remove();
+ }
+ this.boundaryConditionsView = new BoundaryConditionsView({
+ collection: this.model.boundaryConditions
+ });
+ app.registerRenderSubview(this, this.boundaryConditionsView, "boundary-conditions-container");
+ },
renderDomainViewer: function(domainPath=null) {
if(this.domainViewer) {
this.domainViewer.remove()
@@ -287,33 +306,26 @@ let ModelEditor = PageView.extend({
app.registerRenderSubview(this, this.domainViewer, 'domain-viewer-container');
}
},
- renderSpeciesView: function (mode="edit") {
+ renderSpeciesView: function () {
if(this.speciesEditor) {
this.speciesEditor.remove()
}
- if(mode === "edit") {
- this.speciesEditor = new SpeciesEditorView({collection: this.model.species});
- }else{
- this.speciesEditor = new SpeciesViewer({collection: this.model.species});
- }
+ this.speciesEditor = new SpeciesEditorView({
+ collection: this.model.species,
+ spatial: this.model.is_spatial,
+ defaultMode: this.model.defaultMode
+ });
app.registerRenderSubview(this, this.speciesEditor, 'species-editor-container');
},
- renderInitialConditions: function (mode="edit", opened=false) {
+ renderInitialConditions: function () {
if(this.initialConditionsEditor) {
this.initialConditionsEditor.remove();
}
- if(mode === "edit") {
- this.initialConditionsEditor = new InitialConditionsEditorView({
- collection: this.model.initialConditions,
- opened: opened
- });
- }else{
- this.initialConditionsEditor = new InitialConditionsViewer({
- collection: this.model.initialConditions
- });
- }
+ this.initialConditionsEditor = new InitialConditionsEditorView({
+ collection: this.model.initialConditions,
+ });
app.registerRenderSubview(this, this.initialConditionsEditor, 'initial-conditions-editor-container');
- },
+ },
renderParametersView: function () {
if(this.parametersEditor) {
this.parametersEditor.remove()
@@ -321,37 +333,25 @@ let ModelEditor = PageView.extend({
this.parametersEditor = new ParametersEditorView({collection: this.model.parameters});
app.registerRenderSubview(this, this.parametersEditor, 'parameters-editor-container');
},
- renderReactionsView: function (mode="edit", opened=false) {
+ renderReactionsView: function () {
if(this.reactionsEditor) {
this.reactionsEditor.remove()
}
- if(mode === "edit") {
- this.reactionsEditor = new ReactionsEditorView({collection: this.model.reactions, opened: opened});
- }else{
- this.reactionsEditor = new ReactionsViewer({collection: this.model.reactions});
- }
+ this.reactionsEditor = new ReactionsEditorView({collection: this.model.reactions});
app.registerRenderSubview(this, this.reactionsEditor, 'reactions-editor-container');
},
- renderEventsView: function (mode="edit", opened=false) {
+ renderEventsView: function () {
if(this.eventsEditor){
this.eventsEditor.remove();
}
- if(mode === "edit") {
- this.eventsEditor = new EventsEditorView({collection: this.model.eventsCollection, opened: opened});
- }else{
- this.eventsEditor = new EventsViewer({collection: this.model.eventsCollection});
- }
+ this.eventsEditor = new EventsEditorView({collection: this.model.eventsCollection});
app.registerRenderSubview(this, this.eventsEditor, 'events-editor-container');
},
- renderRulesView: function (mode="edit", opened=false) {
+ renderRulesView: function () {
if(this.rulesEditor){
this.rulesEditor.remove();
}
- if(mode === "edit") {
- this.rulesEditor = new RulesEditorView({collection: this.model.rules, opened: opened});
- }else{
- this.rulesEditor = new RulesViewer({collection: this.model.rules})
- }
+ this.rulesEditor = new RulesEditorView({collection: this.model.rules});
app.registerRenderSubview(this, this.rulesEditor, 'rules-editor-container');
},
renderSystemVolumeView: function () {
@@ -368,10 +368,11 @@ let ModelEditor = PageView.extend({
valueType: 'number',
value: this.model.volume,
});
- app.registerRenderSubview(this, this.systemVolumeView, 'volume')
+ app.registerRenderSubview(this, this.systemVolumeView, 'edit-volume')
if(this.model.defaultMode === "continuous") {
$(this.queryByHook("system-volume-container")).collapse("hide")
}
+ $(this.queryByHook("view-volume")).html("Volume: " + this.model.volume)
},
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
@@ -425,6 +426,66 @@ let ModelEditor = PageView.extend({
clickDownloadPNGButton: function (e) {
let pngButton = $('div[data-hook=preview-plot-container] a[data-title*="Download plot as a png"]')[0]
pngButton.click()
+ },
+ getInitialDefaultMode: function () {
+ var self = this;
+ if(document.querySelector('#defaultModeModal')) {
+ document.querySelector('#defaultModeModal').remove();
+ }
+ let modal = $(modals.renderDefaultModeModalHtml()).modal();
+ let continuous = document.querySelector('#defaultModeModal .concentration-btn');
+ let discrete = document.querySelector('#defaultModeModal .population-btn');
+ let dynamic = document.querySelector('#defaultModeModal .hybrid-btn');
+ continuous.addEventListener('click', function (e) {
+ self.setInitialDefaultMode(modal, "continuous");
+ });
+ discrete.addEventListener('click', function (e) {
+ self.setInitialDefaultMode(modal, "discrete");
+ });
+ dynamic.addEventListener('click', function (e) {
+ self.setInitialDefaultMode(modal, "dynamic");
+ });
+ },
+ setAllSpeciesModes: function (prevMode) {
+ let self = this;
+ this.model.species.forEach(function (specie) {
+ specie.mode = self.model.defaultMode;
+ self.model.species.trigger('update-species', specie.compID, specie, false, true);
+ });
+ let switchToDynamic = (!Boolean(prevMode) || prevMode !== "dynamic") && this.model.defaultMode === "dynamic";
+ let switchFromDynamic = Boolean(prevMode) && prevMode === "dynamic" && this.model.defaultMode !== "dynamic";
+ if(switchToDynamic || switchFromDynamic) {
+ this.speciesEditor.renderEditSpeciesView();
+ this.speciesEditor.renderViewSpeciesView();
+ }
+ },
+ setDefaultMode: function (e) {
+ let prevMode = this.model.defaultMode;
+ this.model.defaultMode = e.target.dataset.name;
+ this.speciesEditor.defaultMode = e.target.dataset.name;
+ this.setAllSpeciesModes(prevMode);
+ this.toggleVolumeContainer();
+ },
+ setInitialDefaultMode: function (modal, mode) {
+ var dataHooks = {'continuous':'all-continuous', 'discrete':'all-discrete', 'dynamic':'advanced'};
+ modal.modal('hide');
+ $(this.queryByHook(dataHooks[mode])).prop('checked', true);
+ this.model.defaultMode = mode;
+ this.speciesEditor.defaultMode = mode;
+ this.setAllSpeciesModes();
+ this.toggleVolumeContainer();
+ },
+ toggleVolumeContainer: function () {
+ if(!this.model.is_spatial) {
+ if(this.model.defaultMode === "continuous") {
+ $(this.queryByHook("system-volume-container")).collapse("hide");
+ }else{
+ $(this.queryByHook("system-volume-container")).collapse("show");
+ }
+ }
+ },
+ updateVolumeViewer: function (e) {
+ $(this.queryByHook("view-volume")).html("Volume: " + this.model.volume)
}
});
diff --git a/client/pages/multiple-plots.js b/client/pages/multiple-plots.js
index ad54c5b373..108f9b60ce 100644
--- a/client/pages/multiple-plots.js
+++ b/client/pages/multiple-plots.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/page.js b/client/pages/page.js
index 3e434457ef..d9c6743cc0 100644
--- a/client/pages/page.js
+++ b/client/pages/page.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/project-browser.js b/client/pages/project-browser.js
index 1b65377b8d..6286c611a8 100644
--- a/client/pages/project-browser.js
+++ b/client/pages/project-browser.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js
index 67f45073ba..0ac554d7ce 100644
--- a/client/pages/project-manager.js
+++ b/client/pages/project-manager.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/quickstart.js b/client/pages/quickstart.js
index bf64e271f7..5fdd276d9c 100644
--- a/client/pages/quickstart.js
+++ b/client/pages/quickstart.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/users-home.js b/client/pages/users-home.js
index c5fa5b81c5..2eb2e8ee93 100644
--- a/client/pages/users-home.js
+++ b/client/pages/users-home.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/workflow-manager.js b/client/pages/workflow-manager.js
index 3dd79cdc2e..0e1696a6b0 100644
--- a/client/pages/workflow-manager.js
+++ b/client/pages/workflow-manager.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/pages/workflow-selection.js b/client/pages/workflow-selection.js
index 71846a1d2b..3d28c8c114 100644
--- a/client/pages/workflow-selection.js
+++ b/client/pages/workflow-selection.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/reaction-types.js b/client/reaction-types.js
index 503db760d3..ada8f44efb 100644
--- a/client/reaction-types.js
+++ b/client/reaction-types.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/styles/styles.css b/client/styles/styles.css
index 29403e2122..64935dff14 100644
--- a/client/styles/styles.css
+++ b/client/styles/styles.css
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -293,6 +293,11 @@ input[type="file"]::-ms-browse {
display: inline-block;
}
+.reaction-list-summary {
+ width: auto !important;
+ text-align: center;
+}
+
.container-part {
max-width: none;
}
@@ -697,3 +702,7 @@ span.checkbox {
overflow-y: hidden;
white-space: nowrap;
}
+
+.card-header {
+ background-color: rgba(0, 0, 0, 0.1);
+}
diff --git a/client/templates/includes/boundaryConditionsEditor.pug b/client/templates/includes/boundaryConditionsEditor.pug
new file mode 100644
index 0000000000..fea9fc7d4b
--- /dev/null
+++ b/client/templates/includes/boundaryConditionsEditor.pug
@@ -0,0 +1,133 @@
+div#boundary-conditions.card
+
+ div.card-header.pb-0
+
+ h3.inline.mr-3 Boundary Conditions
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="bc-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="bc-edit-tab" data-toggle="tab" href="#edit-boundary-conditions") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="bc-view-tab" data-toggle="tab" href="#view-boundary-conditions") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-boundary-conditions", data-hook="collapse-bc") +
+
+ div.card-body
+
+ p.mb-0
+ | Set spatial regions of the domain where a property of particles are held constant.
+
+ div.collapse.tab-content(id="collapse-boundary-conditions")
+
+ div.tab-pane.active(id="edit-boundary-conditions" data-hook="edit-boundary-conditions")
+
+ hr
+
+ div.mx-1.row.head
+
+ div.col-sm-3: h6 Name
+
+ div.col-sm-5: h6 Expression
+
+ div.col-sm-2
+
+ div.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-sm-2: h6 Remove
+
+ div.mt-3(data-hook="edit-boundary-conditions-list")
+
+ div.card.mt-3
+
+ div.card-header
+
+ h4.inline New Boundary Condition
+
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-new-boundary-conditions" data-hook="collapse-new-bc") +
+
+ div.card-body.mx-1.collapse(id="collapse-new-boundary-conditions")
+
+ div.row.head
+
+ div.col-sm-2: h6 Name
+
+ div.col-sm-4: h6 Target
+
+ div.col-sm-6: h6 Conditions
+
+ div.row.mt-3
+
+ div.col-sm-2(data-hook="new-bc-name" data-target="name")
+
+ div.col-sm-4
+
+ table.table
+ tbody
+ tr
+ th(scope="row") Property/Variable
+ td(data-hook="new-bc-target")
+ tr
+ th(scope="row") Value
+ td
+ div(data-hook="new-bc-velocity-value")
+ div(data-hook="new-bc-value-x" data-target="value")
+ div(data-hook="new-bc-value-y" data-target="value")
+ div(data-hook="new-bc-value-z" data-target="value")
+ div(data-hook="new-bc-other-value" style="display: none")
+ div(data-hook="new-bc-value" data-target="value")
+ tr
+ th(scope="row") Concentration
+ td
+ input(type="checkbox" checked=this.newBC.deterministic data-hook="new-bc-deterministic" disabled)
+
+ div.col-sm-6
+
+ div(style="display: flex;")
+
+ span.inline.mr-3(for="new-bc-type") Type:
+ div.inline(id="new-bc-type" data-hook="new-bc-type" data-target="type_id")
+
+ table.table
+ thead
+ tr
+ th(scope="col")
+ th(scope="col") X-Axis
+ th(scope="col") Y-Axis
+ th(scope="col") Z-Axis
+ tbody
+ tr
+ th(scope="row") Min
+ td: div(data-hook="new-bc-x-min" data-target="xmin")
+ td: div(data-hook="new-bc-y-min" data-target="ymin")
+ td: div(data-hook="new-bc-z-min" data-target="zmin")
+ tr
+ th(scope="row") Max
+ td: div(data-hook="new-bc-x-max" data-target="xmax")
+ td: div(data-hook="new-bc-y-max" data-target="ymax")
+ td: div(data-hook="new-bc-z-max" data-target="zmax")
+
+ button.btn.btn-outline-primary.box-shadow(data-hook="add-new-bc") Add New Boundary Condition
+
+ div.tab-pane(id="view-boundary-conditions" data-hook="view-boundary-conditions")
+
+ hr
+
+ div.mx-1.row.head
+
+ div.col-sm-3: h6 Name
+
+ div.col-sm-7: h6 Expression
+
+ div.col-sm-2(data-hook="bc-annotation-header")
+
+ h6 Annotation
+
+ div.mt-3(data-hook="view-boundary-conditions-list")
diff --git a/client/templates/includes/domainTypesViewer.pug b/client/templates/includes/domainTypesViewer.pug
deleted file mode 100644
index fab182ab9e..0000000000
--- a/client/templates/includes/domainTypesViewer.pug
+++ /dev/null
@@ -1,13 +0,0 @@
-tr
-
- td=this.model.name
-
- td=this.model.numParticles
-
- td=this.model.mass
-
- td=this.model.volume
-
- td=this.model.nu
-
- td: input(type="checkbox" checked=this.model.fixed disabled)
\ No newline at end of file
diff --git a/client/templates/includes/domainViewer.pug b/client/templates/includes/domainViewer.pug
index 296b7a0d7f..14590cd722 100644
--- a/client/templates/includes/domainViewer.pug
+++ b/client/templates/includes/domainViewer.pug
@@ -1,113 +1,146 @@
-div#domain-viewer.card.card-body
+div#domain-viewer.card
- div
+ div.card-header.pb-0
- h3.inline Domain
+ h3.inline.mr-3 Domain
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="domain-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="domain-edit-tab" data-toggle="tab" href="#edit-domain") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="domain-view-tab" data-toggle="tab" href="#view-domain") View
button.btn.btn-outline-collapse(id="-btn" data-toggle="collapse" data-target="#collapse-domain" data-hook="collapse") +
div.collapse(id="collapse-domain" data-hook="domain-container")
- div
+ div.card-body.tab-content
+
+ div(data-hook="external-domains-container")
+
+ button.btn.btn-outline-secondary.box-shadow.mb-3(data-hook="select-external-domain") View External Domain
+
+ div(data-hook="external-domain-select" style="display: none")
+
+ div.text-info(data-hook="select-location-message" style="display: none")
+ | There are multiple domain files with that name, please select a location
+
+ span.inline Select External Domain:
+
+ div.inline(data-hook="select-domain")
+
+ div.inline.ml-3(data-hook="select-domain-location" style="display: none")
+
+ span.inline Location:
+
+ div.inline(data-hook="select-location")
+
+ div.row
+
+ div.col-md-4
+
+ h4 Domain Properties
+
+ hr.mt-2
+ div.row
+ div.col-sm-6: h6.pl-2 Static Domain
+ div.col-sm-6: input(type="checkbox" id="static-domain" data-hook="static-domain" checked=this.model.static disabled)
+
+ hr.mt-2
+ div.row
+ div.col-sm-6: h6.pl-2 Density
+ div.col-sm-6=this.model.rho_0
+
+ hr.mt-2
+ div.row
+ div.col-sm-6: h6.pl-2 Gravity
+ div.col-sm-6=this.gravity
+
+ hr.mt-2
+ div.row
+ div.col-sm-6: h6.pl-2 Pressure
+ div.col-sm-6=this.model.p_0
- button.btn.btn-outline-secondary.box-shadow.mb-3(data-hook="select-external-domain") View External Domain
+ hr.mt-2
+ div.row
+ div.col-sm-6: h6.pl-2 Speed of Sound
+ div.col-sm-6=this.model.c_0
- div(data-hook="external-domain-select" style="display: none")
+ div.col-md-8
- div.text-info(data-hook="select-location-message" style="display: none")
- | There are multiple domain files with that name, please select a location
+ h4 Domain Limits
- span.inline Select External Domain:
+ hr.mt-2
+ div.row.head.mx-1
+ div.col-sm-3
+ div.col-sm-3.pb-1: h6 Minimum
+ div.col-sm-3: h6 Minimum
+ div.col-sm-3: h6 Reflect
- div.inline(data-hook="select-domain")
+ div.row.mt-3
+ div.col-sm-3: h6.pl-2 X-Axis
+ div.col-sm-3=this.model.x_lim[0]
+ div.col-sm-3=this.model.x_lim[1]
+ div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_x disabled)
- div.inline.ml-3(data-hook="select-domain-location" style="display: none")
+ hr.mt-2
+ div.row
+ div.col-sm-3: h6.pl-2 Y-Axis
+ div.col-sm-3=this.model.y_lim[0]
+ div.col-sm-3=this.model.y_lim[1]
+ div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_y disabled)
- span.inline Location:
+ hr.mt-2
+ div.row
+ div.col-sm-3: h6.pl-2 Z-Axis
+ div.col-sm-3=this.model.z_lim[0]
+ div.col-sm-3=this.model.z_lim[1]
+ div.col-sm-3: input(type="checkbox" checked=this.model.boundary_condition.reflect_z disabled)
- div.inline(data-hook="select-location")
+ div.mt-3
- div.row
+ h4 Types
- div.col-md-4
+ hr
- h4 Domain Properties
+ h6="Number of Un-Assigned Particles: " + this.model.types.get(0, "typeID").numParticles
- table.table
- tbody
- tr
- th(scope="row") Static Domain
- td: input(type="checkbox" id="static-domain" data-hook="static-domain" checked=this.model.static disabled)
- tr
- th(scope="row") Density
- td=this.model.rho_0
- tr
- th(scope="row") Gravity
- td=this.gravity
- tr
- th(scope="row") Pressure
- td=this.model.p_0
- tr
- th(scope="row") Speed of Sound
- td=this.model.c_0
+ div.component-valid(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles.
- div.col-md-8
+ hr
- h4 Domain Limits
+ div.mx-1.row.head.align-items-baseline
- table.table
- thead
- tr
- th(scope="col")
- th(scope="col") Minimum
- th(scope="col") Minimum
- th(scope="col") Reflect
+ div.col-sm-2: h6 Name
- tbody
- tr
- th(scope="row") X-Axis
- td=this.model.x_lim[0]
- td=this.model.x_lim[1]
- td: input(type="checkbox" checked=this.model.boundary_condition.reflect_x disabled)
- tr
- th(scope="row") Y-Axis
- td=this.model.y_lim[0]
- td=this.model.y_lim[1]
- td: input(type="checkbox" checked=this.model.boundary_condition.reflect_y disabled)
- tr
- th(scope="row") Z-Axis
- td=this.model.z_lim[0]
- td=this.model.z_lim[1]
- td: input(type="checkbox" checked=this.model.boundary_condition.reflect_z disabled)
+ div.col-sm-2: h6 Number of Particles
- div
+ div.col-sm-2: h6 Mass
- h4 Types
+ div.col-sm-2: h6 Volume
- hr
+ div.col-sm-2: h6 Viscosity
- h6="Number of Un-Assigned Particles: " + this.model.types.get(0, "typeID").numParticles
+ div.col-sm-2: h6 Fixed
- div(data-hook="domain-error"): p.text-danger A domain cannot have any un-assigned particles.
+ div.my-3(data-hook="domain-types-list")
- table.table
- thead
- tr
- th(scope="col") Name
- th(scope="col") Number of Particles
- th(scope="col") Mass
- th(scope="col") Volume
- th(scope="col") Viscosity
- th(scope="col") Fixed
+ div.tab-pane.active(id="edit-domain" data-hook="edit-domain")
- tbody(data-hook="domain-types-list")
+ hr
- hr
+ div
- div
+ button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain-btn") Edit Domain
- button.btn.btn-outline-primary.box-shadow(data-hook="edit-domain") Edit Domain
+ button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="create-domain") Build New Domain
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="create-domain") Build New Domain
+ button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-to-model" disabled) Import into Model
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-to-model" disabled) Import into Model
+ div.tab-pane(id="view-domain" data-hook="view-domain")
diff --git a/client/templates/includes/editAdvancedSpecie.pug b/client/templates/includes/editAdvancedSpecie.pug
deleted file mode 100644
index e341430071..0000000000
--- a/client/templates/includes/editAdvancedSpecie.pug
+++ /dev/null
@@ -1,19 +0,0 @@
-tr
-
- td.name: div(data-hook="specie-name")=this.model.name
-
- td: div(data-hook="specie-mode")
-
- td
- div.switching
- input(type="radio", name=this.model.name + "-switch-method", data-hook="switching-tol")
- | Switching Tolerance
-
- div.switching
- input(type="radio", name=this.model.name + "-switch-method", data-hook="switching-min")
- | Minimum Value for Switching (number of molecules)
-
- td
- div(data-hook="switching-tolerance")
-
- div(data-hook="switching-threshold")
\ No newline at end of file
diff --git a/client/templates/includes/editBoundaryCondition.pug b/client/templates/includes/editBoundaryCondition.pug
new file mode 100644
index 0000000000..2caa182c6f
--- /dev/null
+++ b/client/templates/includes/editBoundaryCondition.pug
@@ -0,0 +1,30 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-md-3
+
+ div.pl-2=this.model.name
+
+ div.col-md-5
+
+ div
+
+ button.btn.btn-outline-secondary(data-hook="expand") View Expression
+
+ div(data-hook="expression" style="display: none;")
+
+ div(style="white-space:pre;")=this.model.expression
+
+ div.col-md-2
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm(data-hook="edit-annotation-btn") Edit
+
+ div.col-md-2
+
+ button.btn.btn-outline-secondary(data-hook="remove") X
diff --git a/client/templates/includes/editEventAssignment.pug b/client/templates/includes/editEventAssignment.pug
index 00c9294936..ecc8b48dda 100644
--- a/client/templates/includes/editEventAssignment.pug
+++ b/client/templates/includes/editEventAssignment.pug
@@ -1,7 +1,18 @@
-tr
+div.mx-1
- td: div(data-hook="event-assignment-variable")
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td: div(data-hook="event-assignment-Expression")
+ div.row
- td: button.btn.btn-outline-secondary(data-hook="remove") X
\ No newline at end of file
+ div.col-sm-3
+
+ div.pl-2(data-hook="event-assignment-variable")
+
+ div.col-sm-7
+
+ div(data-hook="event-assignment-expression")
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary(data-hook="remove") X
diff --git a/client/templates/includes/editFunctionDefinition.pug b/client/templates/includes/editFunctionDefinition.pug
index 1e9f7f5a54..74866ea363 100644
--- a/client/templates/includes/editFunctionDefinition.pug
+++ b/client/templates/includes/editFunctionDefinition.pug
@@ -1,13 +1,20 @@
-tr
+div.mx-1
- td=this.model.signature
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- th
+ div.row
- div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+ div.col-sm-8
+
+ div.pl-2=this.model.signature
+
+ div.col-sm-2
+
+ 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.viewMode)
button.btn.btn-outline-secondary.btn-sm(data-hook="edit-annotation-btn") Edit
-
- if(!this.parent.viewMode)
- td: button.btn.btn-outline-secondary(data-hook="remove") X
\ No newline at end of file
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary(data-hook="remove") X
diff --git a/client/templates/includes/editInitialCondition.pug b/client/templates/includes/editInitialCondition.pug
index 51d9602e52..3b29326c07 100644
--- a/client/templates/includes/editInitialCondition.pug
+++ b/client/templates/includes/editInitialCondition.pug
@@ -1,21 +1,36 @@
-tr
+div.mx-1
- td: div(data-hook="initial-condition-type")
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td: div(data-hook="initial-condition-species")
+ div.row
- td: div(data-hook="count-container")
+ div.col-sm-2
- td
+ div.pl-2(data-hook="initial-condition-type")
- div(data-hook="place-details")
- span Location:
- div
- div.inline(data-hook="x-container")
- div.inline(data-hook="y-container")
- div.inline(data-hook="z-container")
- div(data-hook="scatter-details")
- span Active in Types:
- div(data-hook="initial-condition-types")
+ div.col-sm-2(data-hook="initial-condition-species")
- td: button.btn.btn-outline-secondary(data-hook="remove") X
\ No newline at end of file
+ div.col-sm-2(data-hook="count-container")
+
+ div.col-sm-2
+
+ div(data-hook="place-details")
+ span Location:
+ div
+ div.inline(data-hook="x-container")
+ div.inline(data-hook="y-container")
+ div.inline(data-hook="z-container")
+ div(data-hook="scatter-details")
+ span Active in Types:
+ div(data-hook="initial-condition-types")
+
+ div.col-sm-2
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary(data-hook="remove") X
diff --git a/client/templates/includes/editReactionVar.pug b/client/templates/includes/editReactionVar.pug
deleted file mode 100644
index 8d416852be..0000000000
--- a/client/templates/includes/editReactionVar.pug
+++ /dev/null
@@ -1,12 +0,0 @@
-tr
- td.name: div(data-hook="input-name-container")
-
- td: div(data-hook="input-value-container")
-
- 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")
-
- button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
-
- td: button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
\ No newline at end of file
diff --git a/client/templates/includes/editRule.pug b/client/templates/includes/editRule.pug
index 30c7547445..cdbb34eaeb 100644
--- a/client/templates/includes/editRule.pug
+++ b/client/templates/includes/editRule.pug
@@ -1,17 +1,32 @@
-tr
+div.mx-1
- td.name: div(data-hook="rule-name")
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td: div(data-hook="rule-type")
+ div.row
- td: div(data-hook="rule-variable")
+ div.col-sm-2
- td: div(data-hook="rule-expression")
+ div.pl-2(data-hook="rule-name")
- td
+ div.col-sm-2
- div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+ div(data-hook="rule-type")
- button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+ div.col-sm-2
- td: button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
\ No newline at end of file
+ div(data-hook="rule-variable")
+
+ div.col-sm-2
+
+ div(data-hook="rule-expression")
+
+ div.col-sm-2
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
diff --git a/client/templates/includes/editSpatialSpecie.pug b/client/templates/includes/editSpatialSpecie.pug
deleted file mode 100644
index 44aefb3757..0000000000
--- a/client/templates/includes/editSpatialSpecie.pug
+++ /dev/null
@@ -1,9 +0,0 @@
-tr
-
- td.name: div(data-hook="input-name-container")
-
- td: div(data-hook="input-diffusion-coeff-container")
-
- td: div.row(data-hook="species-types")
-
- td: button.btn.btn-outline-secondary(data-hook="remove") X
\ No newline at end of file
diff --git a/client/templates/includes/editSpatialSpecies.pug b/client/templates/includes/editSpatialSpecies.pug
new file mode 100644
index 0000000000..ae78da2e75
--- /dev/null
+++ b/client/templates/includes/editSpatialSpecies.pug
@@ -0,0 +1,28 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-sm-2
+
+ div.pl-2(data-hook="input-name-container")
+
+ div.col-sm-2
+
+ div(data-hook="input-value-container")
+
+ div.col-sm-4
+
+ div.row(data-hook="species-types")
+
+ div.col-sm-2
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
diff --git a/client/templates/includes/editSpecies.pug b/client/templates/includes/editSpecies.pug
new file mode 100644
index 0000000000..3c1ad72082
--- /dev/null
+++ b/client/templates/includes/editSpecies.pug
@@ -0,0 +1,70 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-sm-3
+
+ div.pl-2(data-hook="input-name-container")
+
+ div.col-sm-5
+
+ div(data-hook="input-value-container")
+
+ div.col-sm-2
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-sm-2
+
+ button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
+
+ div.mx-1.pl-2(data-hook="advanced-species")
+
+ div.align-items-baseline
+
+ h6.inline Advanced
+
+ button.btn.btn-outline-collapse.mb-2(data-toggle="collapse" data-target="#collapse-species-advanced" + this.model.collection.indexOf(this.model) data-hook="collapse-advanced") +
+
+ div.collapse(id="collapse-species-advanced" + this.model.collection.indexOf(this.model))
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3
+
+ h6.inline Mode
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.tooltips.mode)
+
+ div.col-sm-9
+
+ h6.inline Switching Settings (Hybrid Only)
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.tooltips.switchValue)
+
+ div.row.mt-3
+
+ div.col-sm-3(data-hook="specie-mode")
+
+ div.col-sm-4
+
+ div.switching
+ input(type="radio", name=this.model.name + "-switch-method", data-hook="switching-tol")
+ | Switching Tolerance
+
+ div.switching
+ input(type="radio", name=this.model.name + "-switch-method", data-hook="switching-min")
+ | Minimum Value for Switching (number of molecules)
+
+ div.col-sm-5
+
+ div(data-hook="switching-tolerance")
+
+ div(data-hook="switching-threshold")
diff --git a/client/templates/includes/eventAssignmentsEditor.pug b/client/templates/includes/eventAssignmentsEditor.pug
index 022cef0cd7..f32e4cf6da 100644
--- a/client/templates/includes/eventAssignmentsEditor.pug
+++ b/client/templates/includes/eventAssignmentsEditor.pug
@@ -1,26 +1,55 @@
-div
+div#event-assignments-editor
- table.table
+ div(data-hook="event-assignments-header")
- thead
+ h5.inline.mr-3
- tr
+ div
+
+ div.inline Assignments
- th(scope="col")
- div
- div.inline Target
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.assignments)
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.parent.tooltips.variable)
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-event-assignments" data-hook="collapse-assignments") -
- th(scope="col")
- div
- div.inline Expression
+ div
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.parent.tooltips.assignmentExpression)
+ div.collapse.show.tab-content(id="collapse-event-assignments" data-hook="event-assignments-list-container")
- th(scope="col") Remove
+ div.tab-pane.active(id="edit-event-assignments" data-hook="edit-event-assignments")
- tbody(data-hook="event-assignments-container")
+ hr
- button.btn.btn-outline-primary.box-shadow(data-hook="add-event-assignment", type="button")
- | Add Assignment
\ No newline at end of file
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3
+
+ div.inline Target
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.variable)
+
+ div.col-sm-7
+
+ h6.inline Expression
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.assignmentExpression)
+
+ div.col-sm-2
+
+ h6 Remove
+
+ div.my-3(data-hook="edit-event-assignments-container")
+
+ button.btn.btn-outline-primary.box-shadow(data-hook="add-event-assignment", type="button") Add Assignment
+
+ div.tab-pane(id="view-event-assignments" data-hook="view-event-assignments")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3 Target
+
+ div.col-sm-7 Expression
+
+ div.my-3(data-hook="view-event-assignments-container")
diff --git a/client/templates/includes/eventAssignmentsViewer.pug b/client/templates/includes/eventAssignmentsViewer.pug
deleted file mode 100644
index 4a3aa846c8..0000000000
--- a/client/templates/includes/eventAssignmentsViewer.pug
+++ /dev/null
@@ -1,11 +0,0 @@
-table.table
-
- thead
-
- tr
-
- th(scope="col") Target
-
- th(scope="col") Expression
-
- tbody(data-hook="view-event-assignments-list")
\ No newline at end of file
diff --git a/client/templates/includes/eventDetails.pug b/client/templates/includes/eventDetails.pug
index 6ccdb91b55..c473f51381 100644
--- a/client/templates/includes/eventDetails.pug
+++ b/client/templates/includes/eventDetails.pug
@@ -1,14 +1,18 @@
div(data-hook="event-details")
- div
+ div.row
- span(for="event-trigger-expression") Trigger Expression:
+ div
+
+ span(for="event-trigger-expression") Trigger Expression:
div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.tooltips.triggerExpression)
- div.col-md-8.inline(id="event-trigger-expression" data-hook="event-trigger-expression")
+ div.col-md-8(id="event-trigger-expression" data-hook="event-trigger-expression")
- div
+ div(data-hook="event-assignments")
+
+ div.my-1
h6.inline Advanced
button.btn.btn-outline-collapse(data-toggle='collapse', data-target='#advanced-events', data-hook='advanced-event-button') +
@@ -27,7 +31,7 @@ div(data-hook="event-details")
div.col-md-6
- span(for="event-trigger-expression") Prioirty:
+ span(for="event-trigger-expression") Priority:
div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.tooltips.priority)
@@ -61,18 +65,10 @@ div(data-hook="event-details")
div.horizontal-space.inline
- input(type="radio", name="use-values-from" data-hook="trigger-time" data-name="trigger")
+ input(type="radio", name="edit-use-values-from" data-hook="edit-trigger-time" data-name="trigger")
| Trigger Time
div.horizontal-space.inline
- input(type="radio", name="use-values-from" data-hook="assignment-time" data-name="assignment")
+ input(type="radio", name="edit-use-values-from" data-hook="edit-assignment-time" data-name="assignment")
| Assignment Time
-
- h5.inline
- div
- div.inline Assignments
-
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.parent.tooltips.assignments)
-
- div(data-hook="event-assignments")
\ No newline at end of file
diff --git a/client/templates/includes/eventListings.pug b/client/templates/includes/eventListings.pug
index c1d7a49696..f67a2ecc19 100644
--- a/client/templates/includes/eventListings.pug
+++ b/client/templates/includes/eventListings.pug
@@ -1,13 +1,22 @@
-tr
+div.mx-1
- td: input(type="radio", data-hook="select", name="event-select")
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td.name: div(data-hook="event-name-container")
+ div.row.align-items-baseline
- td
+ div.col-md-2
- div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+ div.pl-3: input(type="radio", data-hook="select", name="event-select")
- button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+ div.col-md-5(data-hook="event-name-container")
- td: button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
\ No newline at end of file
+ div.col-md-3
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-md-2
+
+ button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
diff --git a/client/templates/includes/eventsEditor.pug b/client/templates/includes/eventsEditor.pug
index 41f5845440..0828d3d9ee 100644
--- a/client/templates/includes/eventsEditor.pug
+++ b/client/templates/includes/eventsEditor.pug
@@ -1,45 +1,90 @@
-div#events.card.card-body
+div#events.card
- div
+ div.card-header.pb-0
- h3.inline Events
+ h3.inline.mr-3 Events
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="events-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="events-edit-tab" data-toggle="tab" href="#edit-events") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="events-view-tab" data-toggle="tab" href="#view-events") View
button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#events-container", data-hook="collapse") +
- div.collapse(id="events-container", data-hook="events")
+ div.card-body
+
+ p.mb-0
+ | A discontinuous action triggered by the state of the system.
+
+ div.collapse.tab-content(id="events-container", data-hook="events")
+
+ div.tab-pane.active(id="edit-events" data-hook="edit-events")
+
+ div.row.mb-3.align-items-baseline
+
+ div.col-md-6.container-part
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-md-2
+
+ h6 Edit
+
+ div.col-md-5
+
+ h6.inline Name
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+
+ div.col-md-3
+
+ h6.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-md-2
+
+ h6 Remove
+
+ div.mt-3(data-hook="edit-event-listing-container")
+
+ div.col-md-6.container-part(data-hook="event-details-container")
- div.row
+ button.btn.btn-outline-primary.box-shadow(data-hook="add-event") Add Event
- div.col-md-6.container-part
- p
- | A discontinuous action triggered by the state of the system.
+ div.tab-pane(id="view-events" data-hook="view-events")
- table.table
+ hr
- thead
+ div.mx-1.row.head
- tr
+ div.col-sm-2
- th(scope="col") Edit
+ h6 Name
- th(scope="col")
- div
- div.inline Name
+ div.col-sm-2
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+ h6 Trigger
- th(scope="col")
- div
- div.inline Annotation
+ div.col-sm-4
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+ h6 Assignments
- th(scope="col") Remove
+ div.col-sm-2
- tbody(data-hook="event-listing-container")
+ h6 Advanced
- div.col-md-6.container-part(data-hook="event-details-container")
+ div.col-sm-2(data-hook="events-annotation-header")
- button.btn.btn-outline-primary.box-shadow(data-hook="add-event") Add Event
+ h6 Annotation
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-events") Save Events
+ div.mt-3(data-hook="view-event-listing-container")
diff --git a/client/templates/includes/eventsViewer.pug b/client/templates/includes/eventsViewer.pug
deleted file mode 100644
index bf9bed0f61..0000000000
--- a/client/templates/includes/eventsViewer.pug
+++ /dev/null
@@ -1,30 +0,0 @@
-div#events-viewer.card.card-body
-
- div
-
- h3.inline Events
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-model-events-viewer", data-hook="collapse") -
-
- div.row.collapse(class="show", id="collapse-model-events-viewer")
-
- table.table
-
- thead
-
- tr
-
- th(scope="col") Name
-
- th(scope="col") Trigger
-
- th(scope="col") Assignments
-
- th(scope="col") Advanced
-
- if this.containsMdlWithAnn
- th.col-md-3-view(scope="col") Annotation
-
- tbody(data-hook="view-events-container")
-
- if this.collection.parent.for === "edit"
- button.btn.btn-outline-primary.box-shadow(data-hook="edit-events") Edit Events
diff --git a/client/templates/includes/initialConditionsEditor.pug b/client/templates/includes/initialConditionsEditor.pug
index 935e31f578..bac19f8d8c 100644
--- a/client/templates/includes/initialConditionsEditor.pug
+++ b/client/templates/includes/initialConditionsEditor.pug
@@ -1,51 +1,86 @@
-div#initial-conditions.card.card-body
+div#initial-conditions.card
- div
+ div.card-header.pb-0
- h3.inline Initial Conditions
+ h3.inline.mr-3 Initial Conditions
- button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#initial-condition" data-hook="initial-condition-button") +
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="initial-conditions-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="initial-conditions-edit-tab" data-toggle="tab" href="#edit-initial-conditions") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="initial-conditions-view-tab" data-toggle="tab" href="#view-initial-conditions") View
- div.collapse(id="initial-condition" data-hook="initial-conditions")
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#initial-condition" data-hook="initial-condition-button") +
- p
+ div.card-body
+ p.mb-0
| Define the initial conditions for a spatial simulation
- ul
+ ul.mb-0
li A 'Scatter' initial condition distributes Count particles over the chosen types.
li A 'Place' initial condition places Count particles at a given X, Y, Z coordinate.
li A 'Distribute Uniformly per Voxel' initial condition puts Count particles in each voxel of the chosen types.
- table.table
+ div.collapse.tab-content(id="initial-condition" data-hook="initial-conditions")
+
+ div.tab-pane.active(id="edit-initial-conditions" data-hook="edit-initial-conditions")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-2: h6 Type
+
+ div.col-sm-2: h6 Variable
+
+ div.col-sm-2: h6 Count
+
+ div.col-sm-2: h6 Details
+
+ div.col-sm-2
+
+ h6.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-sm-2: h6 Remove
+
+ div.my-3(data-hook="edit-initial-conditions-collection")
+
+ div.dropdown.inline
+
+ button.btn.btn-outline-primary.box-shadow.dropdown-toggle#addInitialConditionBtn(
+ data-hook='add-initial-condition',
+ data-toggle='dropdown',
+ aria-haspopup='true',
+ aria-expanded='false',
+ type='button'
+ ) Add Initial Condition
+
+ ul.dropdown-menu(aria-labelledby='addInitialConditionBtn')
+ li.dropdown-item(data-hook='scatter') Scatter
+ li.dropdown-item(data-hook='place') Place
+ li.dropdown-item(data-hook='distribute-uniformly') Distribute Uniformly per Voxel
+
+ div.tab-pane(id="view-initial-conditions" data-hook="view-initial-conditions")
+
+ hr
- thead
-
- tr
-
- th(scope="col") Type
-
- th(scope="col") Variable
+ div.mx-1.row.head.align-items-baseline
- th(scope="col") Count
-
- th(scope="col") Details
-
- th(scope="col") Remove
+ div.col-sm-2: h6 Type
- tbody(data-hook="initial-conditions-collection")
+ div.col-sm-2: h6 Variable
- div.dropdown.inline
+ div.col-sm-2: h6 Count
- button.btn.btn-outline-primary.box-shadow.dropdown-toggle#addInitialConditionBtn(
- data-hook='add-initial-condition',
- data-toggle='dropdown',
- aria-haspopup='true',
- aria-expanded='false',
- type='button'
- ) Add Initial Condition
+ div.col-sm-4: h6 Details
- ul.dropdown-menu(aria-labelledby='addInitialConditionBtn')
- li.dropdown-item(data-hook='scatter') Scatter
- li.dropdown-item(data-hook='place') Place
- li.dropdown-item(data-hook='distribute-uniformly') Distribute Uniformly per Voxel
+ div.col-sm-2(data-hook="initial-conditions-annotation-header"): h6 Annotation
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-initial-conditions") Save Initial Conditions
\ No newline at end of file
+ div.my-3(data-hook="view-initial-conditions-collection")
diff --git a/client/templates/includes/reactionListing.pug b/client/templates/includes/reactionListing.pug
index bed0ba53e5..3b7ea5cae3 100644
--- a/client/templates/includes/reactionListing.pug
+++ b/client/templates/includes/reactionListing.pug
@@ -1,14 +1,24 @@
-tr
- td: input(type="radio", data-hook="select", name="reaction-select")
-
- td.name: div(data-hook="input-name-container")
-
- td: div(data-hook="summary", style="width: auto !important")
-
- td
+div.mx-1
- 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.model.collection.indexOf(this.model) !== 0)
+ hr
- button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+ div.row.align-items-baseline
- td: button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
\ No newline at end of file
+ div.col-md-2
+
+ div.pl-3: input(type="radio" data-hook="select" name="reaction-select")
+
+ div.col-md-2(data-hook="input-name-container")
+
+ div.col-md-3.reaction-list-summary(data-hook="summary")
+
+ div.col-md-3
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
+
+ button.btn.btn-outline-secondary.btn-sm.box-shadow(data-hook="edit-annotation-btn") Edit
+
+ div.col-md-2
+
+ button.btn.btn-outline-secondary.box-shadow(data-hook="remove") X
diff --git a/client/templates/includes/reactionsEditor.pug b/client/templates/includes/reactionsEditor.pug
index b27791913b..c3b6e5b7ef 100644
--- a/client/templates/includes/reactionsEditor.pug
+++ b/client/templates/includes/reactionsEditor.pug
@@ -1,78 +1,117 @@
-div#reactions-editor.card.card-body
+div#reactions-editor.card
- div
+ div.card-header.pb-0
- h3.inline
- div
- div.inline Reactions
+ h3.inline.mr-3 Reactions
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-reaction", data-hook="collapse") +
+ div.inline.mr-3
- div.collapse(id="collapse-reaction" data-hook="reactions-list-container")
+ ul.nav.nav-tabs.card-header-tabs(id="reactions-tabs")
- p
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="reactions-edit-tab" data-toggle="tab" href="#edit-reactions") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="reactions-view-tab" data-toggle="tab" href="#view-reactions") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-reaction" data-hook="collapse") +
+
+ div.card-body
+
+ p.mb-0
| A process that transforms a set of Variables (reactants) into a set of Variables (products) at a rate set by a Parameter. Select from the given reaction templates, or use the custom types. The symbol represents null or empty set.
- div.row
- div.col-md-7.container-part: table.table
- thead: tr
- th(scope="col") Edit
- th(scope="col")
- div
- div.inline Name
+ div.collapse.tab-content(id="collapse-reaction" data-hook="reactions-list-container")
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
-
- th(scope="col") Summary
- th(scope="col")
- div
- div.inline Annotation
+ div.tab-pane.active(id="edit-reactions" data-hook="edit-reactions")
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+ div.row.mb-3
+
+ div.col-md-7.container-part
+
+ hr
- th(scope="col") Remove
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-md-2: h6.align-bottom Edit
+
+ div.col-md-2
- tbody(data-hook="reaction-list")
+ h6.inline Name
- div.col-md-5.container-part(data-hook="reaction-details-container")
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
- div(data-hook="massaction-message"): p.text-info To add a mass action reaction the model must have at least one parameter
-
- div(data-hook="process-component-error"): p.text-danger A model must have at least one reaction, event, or rule
-
- div.dropdown.inline
-
- button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addReactionBtn(
- data-hook="add-reaction-full",
- data-toggle="dropdown",
- aria-haspopup="true",
- aria-expanded="false",
- type="button"
- ) Add Reaction
-
- ul.dropdown-menu(aria-labelledby="addReactionBtn")
- li.dropdown-item(data-hook="creation") Creation Reaction
- li.dropdown-item(data-hook="destruction") Destruction Reaction
- li.dropdown-item(data-hook="change") Transformation Reaction
- li.dropdown-item(data-hook="dimerization") Dimerization Reaction
- li.dropdown-item(data-hook="merge") Merge Reaction
- li.dropdown-item(data-hook="split") Split Reaction
- li.dropdown-item(data-hook="four") Four Reaction
- li.dropdown-divider
- li.dropdown-item(data-hook="custom-massaction") Custom mass action
- li.dropdown-item(data-hook="custom-propensity") Custom propensity
-
- div.dropdown.inline
-
- button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addReactionBtn(
- data-hook="add-reaction-partial",
- data-toggle="dropdown",
- aria-haspopup="true",
- aria-expanded="false",
- type="button"
- ) Add Reaction
-
- ul.dropdown-menu(aria-labelledby="addReactionBtn")
- li.dropdown-item(data-hook="custom-propensity") Custom propensity
-
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-reactions") Save Reactions
+ div.col-md-3: h6 Summary
+
+ div.col-md-3
+
+ div.inline
+
+ h6 Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-md-2: h6 Remove
+
+ div.mt-3(data-hook="edit-reaction-list")
+
+ div.col-md-5.container-part(data-hook="reaction-details-container")
+
+ div(data-hook="massaction-message"): p.text-info To add a mass action reaction the model must have at least one parameter
+
+ div.component-valid(data-hook="process-component-error"): p.text-danger A model must have at least one reaction, event, or rule
+
+ div.dropdown.inline
+
+ button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addReactionBtn(
+ data-hook="add-reaction-full",
+ data-toggle="dropdown",
+ aria-haspopup="true",
+ aria-expanded="false",
+ type="button"
+ ) Add Reaction
+
+ ul.dropdown-menu(aria-labelledby="addReactionBtn")
+ li.dropdown-item(data-hook="creation") Creation Reaction
+ li.dropdown-item(data-hook="destruction") Destruction Reaction
+ li.dropdown-item(data-hook="change") Transformation Reaction
+ li.dropdown-item(data-hook="dimerization") Dimerization Reaction
+ li.dropdown-item(data-hook="merge") Merge Reaction
+ li.dropdown-item(data-hook="split") Split Reaction
+ li.dropdown-item(data-hook="four") Four Reaction
+ li.dropdown-divider
+ li.dropdown-item(data-hook="custom-massaction") Custom mass action
+ li.dropdown-item(data-hook="custom-propensity") Custom propensity
+
+ div.dropdown.inline
+
+ button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addReactionBtn(
+ data-hook="add-reaction-partial",
+ data-toggle="dropdown",
+ aria-haspopup="true",
+ aria-expanded="false",
+ type="button"
+ ) Add Reaction
+
+ ul.dropdown-menu(aria-labelledby="addReactionBtn")
+ li.dropdown-item(data-hook="custom-propensity") Custom propensity
+
+ div.tab-pane(id="view-reactions" data-hook="view-reactions")
+
+ hr
+
+ div.mx-1.row.head
+
+ div.col-md-2: h6 Name
+
+ div.col-md-3: h6 Summary
+
+ div.col-md-3: h6 Rate/Propensity
+
+ div.col-md-2(data-hook="reaction-types-header"): h6 Active in Types
+
+ div.col-md-2(data-hook="reaction-annotation-header"): h6 Annotation
+
+ div.mt-3(data-hook="view-reaction-list")
diff --git a/client/templates/includes/reactionsViewer.pug b/client/templates/includes/reactionsViewer.pug
deleted file mode 100644
index 2ad0a5bb15..0000000000
--- a/client/templates/includes/reactionsViewer.pug
+++ /dev/null
@@ -1,24 +0,0 @@
-div#reactions-viewer.card.card-body
-
- div
-
- h3.inline Reactions
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-reactions", data-hook="collapse") -
-
- div.collapse(class="show", id="collapse-reactions")
-
- table.table
- thead
- tr
- 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.collection.parent.is_spatial
- th.col-md-3-view(scope="col") Active in Types
- if this.containsMdlWithAnn
- th.col-md-3-view(scope="col") Annotation
-
- tbody(data-hook="reaction-list")
-
- if this.collection.parent.for === "edit"
- button.btn.btn-outline-primary.box-shadow(data-hook="edit-reactions") Edit Reactions
diff --git a/client/templates/includes/ruleEditor.pug b/client/templates/includes/ruleEditor.pug
index 7065291d4e..97cfd2c051 100644
--- a/client/templates/includes/ruleEditor.pug
+++ b/client/templates/includes/ruleEditor.pug
@@ -1,67 +1,109 @@
-div#rules-editor.card.card-body
+div#rules-editor.card
- div
+ div.card-header.pb-0
- h3.inline Rules
+ h3.inline.mr-3 Rules
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="rules-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="rules-edit-tab" data-toggle="tab" href="#edit-rules") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="rules-view-tab" data-toggle="tab" href="#view-rules") View
button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-rules", data-hook="collapse") +
- div.collapse(id="collapse-rules" data-hook="rules-list-container")
- p
+ div.card-body
+ p.mb-0
| Equations that determine the value (assignment rule) or rates of change (rate rule) of Variables or Parameter.
- table.table
+ div.collapse.tab-content(id="collapse-rules" data-hook="rules-list-container")
+
+ div.tab-pane.active(id="edit-rules" data-hook="edit-rules")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-2
+
+ h6.inline Name
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+
+ div.col-sm-2
+
+ h6.inline Type
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.type)
+
+ div.col-sm-2
+
+ h6.inline Target
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.variable)
+
+ div.col-sm-2
+
+ h6.inline Formula
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.expression)
+
+ div.col-sm-2
+
+ h6.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-sm-2
+
+ h6 Remove
- thead
+ div.my-3(data-hook="edit-rule-list-container")
- tr
+ div.dropdown
- th(scope="col")
- div
- div.inline Name
+ button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addRuleBtn(
+ data-hook="add-rule",
+ data-toggle="dropdown",
+ aria-haspopup="true",
+ aria-expanded="false",
+ type="button"
+ ) Add Rule
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+ ul.dropdown-menu(aria-labelledby="addRuleBtn")
+ li.dropdown-item(data-hook="rate-rule" data-name="Rate Rule") Rate Rule
+ li.dropdown-item(data-hook="assignment-rule" data-name="Assignment Rule") Assignment Rule
- th(scope="col")
- div
- div.inline Type
+ div.tab-pane(id="view-rules" data-hook="view-rules")
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.type)
+ hr
- th(scope="col")
- div
- div.inline Target
+ div.mx-1.row.head.align-items-baseline
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.variable)
+ div.col-sm-2
- th(scope="col")
- div
- div.inline Formula
+ h6.inline Name
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.expression)
+ div.col-sm-2
- th(scope="col")
- div
- div.inline Annotation
+ h6.inline Type
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+ div.col-sm-2
- th(scope="col") Remove
+ h6.inline Target
- tbody(data-hook="rule-list-container")
+ div.col-sm-4
- div.dropdown.inline
+ h6.inline Formula
- button.btn.btn-outline-primary.dropdown-toggle.box-shadow#addRuleBtn(
- data-hook="add-rule",
- data-toggle="dropdown",
- aria-haspopup="true",
- aria-expanded="false",
- type="button"
- ) Add Rule
+ div.col-sm-2(data-hook="rules-annotation-header")
- ul.dropdown-menu(aria-labelledby="addRuleBtn")
- li.dropdown-item(data-hook="rate-rule" data-name="Rate Rule") Rate Rule
- li.dropdown-item(data-hook="assignment-rule" data-name="Assignment Rule") Assignment Rule
+ h6.inline Annotation
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-rules") Save Rules
+ div.mt-3(data-hook="view-rules-list-container")
diff --git a/client/templates/includes/rulesViewer.pug b/client/templates/includes/rulesViewer.pug
deleted file mode 100644
index 1451df8482..0000000000
--- a/client/templates/includes/rulesViewer.pug
+++ /dev/null
@@ -1,23 +0,0 @@
-div#rules-viewer.card.card-body
-
- div
-
- h3.inline Rules
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-rules", data-hook="collapse") -
-
- div.collapse(class="show", id="collapse-rules")
-
- table.table
- thead
- tr
- th.col-md-3-view(scope="col") Name
- th.col-md-3-view(scope="col") Type
- 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
-
- tbody(data-hook="rules-list")
-
- if this.collection.parent.for === "edit"
- button.btn.btn-outline-primary.box-shadow(data-hook="edit-rules") Edit Rules
diff --git a/client/templates/includes/sbmlComponentEditor.pug b/client/templates/includes/sbmlComponentEditor.pug
index 7d4ec4423d..84ac3d3fb5 100644
--- a/client/templates/includes/sbmlComponentEditor.pug
+++ b/client/templates/includes/sbmlComponentEditor.pug
@@ -1,34 +1,75 @@
-div#sbml-components.card.card-body
+div#sbml-components.card
- div
+ div.card-header.pb-0
h3.inline SBML Components
+
button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-sbml-component", data-hook="collapse") +
div.collapse(id="collapse-sbml-component")
- div
+ div.card-body
+
+ div#function-definitions.card
+
+ div.card-header.pb-0
+
+ h5.inline.mr-3 Function Definitions
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="function-definitions-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="function-definitions-edit-tab" data-toggle="tab" href="#edit-function-definitions") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="function-definitions-view-tab" data-toggle="tab" href="#view-function-definitions") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-function-definitions" data-hook="collapse-function-definitions") -
+
+ div.card-body
+ p.mb-0
+ | Object representation defining an evaluable function to be used during simulation.
+
+ div.collapse.tab-content(class="show" id="collapse-function-definitions")
+
+ div.tab-pane.active(id="edit-function-definitions" data-hook="edit-function-definitions")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-8
+
+ h6 Signature
+
+ div.col-sm-2
+
+ h6.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-sm-2
+
+ h6 Remove
+
+ div.my-3(data-hook="edit-function-definition-list")
+
+ div.tab-pane(id="view-function-definitions" data-hook="view-function-definitions")
- h5.inline Function Definitions
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-function-definitions", data-hook="collapse-function-definitions") -
+ hr
- div.collapse(class="show", id="collapse-function-definitions")
+ div.mx-1.row.head.align-items-baseline
- table.table
+ div.col-sm-10
- thead
-
- tr
-
- th(scope="col") Signature
+ h6 Signature
- th(scope="col")
- div
- div.inline Annotation
+ div.col-sm-2(data-hook="function-definition-annotation-header")
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+ h6.inline Annotation
- if(!this.viewMode)
- th(scope="col") Remove
-
- tbody(data-hook="function-definition-list")
\ No newline at end of file
+ div.my-3(data-hook="view-function-definition-list")
diff --git a/client/templates/includes/spatialSpeciesEditor.pug b/client/templates/includes/spatialSpeciesEditor.pug
index 4adc51dfcb..ae24b9fc88 100644
--- a/client/templates/includes/spatialSpeciesEditor.pug
+++ b/client/templates/includes/spatialSpeciesEditor.pug
@@ -1,45 +1,85 @@
-div#species-editor.card.card-body
+div#species-editor.card
- div
+ div.card-header.pb-0
- h3.inline Variables
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-species", data-hook="collapse") -
+ h3.inline.mr-3 Variables
- div.collapse(class="show", id="collapse-species")
+ div.inline.mr-3
- p
+ ul.nav.nav-tabs.card-header-tabs(id="species-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="species-edit-tab" data-toggle="tab" href="#edit-species") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="species-view-tab" data-toggle="tab" href="#view-species") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-species" data-hook="collapse") -
+
+ div.card-body
+ p.mb-0
| Time varying quantities of interest; e.g.: concentrations, populations, or counts of biochemical species, epidemological compartments, chemicals, proteins, or molecules.
- table.table
- thead
- tr
- th(scope="col") Name
- th(scope="col") Diffusion Constant
- th(scope="col") Restricted to Types:
- th(scope="col") Remove
-
- tbody(data-hook="specie-list")
+ div.collapse.tab-content(class="show" id="collapse-species" data-hook="species-list-container")
+
+ div.tab-pane.active(id="edit-species" data-hook="edit-species")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-2
+
+ h6.inline Name
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+
+ div.col-sm-2
+
+ h6.inline Diffusion Constant
+
+ div.col-sm-4
+
+ h6.inline Restricted to Types:
+
+ div.col-sm-2
+
+ h6.inline Annotation
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
+
+ div.col-sm-2
+
+ h6.inline Remove
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.remove)
+
+ div.my-3(data-hook="edit-specie-list")
+
+ button.btn.btn-outline-primary.box-shadow(data-hook="add-species") Add Variable
+
+ div.tab-pane(id="view-species" data-hook="view-species")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-2
+
+ h6.inline Name
- table.table
- thead
- tr
- th(scope="col", colspan="3")
+ div.col-sm-2
- div
+ h6.inline Diffusion Constant
- div.inline Model Mode
+ div.col-sm-6
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.spatialSpeciesMode)
+ h6.inline Restricted to Types:
- tbody
- tr
- td
- input(type="radio", name="species-mode", data-hook="all-continuous", data-name="continuous")
- | Concentration
- td
- input(type="radio", name="species-mode", data-hook="all-discrete", data-name="discrete")
- | Population
+ div.col-sm-2(data-hook="species-annotation-header")
- button.btn.btn-outline-primary.box-shadow(data-hook="add-species") Add Variable
+ h6.inline Annotation
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-species") Save Variables
\ No newline at end of file
+ div.my-3(data-hook="view-specie-list")
diff --git a/client/templates/includes/speciesEditor.pug b/client/templates/includes/speciesEditor.pug
index 9162e167f8..0c0ae48995 100644
--- a/client/templates/includes/speciesEditor.pug
+++ b/client/templates/includes/speciesEditor.pug
@@ -1,92 +1,89 @@
-div#species-editor.card.card-body
+div#species-editor.card
- div
+ div.card-header.pb-0
- h3.inline Variables
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-species", data-hook="collapse") -
+ h3.inline.mr-3 Variables
- div.collapse(class="show", id="collapse-species" data-hook="species-list-container")
- p
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="species-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="species-edit-tab" data-toggle="tab" href="#edit-species") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="species-view-tab" data-toggle="tab" href="#view-species") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-species" data-hook="collapse") -
+
+ div.card-body
+ p.mb-0
| Time varying quantities of interest; e.g.: concentrations, populations, or counts of biochemical species, epidemological compartments, chemicals, proteins, or molecules.
- table.table
- thead
- tr
- th(scope="col")
- div
- div.inline Name
+ div.collapse.tab-content(class="show" id="collapse-species" data-hook="species-list-container")
+
+ div.tab-pane.active(id="edit-species" data-hook="edit-species")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3
+
+ h6.inline Name
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+
+ div.col-sm-5
+
+ h6.inline Initial Condition
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.initialValue)
+
+ div.col-sm-2
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.name)
+ h6.inline Annotation
- th(scope="col")
- div
- div.inline Initial Condition
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.initialValue)
+ div.col-sm-2
- th(scope="col")
- div
- div.inline Annotation
+ h6.inline Remove
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.annotation)
-
- th(scope="col")
- div
- div.inline Remove
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.remove)
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.remove)
-
- tbody(data-hook="specie-list")
+ div.my-3(data-hook="edit-specie-list")
- table.table
- thead
- tr
- th(scope="col", colspan="3")
+ div(data-hook="species-collection-error"): p.text-danger A model must have at least one variable
- div
+ button.btn.btn-outline-primary.box-shadow(data-hook="add-species") Add Variable
- div.inline Variable Mode
+ div.tab-pane(id="view-species" data-hook="view-species")
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.speciesMode)
+ hr
- tbody
- tr
- td
- input(type="radio", name="species-mode", data-hook="all-continuous", data-name="continuous")
- | Concentration
- td
- input(type="radio", name="species-mode", data-hook="all-discrete", data-name="discrete")
- | Population
- td
- input(type="radio", name="species-mode", data-hook="advanced", data-name="dynamic")
- | Hybrid Concentration/Population
-
- div.collapse(data-hook="advanced-species")
+ div.mx-1.row.head.align-items-baseline
- table.table
+ div.col-sm-2
- thead
+ h6.inline Name
- tr
+ div.col-sm-2
- th(scope="col") Name
+ h6.inline Initial Condition
- th(scope="col")
- div
- div.inline Mode
+ div.col-sm-2
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.mode)
-
- th(scope="col" colspan="2")
- div
- div.inline Switching Settings (Hybrid Only)
+ h6.inline Mode
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.switchValue)
+ div.col-sm-4(data-hook="species-switching-header")
- tbody(data-hook="edit-species-mode")
+ h6.inline Switch Tolerance/Minimum Value for Switching
- div(data-hook="species-collection-error"): p.text-danger A model must have at least one variable
+ div.col-sm-2(data-hook="species-annotation-header")
- button.btn.btn-outline-primary.box-shadow(data-hook="add-species") Add Variable
+ h6.inline Annotation
- button.btn.btn-outline-primary.box-shadow.ml-2(data-hook="save-species") Save Variables
+ div.my-3(data-hook="view-specie-list")
diff --git a/client/templates/includes/speciesViewer.pug b/client/templates/includes/speciesViewer.pug
deleted file mode 100644
index f2ad8b30e9..0000000000
--- a/client/templates/includes/speciesViewer.pug
+++ /dev/null
@@ -1,28 +0,0 @@
-div#species-viewer.card.card-body
-
- div
-
- h3.inline Variables
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-species", data-hook="collapse") -
-
- div.collapse(class="show", id="collapse-species")
-
- table.table
- thead
- tr
- th.col-md-3-view(scope="col") Name
- if this.collection.parent.is_spatial
- th.col-md-3-view(scope="col") Diffusion Constant
- th.col-md-3-view(scope="col") Restricted to Types:
- else
- th.col-md-3-view(scope="col") Initial Condition
- 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"
- button.btn.btn-outline-primary.box-shadow(data-hook="edit-species") Edit Variables
diff --git a/client/templates/includes/timespanSettings.pug b/client/templates/includes/timespanSettings.pug
index 35e7ad3b88..e49fe14c96 100644
--- a/client/templates/includes/timespanSettings.pug
+++ b/client/templates/includes/timespanSettings.pug
@@ -1,33 +1,113 @@
-div#preview-settings.card.card-body
+div#preview-settings.card
- div
+ div.card-header.pb-0
- h3.inline Timespan
+ h3.inline.mr-3 Timespan
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-preview-settings", data-hook="collapse") -
+ div.inline.mr-3
- div.collapse(class="show", id="collapse-preview-settings" data-hook="timespan-container")
+ ul.nav.nav-tabs.card-header-tabs(id="timespan-tabs")
- p Timespan settings are used for the preview and all workflows created using this model.
+ li.nav-item
- table.table
+ a.nav-link.tab.active(data-hook="timespan-edit-tab" data-toggle="tab" href="#edit-timespan") Edit
- thead
+ li.nav-item
- tr
+ a.nav-link.tab(data-hook="timespan-view-tab" data-toggle="tab" href="#view-timespan") View
- th(scope="col") Simulation Time
+ button.btn.btn-outline-collapse(data-toggle="collapse" data-target="#collapse-preview-settings" data-hook="collapse") -
- th(scope="col")
- div
- div.inline Sample Frequency
+ div.card-body
- div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.timeUnits)
+ p.mb-0
+ | Timespan settings are used for the preview and all workflows created using this model.
- tbody
+ div.collapse.tab-content(class="show" id="collapse-preview-settings" data-hook="timespan-container")
- tr
+ div.tab-pane.active(id="edit-timespan" data-hook="edit-timespan")
- td: div(data-hook="preview-time")
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3
+
+ h6 Simulation Time
+
+ div.col-sm-3
+
+ h6.inline Sample Frequency
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.timeUnits)
+
+ div.col-sm-6
+
+ if this.parent.model.is_spatial
+ h6 Timestep Size
+
+ div.mx-1.my-3.row
+
+ div.col-sm-3(data-hook="preview-time")
+
+ div.col-sm-3(data-hook="time-units")
+
+ div.col-sm-6
+
+ if this.parent.model.is_spatial
+ div
+
+ div.row
+
+ div.col-sm-1
+
+ span.inline 1
+
+ div.col-sm-8
+
+ span.mr-2.inline Current Value:
+
+ div.inline(data-hook="timestep-size-value")
+
+ div.col-sm-3.d-flex.justify-content-end
+
+ span.inline 1e-5
+
+ input.custom-range(
+ type="range"
+ min="0"
+ max="5"
+ step="1"
+ value=this.tssValue
+ data-hook="timestep-size-slider"
+ )
+
+ div.tab-pane(id="view-timespan" data-hook="view-timespan")
+
+ hr
+
+ div.mx-1.row.head.align-items-baseline
+
+ div.col-sm-3
+
+ h6 Simulation Time
+
+ div.col-sm-3
+
+ h6 Sample Frequency
+
+ div.col-sm-3
+
+ if this.parent.model.is_spatial
+ h6 Timestep Size
+
+ div.mx-1.my-3.row
+
+ div.col-sm-3(data-hook="view-end-sim")="0 to " + this.model.endSim
+
+ div.col-sm-3(data-hook="view-time-step")=this.model.timeStep
+
+ if this.parent.model.is_spatial
+ div.col-sm-6(data-hook="view-timestep-size")=this.model.timestepSize
+
- td: div(data-hook="time-units")
diff --git a/client/templates/includes/viewBoundaryCondition.pug b/client/templates/includes/viewBoundaryCondition.pug
new file mode 100644
index 0000000000..6ea4db586d
--- /dev/null
+++ b/client/templates/includes/viewBoundaryCondition.pug
@@ -0,0 +1,20 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-md-3
+
+ div.pl-2=this.model.name
+
+ div.col-md-7
+
+ div(style="white-space:pre;")=this.model.expression
+
+ div.col-md-2
+
+ if this.model.annotation
+
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewDomainType.pug b/client/templates/includes/viewDomainType.pug
new file mode 100644
index 0000000000..1baecacecc
--- /dev/null
+++ b/client/templates/includes/viewDomainType.pug
@@ -0,0 +1,22 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 1)
+ hr
+
+ div.row
+
+ div.col-sm-2
+
+ div.pl-2=this.model.name
+
+ div.col-sm-2=this.model.numParticles
+
+ div.col-sm-2=this.model.mass
+
+ div.col-sm-2=this.model.volume
+
+ div.col-sm-2=this.model.nu
+
+ div.col-sm-2
+
+ input(type="checkbox" checked=this.model.fixed disabled)
diff --git a/client/templates/includes/viewEventAssignment.pug b/client/templates/includes/viewEventAssignment.pug
new file mode 100644
index 0000000000..dc2a1867fc
--- /dev/null
+++ b/client/templates/includes/viewEventAssignment.pug
@@ -0,0 +1,14 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-sm-3
+
+ div.pl-2=this.model.variable.name
+
+ div.col-sm-7
+
+ div=this.model.expression
diff --git a/client/templates/includes/viewEventAssignments.pug b/client/templates/includes/viewEventAssignments.pug
deleted file mode 100644
index 6d9f62e879..0000000000
--- a/client/templates/includes/viewEventAssignments.pug
+++ /dev/null
@@ -1,5 +0,0 @@
-tr
-
- td=this.model.variable.name
-
- td=this.model.expression
\ No newline at end of file
diff --git a/client/templates/includes/viewEvents.pug b/client/templates/includes/viewEvents.pug
index a26dfb151f..ef20893766 100644
--- a/client/templates/includes/viewEvents.pug
+++ b/client/templates/includes/viewEvents.pug
@@ -1,45 +1,51 @@
-tr
+div.mx-1
- td: div.name=this.model.name
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td=this.model.triggerExpression
+ div.row
- td: div(data-hook="assignment-viewer")
+ div.col-sm-2
- td
+ div.pl-2=this.model.name
- div="Delay: "+this.delay
+ div.col-sm-2=this.model.triggerExpression
- div="Priority: "+this.model.priority
+ div.col-sm-4(data-hook="assignment-viewer")
- div
+ div.col-sm-2
- span.checkbox(for="initial-value") Initial Value:
+ div="Delay: "+this.delay
- input(type="checkbox", id="initial-value", data-hook="event-trigger-init-value" disabled)
+ div="Priority: "+this.model.priority
- div
+ div
- span.checkbox(for="persistent") Persistent:
+ span.checkbox(for="initial-value") Initial Value:
- input(type="checkbox", id="persistent", data-hook="event-trigger-persistent" disabled)
+ input(type="checkbox", id="initial-value", data-hook="event-trigger-init-value" disabled)
- div.event-adv-header Use Values From
+ div
- div
+ span.checkbox(for="persistent") Persistent:
- input(type="radio", id="trigger-time", name="use-values-from" data-hook="trigger-time" disabled)
+ input(type="checkbox", id="persistent", data-hook="event-trigger-persistent" disabled)
- span.inline.horizontal-space(for="trigger-time") Trigger Time
+ div.event-adv-header Use Values From
- div
+ div
- input(type="radio", id="assignment-time", name="use-values-from" data-hook="assignment-time" disabled)
+ input(type="radio", id="trigger-time", name="view-use-values-from" data-hook="view-trigger-time" disabled)
- span.inline.horizontal-space(for="assignment-time") Assignment Time
+ span.inline.horizontal-space(for="trigger-time") Trigger 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")
+ div
- if this.parent.containsMdlWithAnn && !this.model.annotation
- td: div
+ input(type="radio", id="assignment-time", name="view-use-values-from" data-hook="view-assignment-time" disabled)
+
+ span.inline.horizontal-space(for="assignment-time") Assignment Time
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewFunctionDefinition.pug b/client/templates/includes/viewFunctionDefinition.pug
new file mode 100644
index 0000000000..cdfc4ac78a
--- /dev/null
+++ b/client/templates/includes/viewFunctionDefinition.pug
@@ -0,0 +1,15 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-sm-10
+
+ div.pl-2=this.model.signature
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewInitialCondition.pug b/client/templates/includes/viewInitialCondition.pug
index 34f4017019..68d6623a66 100644
--- a/client/templates/includes/viewInitialCondition.pug
+++ b/client/templates/includes/viewInitialCondition.pug
@@ -1,17 +1,33 @@
-tr
+div.mx-1
- td=this.model.icType
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td=this.model.specie.name
+ div.row
- td=this.model.count
+ div.col-sm-2
- td
+ div.pl-2=this.model.icType
- if this.model.icType === "Place"
- span Location:
- div="(x: "+this.model.x+", y: "+this.model.y+", z: "+this.model.z+")"
-
- else
- span Active in Types:
- div=this.types.join(", ")
+ div.col-sm-2
+
+ div=this.model.specie.name
+
+ div.col-sm-2
+
+ div=this.model.count
+
+ div.col-sm-4
+
+ if this.model.icType === "Place"
+ span Location:
+ div="(x: "+this.model.x+", y: "+this.model.y+", z: "+this.model.z+")"
+
+ else
+ span Active in Types:
+ div=this.types.join(", ")
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewReactions.pug b/client/templates/includes/viewReactions.pug
index 582e48dae1..21be6b3275 100644
--- a/client/templates/includes/viewReactions.pug
+++ b/client/templates/includes/viewReactions.pug
@@ -1,15 +1,24 @@
-tr
- td=this.model.name
+div.mx-1
- td: div(data-hook="summary")
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td=this.rate
+ div.row.align-items-baseline
- if this.model.collection.parent.is_spatial
- td: div=this.types.join(', ')
+ div.col-md-2
- 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")
+ div.pl-2=this.model.name
- if this.parent.containsMdlWithAnn && !this.model.annotation
- td: div
+ div.col-md-3(data-hook="summary")
+
+ div.col-md-3=this.rate
+
+ if this.model.collection.parent.is_spatial
+ div.col-md-2(data-hook="reaction-types")
+
+ div=this.types.join(', ')
+
+ div.col-md-2(data-hook="reaction-annotation-header")
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation)
diff --git a/client/templates/includes/viewRules.pug b/client/templates/includes/viewRules.pug
index f4b039523b..30bacfe4dd 100644
--- a/client/templates/includes/viewRules.pug
+++ b/client/templates/includes/viewRules.pug
@@ -1,14 +1,19 @@
-tr
- td=this.model.name
+div.mx-1
- td=this.model.type
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td=this.model.variable.name
+ div.row
- td=this.model.expression
+ div.col-sm-2=this.model.name
- 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")
+ div.col-sm-2=this.model.type
- if this.parent.containsMdlWithAnn && !this.model.annotation
- td: div
+ div.col-sm-2=this.model.variable.name
+
+ div.col-sm-4=this.model.expression
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewSpatialSpecies.pug b/client/templates/includes/viewSpatialSpecies.pug
new file mode 100644
index 0000000000..4af4396fa9
--- /dev/null
+++ b/client/templates/includes/viewSpatialSpecies.pug
@@ -0,0 +1,23 @@
+div.mx-1
+
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
+
+ div.row
+
+ div.col-sm-2
+
+ div.pl-2=this.model.name
+
+ div.col-sm-2
+
+ div=this.model.diffusionConst
+
+ div.col-sm-6
+
+ div=this.types.join(", ")
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/includes/viewSpecies.pug b/client/templates/includes/viewSpecies.pug
index e5ab763ec9..a792c44923 100644
--- a/client/templates/includes/viewSpecies.pug
+++ b/client/templates/includes/viewSpecies.pug
@@ -1,21 +1,27 @@
-tr
- td=this.model.name
+div.mx-1
- if this.model.collection.parent.is_spatial
- td=this.model.diffusionConst
+ if(this.model.collection.indexOf(this.model) !== 0)
+ hr
- td=this.types.join(", ")
- else
- td=this.model.value
+ div.row
- td=this.model.mode
+ div.col-sm-2
- if this.model.collection.parent.defaultMode === 'dynamic'
- td=this.switchingValWithLabel
+ div.pl-2=this.model.name
- 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")
+ div.col-sm-2
- if this.parent.containsMdlWithAnn && !this.model.annotation
- td: div
-
\ No newline at end of file
+ div=this.model.value
+
+ div.col-sm-2
+
+ div=this.model.mode
+
+ if this.model.mode === "dynamic"
+ div.col-sm-4
+ div=this.switchingValWithLabel
+
+ div.col-sm-2
+
+ if this.model.annotation
+ div.tooltip-icon-large(data-hook="annotation-tooltip" data-html="true" data-toggle="tooltip" title=this.model.annotation || "Click 'Add' to add an annotation")
diff --git a/client/templates/pages/modelEditor.pug b/client/templates/pages/modelEditor.pug
index eeb3660d85..1c1d3cc683 100644
--- a/client/templates/pages/modelEditor.pug
+++ b/client/templates/pages/modelEditor.pug
@@ -26,6 +26,26 @@ section.page
ol.breadcrumb
li.breadcrumb-item.active(aria-current="page")=this.model.name
+ div.card
+
+ div.card-header.pb-0
+
+ h3.inline Model Mode
+
+ div.tooltip-icon(data-html="true" data-toggle="tooltip" title=this.tooltips.modelMode)
+
+ div.card-body
+ div.row
+ div.col-sm-4
+ input.mr-2(type="radio" name="default-mode" data-hook="all-continuous" data-name="continuous")
+ span Concentration
+ div.col-sm-4
+ input.mr-2(type="radio" name="default-mode" data-hook="all-discrete" data-name="discrete")
+ span Population
+ div.col-sm-4(data-hook="advaced-model-mode")
+ input.mr-2(type="radio" name="default-mode" data-hook="advanced" data-name="dynamic")
+ span Hybrid Concentration/Population
+
div(data-hook="domain-viewer-container")
div(data-hook="species-editor-container")
@@ -36,9 +56,9 @@ section.page
div(data-hook="reactions-editor-container")
- div.card.card-body(data-hook="model-editor-advanced-container")
+ div.card(data-hook="model-editor-advanced-container")
- div
+ div.card-header.pb-0
h3.inline Advanced
@@ -46,26 +66,54 @@ section.page
div.collapse(id="me-advanced-section", data-hook="me-advanced-section")
- div(data-hook="events-editor-container")
+ div.card-body
- div(data-hook="rules-editor-container")
+ div(data-hook="events-editor-container")
- div(data-hook="sbml-component-container")
+ div(data-hook="rules-editor-container")
- div.card.card-body.collapse.show(data-hook="system-volume-container")
+ div(data-hook="boundary-conditions-container")
- div
+ div(data-hook="sbml-component-container")
- h3.inline System Volume
- button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-system-volume", data-hook="collapse-system-volume") +
+ div.card.collapse.show(data-hook="system-volume-container")
- div.collapse(id="collapse-system-volume" data-hook="system-volume-section")
-
- 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.card-header.pb-0
+
+ h3.inline.mr-3 System Volume
+
+ div.inline.mr-3
+
+ ul.nav.nav-tabs.card-header-tabs(id="volume-tabs")
+
+ li.nav-item
+
+ a.nav-link.tab.active(data-hook="volume-edit-tab" data-toggle="tab" href="#edit-system-volume") Edit
+
+ li.nav-item
+
+ a.nav-link.tab(data-hook="volume-view-tab" data-toggle="tab" href="#view-system-volume") View
+
+ button.btn.btn-outline-collapse(data-toggle="collapse", data-target="#collapse-system-volume", data-hook="collapse-system-volume") +
+
+ div.card-body
+
+ p.mb-0
+ | 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. In most cases this should not be changed. please review your model requirements carefully before changing this property.
+
+ div.collapse.tab-content(id="collapse-system-volume" data-hook="system-volume-section")
+
+ div.tab-pane.active(id="edit-system-volume" data-hook="edit-system-volume")
+
+ hr
+
+ div(data-hook="edit-volume")
+
+ div.tab-pane(id="view-system-volume" data-hook="view-system-volume")
- hr
+ hr
- div(data-hook="volume")
+ div(data-hook="view-volume")
div(data-hook="model-settings-container")
diff --git a/client/tooltips.js b/client/tooltips.js
index 4c426230a2..56fc32971c 100644
--- a/client/tooltips.js
+++ b/client/tooltips.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,6 +17,13 @@ along with this program. If not, see .
*/
module.exports = {
+ modelEditor: {
+ modelMode: "Concentration - Variables will only be represented using continuous (floating point) values.
Population - Variables will only be represented "+
+ "using discrete (integer count) values.
Hybrid Concentration/Population - Allows a variables to be represented using continuous and/or discrete values.",
+
+ spatialModelMode: "Concentration - Variables will only be represented using continuous (floating point) values.
Population - Variables will only be represented "+
+ "using discrete (integer count) values."
+ },
speciesEditor: {
name: "Unique identifier for Variable. Cannot share a name with other model components.",
@@ -26,12 +33,6 @@ module.exports = {
remove: "A variables may only be removed if it is not a part of any reaction, event assignment, or rule.",
- speciesMode: "Concentration - Variables will only be represented using continuous (floating point) values.
Population - Variables will only be represented "+
- "using discrete (integer count) values.
Hybrid Concentration/Population - Allows a variables to be represented using continuous and/or discrete values.",
-
- spatialSpeciesMode: "Concentration - Variables will only be represented using continuous (floating point) values.
Population - Variables will only be represented "+
- "using discrete (integer count) values.",
-
mode: "Concentration - Variables will only be represented using continuous (floating point) values.
Population - Variables will only be represented "+
"using discrete (integer count) values.
Hybrid Concentration/Population - Allows a variables to be represented using continuous and/or discrete values.",
@@ -39,6 +40,9 @@ module.exports = {
"of a variables after a given time step. This value will be used if a 'Minimum Value' not provided.
Minimum Value For Switching - Minimum population value "+
"at which variables will be represented as Concentration."
},
+ initialConditionsEditor: {
+ annotation: "An optional note about the initial conditions."
+ },
parametersEditor: {
name: "Unique identifier for Parameter. Cannot share a name with other model components.",
@@ -178,5 +182,8 @@ module.exports = {
pressure: "Atmospheric or background pressure.",
speed: "Approximate or artificial speed of sound"
+ },
+ boundaryConditionsEditor: {
+ annotation: "An optional note about a boundary condition."
}
}
diff --git a/client/views/archive-listing.js b/client/views/archive-listing.js
index e5bb93c18b..9aacef63b1 100644
--- a/client/views/archive-listing.js
+++ b/client/views/archive-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/boundary-condition-view.js b/client/views/boundary-condition-view.js
new file mode 100644
index 0000000000..a91cf1b9fb
--- /dev/null
+++ b/client/views/boundary-condition-view.js
@@ -0,0 +1,86 @@
+/*
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+let $ = require('jquery');
+//support files
+let modals = require('../modals');
+//views
+let View = require('ampersand-view');
+//templates
+let editTemplate = require('../templates/includes/editBoundaryCondition.pug');
+let viewTemplate = require('../templates/includes/viewBoundaryCondition.pug');
+
+module.exports = View.extend({
+ events: {
+ 'click [data-hook=expand]' : 'toggleExpressionView',
+ 'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
+ 'click [data-hook=remove]' : 'removeBoundaryCondition'
+ },
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false
+ },
+ render: function (attrs, options) {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
+ View.prototype.render.apply(this, arguments);
+ $(document).on('shown.bs.modal', function (e) {
+ $('[autofocus]', e.target).focus();
+ });
+ $(document).on('hide.bs.modal', '.modal', function (e) {
+ e.target.remove()
+ });
+ if(!this.model.annotation){
+ $(this.queryByHook('edit-annotation-btn')).text('Add')
+ }
+ },
+ editAnnotation: function () {
+ let self = this;
+ let name = this.model.name;
+ let annotation = this.model.annotation;
+ if(document.querySelector('#boundaryConditionAnnotationModal')) {
+ document.querySelector('#boundaryConditionAnnotationModal').remove();
+ }
+ let modal = $(modals.annotationModalHtml("boundaryCondition", name, annotation)).modal();
+ let okBtn = document.querySelector('#boundaryConditionAnnotationModal .ok-model-btn');
+ let input = document.querySelector('#boundaryConditionAnnotationModal #boundaryConditionAnnotationInput');
+ input.addEventListener("keyup", function (event) {
+ if(event.keyCode === 13){
+ event.preventDefault();
+ okBtn.click();
+ }
+ });
+ okBtn.addEventListener('click', function (e) {
+ self.model.annotation = input.value.trim();
+ self.parent.renderEditBoundaryConditionView();
+ self.parent.renderViewBoundaryConditionView();
+ modal.modal('hide');
+ });
+ },
+ removeBoundaryCondition: function () {
+ this.model.collection.remove(this.model);
+ },
+ toggleExpressionView: function (e) {
+ if(e.target.textContent.startsWith("View")){
+ $(this.queryByHook("expand")).html("Hide Expression");
+ $(this.queryByHook("expression")).css("display", "block");
+ }else{
+ $(this.queryByHook("expand")).html("View Expression");
+ $(this.queryByHook("expression")).css("display", "none");
+ }
+ }
+});
\ No newline at end of file
diff --git a/client/views/boundary-conditions-editor.js b/client/views/boundary-conditions-editor.js
new file mode 100644
index 0000000000..bfc9607a00
--- /dev/null
+++ b/client/views/boundary-conditions-editor.js
@@ -0,0 +1,394 @@
+/*
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+let $ = require('jquery');
+let path = require('path');
+//support files
+let app = require('../app');
+let tests = require('./tests');
+let Tooltips = require('../tooltips');
+//views
+let InputView = require('./input');
+let View = require('ampersand-view');
+let SelectView = require('ampersand-select-view');
+let BoundaryConditionView = require('./boundary-condition-view');
+//templates
+let template = require('../templates/includes/boundaryConditionsEditor.pug');
+
+module.exports = View.extend({
+ template: template,
+ events: {
+ 'change [data-hook=new-bc-name]' : 'handleSetValue',
+ 'change [data-hook=new-bc-target]' : 'handleSetTarget',
+ 'change [data-hook=new-bc-deterministic]' : 'handleSetDeterministic',
+ 'change [data-hook=new-bc-type]' : 'handleSetValue',
+ 'change [data-hook=new-bc-value]' : 'handleSetValue',
+ 'change [data-hook=new-bc-value-x]' : 'handleSetValue',
+ 'change [data-hook=new-bc-value-y]' : 'handleSetValue',
+ 'change [data-hook=new-bc-value-z]' : 'handleSetValue',
+ 'change [data-hook=new-bc-x-min]' : 'handleSetValue',
+ 'change [data-hook=new-bc-x-max]' : 'handleSetValue',
+ 'change [data-hook=new-bc-y-min]' : 'handleSetValue',
+ 'change [data-hook=new-bc-y-max]' : 'handleSetValue',
+ 'change [data-hook=new-bc-z-min]' : 'handleSetValue',
+ 'change [data-hook=new-bc-z-max]' : 'handleSetValue',
+ 'click [data-hook=collapse-bc]' : 'changeCollapseButtonText',
+ 'click [data-hook=collapse-new-bc' : 'changeCollapseButtonText',
+ 'click [data-hook=add-new-bc]' : 'handleAddBCClick'
+ },
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
+ this.tooltips = Tooltips.boundaryConditionsEditor;
+ this.setDefaultBC();
+ },
+ render: function (attrs, options) {
+ View.prototype.render.apply(this, arguments);
+ if(this.readOnly) {
+ $(this.queryByHook('bc-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('bc-view-tab')).tab('show');
+ $(this.queryByHook('edit-boundary-conditions')).removeClass('active');
+ $(this.queryByHook('view-boundary-conditions')).addClass('active');
+ }else{
+ this.renderEditBoundaryConditionView();
+ this.toggleAddNewBCButton();
+ }
+ this.renderViewBoundaryConditionView();
+ },
+ changeCollapseButtonText: function (e) {
+ app.changeCollapseButtonText(this, e);
+ },
+ handleAddBCClick: function (e) {
+ let endpoint = path.join(app.getApiPath(), "model/new-bc")
+ let self = this;
+ if(this.newBC.property === "v") {
+ this.newBC.value = this.newBCVector
+ }
+ let data = {model_path: this.collection.parent.directory,
+ kwargs: this.newBC}
+ app.postXHR(endpoint, data, {
+ success: function (err, response, body) {
+ self.collection.addNewBoundaryCondition(self.newBCName, body.expression);
+ self.setDefaultBC();
+ self.resetNewBCViews();
+ }
+ });
+ },
+ handleSetDeterministic: function (e) {
+ this.newBC.deterministic = e.target.checked;
+ },
+ handleSetTarget: function (e) {
+ let properties = ["v", "nu", "rho"];
+ let target = e.target.value;
+ if(properties.includes(target)) {
+ if(target === "v") {
+ $(this.queryByHook("new-bc-other-value")).css("display", "none");
+ $(this.queryByHook("new-bc-velocity-value")).css("display", "block");
+ }else {
+ $(this.queryByHook("new-bc-velocity-value")).css("display", "none");
+ $(this.queryByHook("new-bc-other-value")).css("display", "block");
+ }
+ this.newBC.property = target;
+ this.newBC.species = null;
+ $(this.queryByHook("new-bc-deterministic")).prop("disabled", true);
+ }else{
+ let species = this.collection.parent.species.filter(function (specie) {
+ return specie.compID === Number(target)
+ })[0].name;
+ this.newBC.property = null;
+ this.newBC.species = species;
+ $(this.queryByHook("new-bc-deterministic")).prop("disabled", false);
+ }
+ },
+ handleSetValue: function (e) {
+ let key = e.delegateTarget.dataset.target;
+ let value = e.target.value;
+ if(key === "name") {
+ this.newBCName = value;
+ }else{
+ if(key.endsWith("min") || key.endsWith("max") || key === "type_id"){
+ this.newBC[key] = this.validateNewBCCondition(key, value);
+ }else if(key === "value") {
+ if(e.delegateTarget.dataset.hook.endsWith("x")) {
+ this.newBCVector[0] = value === "" ? 0 : value
+ }else if(e.delegateTarget.dataset.hook.endsWith("y")) {
+ this.newBCVector[1] = value === "" ? 0 : value
+ }else if(e.delegateTarget.dataset.hook.endsWith("z")) {
+ this.newBCVector[2] = value === "" ? 0 : value
+ }else{
+ this.newBC[key] = value === "" ? null : value
+ }
+ }
+ }
+ this.toggleAddNewBCButton();
+ },
+ renderEditBoundaryConditionView: function () {
+ if(this.editBoundaryConditionView) {
+ this.editBoundaryConditionView.remove();
+ }
+ this.editBoundaryConditionView = this.renderCollection(
+ this.collection,
+ BoundaryConditionView,
+ this.queryByHook("edit-boundary-conditions-list")
+ );
+ $(document).ready(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ renderViewBoundaryConditionView: function () {
+ if(this.viewBoundaryConditionView) {
+ this.viewBoundaryConditionView.remove();
+ }
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("bc-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("bc-annotation-header")).css("display", "block");
+ }
+ let options = {viewOptions: {viewMode: true}};
+ this.viewBoundaryConditionView = this.renderCollection(
+ this.collection,
+ BoundaryConditionView,
+ this.queryByHook("view-boundary-conditions-list"),
+ options
+ );
+ },
+ resetNewBCViews: function () {
+ $(this.queryByHook("new-bc-deterministic")).prop("checked", this.newBC.deterministic);
+ $(this.queryByHook("new-bc-name")).find("input").val(this.newBCName);
+ $(this.queryByHook("new-bc-target")).find("select").val(this.newBC.property);
+ $(this.queryByHook("new-bc-type")).find("input").val(this.newBC.type_id);
+ $(this.queryByHook("new-bc-value")).find("input").val(this.newBC.value);
+ $(this.queryByHook("new-bc-x-min")).find("input").val(this.newBC.xmin);
+ $(this.queryByHook("new-bc-x-max")).find("input").val(this.newBC.xmax);
+ $(this.queryByHook("new-bc-y-min")).find("input").val(this.newBC.ymin);
+ $(this.queryByHook("new-bc-y-max")).find("input").val(this.newBC.ymax);
+ $(this.queryByHook("new-bc-z-min")).find("input").val(this.newBC.zmin);
+ $(this.queryByHook("new-bc-z-max")).find("input").val(this.newBC.zmax);
+ $(this.queryByHook("new-bc-deterministic")).prop("disabled", true);
+ this.toggleAddNewBCButton();
+ },
+ setDefaultBC: function () {
+ this.newBCName = "";
+ this.newBC = {"species": null, "property": "v", "value": null, "deterministic": true, "type_id": null,
+ "xmin": null, "ymin": null, "zmin": null, "xmax": null, "ymax": null, "zmax": null};
+ this.newBCVector = [0, 0, 0]
+ this.setConditions = [];
+ },
+ toggleAddNewBCButton: function () {
+ let invalidName = this.newBCName === ""
+ let invalidValue = this.newBC.property === "v" ? this.newBCVector === [0, 0, 0] : this.newBC.value === null
+ let disabled = invalidName || invalidValue || !this.setConditions.length;
+ $(this.queryByHook("add-new-bc")).prop("disabled", disabled);
+ },
+ update: function (e) {},
+ validateNewBCCondition: function(key, value) {
+ if((value === 0 && key === "type_id") || value === "") {
+ value = null
+ if(this.setConditions.includes(key)){
+ let index = this.setConditions.indexOf(key);
+ this.setConditions.splice(index, 1);
+ }
+ }else if(!this.setConditions.includes(key)){
+ this.setConditions.push(key);
+ }
+ return value;
+ },
+ subviews: {
+ newBCName: {
+ hook: "new-bc-name",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'name',
+ valueType: 'string',
+ value: this.newBCName
+ });
+ }
+ },
+ newBCTarget: {
+ hook: "new-bc-target",
+ prepareView: function (el) {
+ let species = this.collection.parent.species.map(function (specie) {
+ return [specie.compID, specie.name]
+ });
+ let properties = [["v", "Velocity"], ["nu", "Viscosity"], ["rho", "Density"]]
+ let options = [{groupName: "Properties", options: properties},
+ {groupName: "Variables", options: species}]
+ return new SelectView({
+ parent: this,
+ required: false,
+ name: 'target',
+ eagerValidate: true,
+ groupOptions: options,
+ value: this.newBC.property
+ });
+ }
+ },
+ newBCValue: {
+ hook: "new-bc-value",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'value',
+ tests: tests.valueTests,
+ valueType: 'number',
+ });
+ }
+ },
+ newBCValueX: {
+ hook: "new-bc-value-x",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'value-x',
+ tests: tests.valueTests,
+ valueType: 'number',
+ label: "X: "
+ });
+ }
+ },
+ newBCValueY: {
+ hook: "new-bc-value-y",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'value-y',
+ tests: tests.valueTests,
+ valueType: 'number',
+ label: "Y: "
+ });
+ }
+ },
+ newBCValueZ: {
+ hook: "new-bc-value-z",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'value-z',
+ tests: tests.valueTests,
+ valueType: 'number',
+ label: "Z: "
+ });
+ }
+ },
+ newBCxmin: {
+ hook: "new-bc-x-min",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'xmin',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.xmin,
+ });
+ }
+ },
+ newBCymin: {
+ hook: "new-bc-y-min",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'ymin',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.ymin,
+ });
+ }
+ },
+ newBCzmin: {
+ hook: "new-bc-z-min",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'zmin',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.zmin,
+ });
+ }
+ },
+ newBCxmax: {
+ hook: "new-bc-x-max",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'xmax',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.xmax,
+ });
+ }
+ },
+ newBCymax: {
+ hook: "new-bc-y-max",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'ymax',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.ymax,
+ });
+ }
+ },
+ newBCzmax: {
+ hook: "new-bc-z-max",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'zmax',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.zmax,
+ });
+ }
+ },
+ newBCType: {
+ hook: "new-bc-type",
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: false,
+ name: 'type',
+ tests: tests.valueTests,
+ valueType: 'number',
+ value: this.newBC.type_id,
+ });
+ }
+ }
+ }
+});
\ No newline at end of file
diff --git a/client/views/component-types.js b/client/views/component-types.js
index d5856b2693..f96375fa28 100644
--- a/client/views/component-types.js
+++ b/client/views/component-types.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -46,5 +46,6 @@ module.exports = View.extend({
let index = this.parent.model.types.indexOf(typeID);
this.parent.model.types.splice(index, 1);
}
+ this.parent.model.trigger('change');
}
});
\ No newline at end of file
diff --git a/client/views/creator-listing.js b/client/views/creator-listing.js
index 847f8f1b92..016b6e5d21 100644
--- a/client/views/creator-listing.js
+++ b/client/views/creator-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/domain-viewer.js b/client/views/domain-viewer.js
index edaff605a7..2ff51bcc60 100644
--- a/client/views/domain-viewer.js
+++ b/client/views/domain-viewer.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ var Plotly = require('../lib/plotly');
var Tooltips = require('../tooltips');
//views
var View = require('ampersand-view');
-var TypesViewer = require('./view-domain-types');
+var TypesViewer = require('./edit-domain-type');
var SelectView = require('ampersand-select-view');
var ParticleViewer = require('./view-particle');
//templates
@@ -34,14 +34,65 @@ var template = require('../templates/includes/domainViewer.pug');
module.exports = View.extend({
template: template,
events: {
+ 'click [data-hook=domain-edit-tab]' : 'toggleViewExternalDomainBtn',
+ 'click [data-hook=domain-view-tab]' : 'toggleViewExternalDomainBtn',
'click [data-hook=collapse]' : 'changeCollapseButtonText',
- 'click [data-hook=edit-domain]' : 'editDomain',
+ 'click [data-hook=edit-domain-btn]' : 'editDomain',
'click [data-hook=create-domain]' : 'editDomain',
'click [data-hook=save-to-model]' : 'saveDomainToModel',
'click [data-hook=select-external-domain]' : 'handleLoadExternalDomain',
'change [data-hook=select-domain]' : 'handleSelectDomain',
'change [data-hook=select-location]' : 'handleSelectDomainLocation'
},
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
+ this.tooltips = Tooltips.domainEditor;
+ this.domainPath = attrs.domainPath;
+ let self = this;
+ this.model.particles.forEach(function (particle) {
+ self.model.types.get(particle.type, "typeID").numParticles += 1;
+ });
+ this.gravity = this.getGravityString()
+ },
+ render: function () {
+ View.prototype.render.apply(this, arguments);
+ let self = this;
+ var queryStr = "?path=" + this.parent.model.directory
+ if(this.readOnly) {
+ $(this.queryByHook('domain-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('domain-view-tab')).tab('show');
+ $(this.queryByHook('edit-domain')).removeClass('active');
+ $(this.queryByHook('view-domain')).addClass('active');
+ this.toggleViewExternalDomainBtn();
+ }else {
+ this.renderDomainSelectView();
+ if(this.domainPath) {
+ $(this.queryByHook("domain-container")).collapse("show")
+ $(this.queryByHook("collapse")).text("-")
+ if(this.domainPath !== "viewing") {
+ $(this.queryByHook("save-to-model")).prop("disabled", false)
+ $(this.queryByHook("external-domain-select")).css("display", "block")
+ $(this.queryByHook("select-external-domain")).text("View Model's Domain")
+ queryStr += "&domain_path=" + this.domainPath
+ }
+ }
+ this.toggleDomainError();
+ }
+ this.renderTypesViewer();
+ this.parent.renderParticleViewer(null);
+ let endpoint = path.join(app.getApiPath(), "spatial-model/domain-plot") + queryStr;
+ app.getXHR(endpoint, {
+ always: function (err, response, body) {
+ self.plot = body.fig;
+ self.displayDomain();
+ }
+ });
+ },
handleLoadExternalDomain: function (e) {
let text = e.target.textContent
if(text === "View External Domain") {
@@ -78,48 +129,12 @@ module.exports = View.extend({
this.parent.renderDomainViewer(domainPath);
}
},
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- this.tooltips = Tooltips.domainEditor;
- this.domainPath = attrs.domainPath;
- let self = this;
- this.model.particles.forEach(function (particle) {
- self.model.types.get(particle.type, "typeID").numParticles += 1;
- });
- this.gravity = this.getGravityString()
- },
getGravityString: function () {
var gravity = "(X: " + this.model.gravity[0];
gravity += ", Y: " + this.model.gravity[1];
gravity += ", Z: " + this.model.gravity[2] + ")";
return gravity;
},
- render: function () {
- View.prototype.render.apply(this, arguments);
- this.renderDomainSelectView();
- this.renderTypesViewer();
- let self = this;
- var queryStr = "?path=" + this.parent.model.directory
- if(this.domainPath) {
- $(this.queryByHook("domain-container")).collapse("show")
- $(this.queryByHook("collapse")).text("-")
- if(this.domainPath !== "viewing") {
- $(this.queryByHook("save-to-model")).prop("disabled", false)
- $(this.queryByHook("external-domain-select")).css("display", "block")
- $(this.queryByHook("select-external-domain")).text("View Model's Domain")
- queryStr += "&domain_path=" + this.domainPath
- }
- }
- this.parent.renderParticleViewer(null);
- let endpoint = path.join(app.getApiPath(), "spatial-model/domain-plot") + queryStr;
- app.getXHR(endpoint, {
- always: function (err, response, body) {
- self.plot = body.fig;
- self.displayDomain();
- }
- });
- this.toggleDomainError();
- },
renderDomainSelectView: function () {
let self = this;
let endpoint = path.join(app.getApiPath(), "spatial-model/domain-list");
@@ -171,9 +186,9 @@ module.exports = View.extend({
this.model.types,
TypesViewer,
this.queryByHook("domain-types-list"),
- {"filter": function (model) {
+ {filter: function (model) {
return model.typeID != 0;
- }}
+ }, viewOptions: {viewMode: true}}
);
},
displayDomain: function () {
@@ -213,6 +228,17 @@ module.exports = View.extend({
errorMsg.removeClass('component-invalid')
}
},
+ toggleViewExternalDomainBtn: function (e) {
+ if(e) {
+ if(!e.target.classList.contains("active")) {
+ let display = e.target.text === "View" ? "none" : "block";
+ $(this.queryByHook("external-domains-container")).css("display", display);
+ }
+ }else{
+ let display = this.readOnly ? "none" : "block";
+ $(this.queryByHook("external-domains-container")).css("display", display);
+ }
+ },
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
}
diff --git a/client/views/edit-3D-domain.js b/client/views/edit-3D-domain.js
index 5513d14991..e1161faf3f 100644
--- a/client/views/edit-3D-domain.js
+++ b/client/views/edit-3D-domain.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/edit-advanced-specie.js b/client/views/edit-advanced-specie.js
deleted file mode 100644
index 33c6ac446a..0000000000
--- a/client/views/edit-advanced-specie.js
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-var tests = require('./tests');
-//views
-var View = require('ampersand-view');
-var SelectView = require('ampersand-select-view');
-var InputView = require('./input');
-//templates
-var template = require('../templates/includes/editAdvancedSpecie.pug');
-
-module.exports = View.extend({
- template: template,
- events: {
- 'change [data-hook=switching-tol]' : 'setSwitchingType',
- 'change [data-hook=switching-min]' : 'setSwitchingType',
- 'change [data-hook=specie-mode]' : 'setSpeciesMode',
- },
- initialize: function () {
- View.prototype.initialize.apply(this, arguments);
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- var optionDict = {"continuous":"Concentration", "discrete":"Population", "dynamic":"Hybrid Concentration/Population"}
- var modeSelectView = new SelectView({
- label: '',
- name: 'mode',
- required: true,
- idAttributes: 'cid',
- options: ['Concentration','Population','Hybrid Concentration/Population'],
- value: optionDict[this.model.mode],
- });
- app.registerRenderSubview(this, modeSelectView, "specie-mode")
- if(this.model.isSwitchTol){
- $(this.queryByHook('switching-tol')).prop('checked', true);
- }else{
- $(this.queryByHook('switching-min')).prop('checked', true);
- }
- this.toggleSwitchingSettings();
- this.updateInputValidation();
- },
- update: function () {
- },
- updateValid: function () {
- },
- setSpeciesMode: function (e) {
- var value = e.target.selectedOptions.item(0).text
- var modeDict = {"Concentration":"continuous","Population":"discrete","Hybrid Concentration/Population":"dynamic"}
- this.model.mode = modeDict[value]
- this.model.collection.trigger('update-species', this.model.compID, this.model, false, false);
- this.updateInputValidation();
- this.toggleSwitchingSettings();
- },
- setSwitchingType: function (e) {
- this.model.isSwitchTol = $(this.queryByHook('switching-tol')).is(":checked");
- this.updateInputValidation();
- this.toggleSwitchingSettingsInput();
- },
- updateInputValidation: function () {
- // Update validation requirements and re-run tests for inputSwitchTol.
- // This removes error reporting not using switching tolerance
- let shouldValidateTol = this.model.mode === "dynamic" && this.model.isSwitchTol
- this.inputSwitchTol.required = shouldValidateTol;
- this.inputSwitchTol.tests = shouldValidateTol ? tests.valueTests : []
- this.inputSwitchTol.runTests()
- // Update validation requirements and re-run tests for inputSwitchMin.
- // This removes error reporting when not using minimum value for switching.
- let shouldValidateMin = this.model.mode === "dynamic" && !this.model.isSwitchTol
- this.inputSwitchMin.required = shouldValidateMin;
- this.inputSwitchMin.tests = shouldValidateMin ? tests.valueTests : []
- this.inputSwitchMin.runTests()
- // Add/Remove 'input-invalid' class from inputSwitchTol and inputSwitchMin based on whether
- // the user is using switching tolerance or minimum value for switching
- let tolInput = $(this.queryByHook('switching-tolerance')).find('input')[0]
- let minInput = $(this.queryByHook('switching-threshold')).find('input')[0]
- if(this.model.mode !== "dynamic") {
- $(tolInput).removeClass('input-invalid')
- $(minInput).removeClass('input-invalid')
- }else if(this.model.isSwitchTol){
- $(minInput).removeClass('input-invalid')
- if(this.model.switchTol === "" || isNaN(this.model.switchTol)){
- $(tolInput).addClass('input-invalid')
- }
- }else{
- $(tolInput).removeClass('input-invalid')
- if(this.model.switchMin === "" || isNaN(this.model.switchMin)){
- $(minInput).addClass('input-invalid')
- }
- }
- },
- toggleSwitchingSettingsInput: function () {
- if(this.model.isSwitchTol){
- $(this.queryByHook('switching-threshold')).find('input').prop('disabled', true);
- $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', false);
- }else{
- $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', true);
- $(this.queryByHook('switching-threshold')).find('input').prop('disabled', false);
- }
- },
- toggleSwitchingSettings: function () {
- if(this.model.mode === "dynamic"){
- $(this.queryByHook('switching-tol')).prop('disabled', false);
- $(this.queryByHook('switching-min')).prop('disabled', false);
- this.toggleSwitchingSettingsInput();
- }else{
- $(this.queryByHook('switching-tol')).prop('disabled', true);
- $(this.queryByHook('switching-min')).prop('disabled', true);
- $(this.queryByHook('switching-threshold')).find('input').prop('disabled', true);
- $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', true);
- }
- },
- subviews: {
- inputSwitchTol: {
- hook: 'switching-tolerance',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'switching-tolerance',
- label: '',
- tests: tests.valueTests,
- modelKey: 'switchTol',
- valueType: 'number',
- value: this.model.switchTol,
- });
- },
- },
- inputSwitchMin: {
- hook: 'switching-threshold',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'switching-threshold',
- label: '',
- tests: tests.valueTests,
- modelKey: 'switchMin',
- valueType: 'number',
- value: this.model.switchMin,
- });
- },
- },
- },
-});
\ No newline at end of file
diff --git a/client/views/edit-custom-stoich-specie.js b/client/views/edit-custom-stoich-specie.js
index 5db31730e7..0e842387eb 100644
--- a/client/views/edit-custom-stoich-specie.js
+++ b/client/views/edit-custom-stoich-specie.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/edit-domain-type.js b/client/views/edit-domain-type.js
index 20bba307e3..5460f753ba 100644
--- a/client/views/edit-domain-type.js
+++ b/client/views/edit-domain-type.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,10 +22,10 @@ let app = require('../app');
var View = require('ampersand-view');
var InputView = require('./input');
//templates
-var template = require('../templates/includes/editDomainType.pug');
+let editTemplate = require('../templates/includes/editDomainType.pug');
+let viewTemplate = require('../templates/includes/viewDomainType.pug');
module.exports = View.extend({
- template: template,
events: {
'click [data-hook=unassign-all]' : 'handleUnassignParticles',
'click [data-hook=delete-type]' : 'handleDeleteType',
@@ -33,6 +33,14 @@ module.exports = View.extend({
'click [data-hook=edit-defaults-btn]' : 'handleEditDefaults',
'change [data-target=type-name]' : 'handleRenameType'
},
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
+ },
+ render: function (attrs, options) {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
+ View.prototype.render.apply(this, arguments);
+ },
handleDeleteType: function (e) {
let type = Number(e.target.dataset.type);
this.parent.deleteType(type);
@@ -58,19 +66,21 @@ module.exports = View.extend({
this.parent.unassignAllParticles(type);
this.parent.renderDomainTypes();
},
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- },
- render: function (attrs, options) {
- View.prototype.render.apply(this, arguments);
- this.renderNameView();
- },
- renderNameView: function () {
- let nameView = new InputView({parent: this, required: true,
- name: 'name', valueType: 'string',
- value: this.model.name});
- app.registerRenderSubview(this, nameView, "type-" + this.model.typeID);
- },
update: function () {},
- updateValid: function () {}
+ updateValid: function () {},
+ subviews: {
+ inputName: {
+ waitFor: "model.typeID",
+ prepareView: function (el) {
+ return new InputView({
+ el: "type-" + this.model.typeID,
+ parent: this,
+ required: true,
+ name: 'name',
+ valueType: 'string',
+ value: this.model.name
+ });
+ }
+ }
+ }
});
\ No newline at end of file
diff --git a/client/views/edit-event-assignment.js b/client/views/edit-event-assignment.js
index 72c4b268d3..8bb53ad728 100644
--- a/client/views/edit-event-assignment.js
+++ b/client/views/edit-event-assignment.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,31 +24,22 @@ var View = require('ampersand-view');
var InputView = require('./input');
var SelectView = require('ampersand-select-view');
//templates
-var template = require('../templates/includes/editEventAssignment.pug');
+var editTemplate = require('../templates/includes/editEventAssignment.pug');
+var viewTemplate = require('../templates/includes/viewEventAssignment.pug');
module.exports = View.extend({
- template: template,
events: {
'click [data-hook=remove]' : 'removeAssignment',
'change [data-hook=event-assignment-variable]' : 'selectAssignmentVariable',
+ 'change [data-hook=event-assignment-expression]' : 'updateViewer'
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
},
render: function () {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
View.prototype.render.apply(this, arguments);
- var options = this.getOptions();
- var variableSelectView = new SelectView({
- label: '',
- name: 'variable',
- required: true,
- idAttributes: 'cid',
- options: options,
- value: this.model.variable.name,
- });
- app.registerRenderSubview(this, variableSelectView, 'event-assignment-variable');
- var inputField = this.queryByHook('event-assignment-Expression').children[0].children[1];
- $(inputField).attr("placeholder", "---No Expression Entered---");
},
update: function () {
},
@@ -62,44 +53,66 @@ module.exports = View.extend({
getOptions: function () {
var species = this.model.collection.parent.collection.parent.species;
var parameters = this.model.collection.parent.collection.parent.parameters;
- var speciesNames = species.map(function (specie) { return specie.name });
- var parameterNames = parameters.map(function (parameter) { return parameter.name });
- return speciesNames.concat(parameterNames);
+ var specs = species.map(function (specie) {
+ return [specie.compID, specie.name]
+ });
+ var params = parameters.map(function (parameter) {
+ return [parameter.compID, parameter.name]
+ });
+ let options = [{groupName: "Variables", options: specs},
+ {groupName: "Parameters", options: params}]
+ return options;
},
selectAssignmentVariable: function (e) {
var species = this.model.collection.parent.collection.parent.species;
var parameters = this.model.collection.parent.collection.parent.parameters;
- var val = e.target.selectedOptions.item(0).text;
+ var val = Number(e.target.value);
var eventVar = species.filter(function (specie) {
- if(specie.name === val) {
+ if(specie.compID === val) {
return specie;
}
});
if(!eventVar.length) {
eventVar = parameters.filter(function (parameter) {
- if(parameter.name === val) {
+ if(parameter.compID === val) {
return parameter;
}
});
}
this.model.variable = eventVar[0];
+ this.updateViewer();
this.model.collection.parent.collection.trigger('change');
},
+ updateViewer: function () {
+ this.model.collection.parent.trigger('change');
+ },
subviews: {
inputAssignmentExpression: {
- hook: 'event-assignment-Expression',
+ hook: 'event-assignment-expression',
prepareView: function (el) {
return new InputView({
parent: this,
required: true,
name: 'event-assignment-expression',
- label: '',
- tests: '',
+ placeholder: "---No Expression Entered---",
modelKey: 'expression',
valueType: 'string',
value: this.model.expression,
});
},
},
+ variableSelectView: {
+ hook: 'event-assignment-variable',
+ prepareView: function (el) {
+ let options = this.getOptions();
+ return new SelectView({
+ name: 'variable',
+ required: true,
+ idAttributes: 'cid',
+ groupOptions: options,
+ value: this.model.variable.compID,
+ });
+ }
+ }
},
});
\ No newline at end of file
diff --git a/client/views/edit-function-definition.js b/client/views/edit-function-definition.js
index 61a3261b45..d582b9dba6 100644
--- a/client/views/edit-function-definition.js
+++ b/client/views/edit-function-definition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,18 +22,20 @@ var modals = require('../modals');
//views
var View = require('ampersand-view');
//templates
-var template = require('../templates/includes/editFunctionDefinition.pug');
+var editTemplate = require('../templates/includes/editFunctionDefinition.pug');
+let viewTemplate = require('../templates/includes/viewFunctionDefinition.pug');
module.exports = View.extend({
- template: template,
events: {
'click [data-hook=remove]' : 'removeFunctionDefinition',
'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
},
render: function () {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
View.prototype.render.apply(this, arguments);
$(document).on('hide.bs.modal', '.modal', function (e) {
e.target.remove()
@@ -57,7 +59,7 @@ module.exports = View.extend({
});
okBtn.addEventListener('click', function (e) {
self.model.annotation = input.value.trim();
- self.parent.renderEdirFunctionDefinitionView();
+ self.parent.renderEditFunctionDefinitionView();
modal.modal('hide');
});
},
diff --git a/client/views/edit-initial-condition.js b/client/views/edit-initial-condition.js
index 11089e5efc..80b9489814 100644
--- a/client/views/edit-initial-condition.js
+++ b/client/views/edit-initial-condition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,108 +17,78 @@ along with this program. If not, see .
*/
let $ = require('jquery');
+let _ = require('underscore');
//support files
let app = require('../app');
var tests = require('./tests');
+let modals = require('../modals');
//views
var View = require('ampersand-view');
var InputView = require('./input');
var SelectView = require('ampersand-select-view');
var TypesView = require('./component-types');
//templates
-var template = require('../templates/includes/editInitialCondition.pug');
+let editTemplate = require('../templates/includes/editInitialCondition.pug');
+let viewTemplate = require('../templates/includes/viewInitialCondition.pug');
module.exports = View.extend({
- template: template,
events: {
+ 'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
'click [data-hook=remove]' : 'removeInitialCondition',
'change [data-hook=initial-condition-type]' : 'selectInitialConditionType',
- 'change [data-hook=initial-condition-species]' : 'selectInitialConditionSpecies',
+ 'change [data-hook=initial-condition-species]' : 'selectInitialConditionSpecies'
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
this.modelType = "initial-condition";
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
+ if(this.viewMode) {
+ let self = this;
+ this.types = [];
+ this.model.types.forEach(function (index) {
+ let type = self.model.collection.parent.domain.types.get(index, "typeID");
+ self.types.push(type.name)
+ });
+ }
},
render: function () {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
View.prototype.render.apply(this, arguments);
- var self = this;
- var options = ['Scatter', 'Place', 'Distribute Uniformly per Voxel'];
- var typeSelectView = new SelectView({
- label: '',
- name: 'type',
- required: true,
- idAttributes: 'cid',
- options: options,
- value: self.model.icType,
+ if(!this.viewMode) {
+ this.model.on('change', _.bind(this.updateViewer, this));
+ }
+ $(document).on('shown.bs.modal', function (e) {
+ $('[autofocus]', e.target).focus();
});
- var speciesSelectView = new SelectView({
- label: '',
- name: 'specie',
- required: true,
- idAttribute: 'cid',
- textAttribute: 'name',
- eagerValidate: true,
- options: this.model.collection.parent.species,
- // For new reactions (with no rate.name) just use the first parameter in the Parameters collection
- // Else fetch the right Parameter from Parameters based on existing rate
- value: this.model.specie.name ? this.getSpecieFromSpecies(this.model.specie.name) : this.model.collection.parent.species.at(0),
+ $(document).on('hide.bs.modal', '.modal', function (e) {
+ e.target.remove()
});
- app.registerRenderSubview(this, typeSelectView, 'initial-condition-type');
- app.registerRenderSubview(this, speciesSelectView, 'initial-condition-species');
- this.renderDetailsView();
- },
- update: function () {
- },
- updateValid: function () {
- },
- renderDetailsView: function () {
- if(this.model.icType === "Place") {
- $(this.queryByHook("scatter-details")).css("display", "none")
- $(this.queryByHook("place-details")).css("display", "block")
- this.renderLocation();
- }else {
- $(this.queryByHook("place-details")).css("display", "none")
- $(this.queryByHook("scatter-details")).css("display", "block")
- this.renderTypes();
+ if(!this.model.annotation){
+ $(this.queryByHook('edit-annotation-btn')).text('Add')
}
+ this.toggleDetailsView();
},
- renderLocation: function () {
- if(this.xCoord) {
- this.xCoord.remove();
- this.yCoord.remove();
- this.zCoord.remove();
- }
- this.xCoord = new InputView({parent: this, required: true,
- name: 'X', valueType: 'number',
- modelKey: "x", label: 'x: ',
- tests: tests.valueTests,
- value: this.model.x});
- app.registerRenderSubview(this, this.xCoord, "x-container");
- this.yCoord = new InputView({parent: this, required: true,
- name: 'Y', valueType: 'number',
- modelKey: "y", label: 'y: ',
- tests: tests.valueTests,
- value: this.model.y});
- app.registerRenderSubview(this, this.yCoord, "y-container");
- this.zCoord = new InputView({parent: this, required: true,
- name: 'Z', valueType: 'number',
- modelKey: "z", label: 'z: ',
- tests: tests.valueTests,
- value: this.model.z});
- app.registerRenderSubview(this, this.zCoord, "z-container");
- },
- renderTypes: function () {
- if(this.typesView) {
- this.typesView.remove();
+ editAnnotation: function () {
+ var self = this;
+ var name = this.model.name;
+ var annotation = this.model.annotation;
+ if(document.querySelector('#initialConditionAnnotationModal')) {
+ document.querySelector('#initialConditionAnnotationModal').remove();
}
- this.typesView = this.renderCollection(
- this.model.collection.parent.domain.types,
- TypesView,
- this.queryByHook("initial-condition-types"),
- {"filter": function (model) {
- return model.typeID != 0;
- }}
- );
+ let modal = $(modals.annotationModalHtml("initialCondition", name, annotation)).modal();
+ let okBtn = document.querySelector('#initialConditionAnnotationModal .ok-model-btn');
+ let input = document.querySelector('#initialConditionAnnotationModal #initialConditionAnnotationInput');
+ input.addEventListener("keyup", function (event) {
+ if(event.keyCode === 13){
+ event.preventDefault();
+ okBtn.click();
+ }
+ });
+ okBtn.addEventListener('click', function (e) {
+ self.model.annotation = input.value.trim();
+ self.parent.renderEditInitialConditionsView();
+ modal.modal('hide');
+ });
},
getSpecieFromSpecies: function (name) {
var species = this.model.collection.parent.species.filter(function (specie) {
@@ -129,20 +99,62 @@ module.exports = View.extend({
removeInitialCondition: function () {
this.collection.removeInitialCondition(this.model);
},
+ selectInitialConditionSpecies: function (e) {
+ var name = e.target.selectedOptions.item(0).text;
+ var specie = this.getSpecieFromSpecies(name);
+ this.model.specie = specie || this.model.specie;
+ this.model.trigger('change');
+ },
selectInitialConditionType: function (e) {
var currentType = this.model.icType;
var newType = e.target.selectedOptions.item(0).text;
this.model.icType = newType;
if(currentType === "Place" || newType === "Place"){
- this.renderDetailsView();
+ this.toggleDetailsView();
}
},
- selectInitialConditionSpecies: function (e) {
- var name = e.target.selectedOptions.item(0).text;
- var specie = this.getSpecieFromSpecies(name);
- this.model.specie = specie || this.model.specie;
+ toggleDetailsView: function () {
+ if(this.model.icType === "Place") {
+ $(this.queryByHook("scatter-details")).css("display", "none")
+ $(this.queryByHook("place-details")).css("display", "block")
+ }else {
+ $(this.queryByHook("place-details")).css("display", "none")
+ $(this.queryByHook("scatter-details")).css("display", "block")
+ }
+ },
+ update: function () {},
+ updateValid: function () {},
+ updateViewer: function () {
+ this.parent.renderViewInitialConditionsView();
},
subviews: {
+ selectICType: {
+ hook: 'initial-condition-type',
+ prepareView: function (el) {
+ let options = ['Scatter', 'Place', 'Distribute Uniformly per Voxel'];
+ return new SelectView({
+ name: 'type',
+ required: true,
+ idAttributes: 'cid',
+ options: options,
+ value: this.model.icType,
+ });
+ }
+ },
+ selectSpecies: {
+ hook: 'initial-condition-species',
+ prepareView: function (el) {
+ return new SelectView({
+ name: 'specie',
+ required: true,
+ idAttribute: 'cid',
+ textAttribute: 'name',
+ eagerValidate: true,
+ options: this.model.collection.parent.species,
+ value: this.model.specie.name ? this.getSpecieFromSpecies(this.model.specie.name) : this.model.collection.parent.species.at(0),
+ });
+ }
+ },
inputCount: {
hook: 'count-container',
prepareView: function (el) {
@@ -150,13 +162,70 @@ module.exports = View.extend({
parent: this,
required: true,
name: 'count',
- label: '',
tests: tests.valueTests,
modelKey: 'count',
valueType: 'number',
value: this.model.count,
});
- },
+ }
+ },
+ typesView: {
+ hook: 'initial-condition-types',
+ prepareView: function (el) {
+ return this.renderCollection(
+ this.model.collection.parent.domain.types,
+ TypesView,
+ this.queryByHook("initial-condition-types"),
+ {"filter": function (model) {
+ return model.typeID != 0;
+ }}
+ );
+ }
+ },
+ inputXCoord: {
+ hook: 'x-container',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'X',
+ valueType: 'number',
+ modelKey: "x",
+ label: 'x: ',
+ tests: tests.valueTests,
+ value: this.model.x
+ });
+ }
+ },
+ inputYCoord: {
+ hook: 'y-container',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'Y',
+ valueType: 'number',
+ modelKey: "y",
+ label: 'y: ',
+ tests: tests.valueTests,
+ value: this.model.y
+ });
+ }
+ },
+ inputZCoord: {
+ hook: 'z-container',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'Z',
+ valueType: 'number',
+ modelKey: "z",
+ label: 'z: ',
+ tests: tests.valueTests,
+ value: this.model.z
+ });
+ }
}
}
});
\ No newline at end of file
diff --git a/client/views/edit-parameter.js b/client/views/edit-parameter.js
index e8b342f24c..bc2bec13e9 100644
--- a/client/views/edit-parameter.js
+++ b/client/views/edit-parameter.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/edit-particle.js b/client/views/edit-particle.js
index 099e0a099a..8dc1f0d2da 100644
--- a/client/views/edit-particle.js
+++ b/client/views/edit-particle.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/edit-project.js b/client/views/edit-project.js
index 042dddc754..2dcf7d3f90 100644
--- a/client/views/edit-project.js
+++ b/client/views/edit-project.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/edit-rule.js b/client/views/edit-rule.js
index 9c54a25471..66e36128b8 100644
--- a/client/views/edit-rule.js
+++ b/client/views/edit-rule.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@ along with this program. If not, see .
*/
var $ = require('jquery');
+let _ = require('underscore');
//support files
let app = require('../app');
var tests = require('./tests');
@@ -26,43 +27,26 @@ var View = require('ampersand-view');
var InputView = require('./input');
var SelectView = require('ampersand-select-view');
//templates
-var template = require('../templates/includes/editRule.pug');
+var editTemplate = require('../templates/includes/editRule.pug');
+let viewTemplate = require('../templates/includes/viewRules.pug');
module.exports = View.extend({
- template: template,
events: {
'change [data-hook=rule-type]' : 'selectRuleType',
'change [data-hook=rule-variable]' : 'selectRuleVariable',
'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
'click [data-hook=remove]' : 'removeRule',
},
- initiailize: function (attrs, options) {
- View.prototype.initiailize.apply(this, arguments);
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
},
render: function () {
- this.renderWithTemplate();
- var inputField = this.queryByHook('rule-expression').children[0].children[1];
- $(inputField).attr("placeholder", "---No Expression Entered---");
- var varOptions = this.getOptions();
- var typeOptions = ['Rate Rule', 'Assignment Rule']
- var typeSelectView = new SelectView({
- label: '',
- name: 'type',
- required: true,
- idAttributes: 'cid',
- options: typeOptions,
- value: this.model.type,
- });
- var variableSelectView = new SelectView({
- label: '',
- name: 'variable',
- required: true,
- idAttributes: 'cid',
- options: varOptions,
- value: this.model.variable.name,
- });
- app.registerRenderSubview(this, typeSelectView, "rule-type");
- app.registerRenderSubview(this, variableSelectView, 'rule-variable');
+ this.template = this.viewMode ? viewTemplate : editTemplate;
+ View.prototype.render.apply(this, arguments);
+ if(!this.viewMode){
+ this.model.on('change', _.bind(this.updateViewer, this))
+ }
$(document).on('shown.bs.modal', function (e) {
$('[autofocus]', e.target).focus();
});
@@ -95,33 +79,38 @@ module.exports = View.extend({
});
okBtn.addEventListener('click', function (e) {
self.model.annotation = input.value.trim();
- self.parent.renderRules();
+ self.parent.renderEditRules();
modal.modal('hide');
});
},
getOptions: function () {
var species = this.model.collection.parent.species;
var parameters = this.model.collection.parent.parameters;
- var speciesNames = species.map(function (specie) { return specie.name });
- var parameterNames = parameters.map(function (parameter) { return parameter.name });
- return speciesNames.concat(parameterNames);
+ var specs = species.map(function (specie) {
+ return [specie.compID, specie.name];
+ });
+ var params = parameters.map(function (parameter) {
+ return [parameter.compID, parameter.name];
+ });
+ let options = [{groupName: "Variables", options: specs},
+ {groupName: "Parameters", options: params}];
+ return options;
},
selectRuleType: function (e) {
- var type = e.target.selectedOptions.item(0).text;
- this.model.type = type;
+ this.model.type = e.target.value;
},
selectRuleVariable: function (e) {
var species = this.model.collection.parent.species;
var parameters = this.model.collection.parent.parameters;
- var val = e.target.selectedOptions.item(0).text;
+ var compID = Number(e.target.value);
var ruleVar = species.filter(function (specie) {
- if(specie.name === val) {
+ if(specie.compID === compID) {
return specie;
}
});
if(!ruleVar.length) {
ruleVar = parameters.filter(function (parameter) {
- if(parameter.name === val) {
+ if(parameter.compID === compID) {
return parameter;
}
});
@@ -131,6 +120,9 @@ module.exports = View.extend({
removeRule: function () {
this.model.collection.removeRule(this.model);
},
+ updateViewer: function () {
+ this.parent.renderViewRules();
+ },
subviews: {
inputName: {
hook: 'rule-name',
@@ -145,7 +137,33 @@ module.exports = View.extend({
valueType: 'string',
value: this.model.name,
});
- },
+ }
+ },
+ selectType: {
+ hook: 'rule-type',
+ prepareView: function (el) {
+ let options = ['Rate Rule', 'Assignment Rule'];
+ return new SelectView({
+ name: 'type',
+ required: true,
+ idAttributes: 'cid',
+ options: options,
+ value: this.model.type,
+ });
+ }
+ },
+ selectTarget: {
+ hook: 'rule-variable',
+ prepareView: function(el) {
+ let options = this.getOptions();
+ return new SelectView({
+ name: 'variable',
+ required: true,
+ idAttributes: 'cid',
+ groupOptions: options,
+ value: this.model.variable.compID,
+ });
+ }
},
inputRule: {
hook: 'rule-expression',
@@ -154,14 +172,12 @@ module.exports = View.extend({
parent: this,
required: true,
name: 'rule-expression',
- label: '',
- tests: '',
modelKey: 'expression',
valueType: 'string',
value: this.model.expression,
placeholder: "--No Formula Entered--"
});
- },
- },
- },
+ }
+ }
+ }
});
\ No newline at end of file
diff --git a/client/views/edit-spatial-specie.js b/client/views/edit-spatial-specie.js
deleted file mode 100644
index 7a685800b6..0000000000
--- a/client/views/edit-spatial-specie.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var tests = require('./tests');
-var _ = require('underscore');
-//views
-var View = require('ampersand-view');
-var InputView = require('./input');
-var TypesView = require('./component-types');
-//templates
-var template = require('../templates/includes/editSpatialSpecie.pug');
-
-module.exports = View.extend({
- template: template,
- bindings: {
- 'model.inUse': {
- hook: 'remove',
- type: 'booleanAttribute',
- name: 'disabled',
- },
- },
- events: {
- 'click [data-hook=remove]' : 'removeSpecie',
- },
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- this.baseModel = this.model.collection.parent;
- this.modelType = "species";
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- this.renderTypes();
- },
- update: function () {
- },
- updateValid: function () {
- },
- removeSpecie: function () {
- this.remove();
- this.collection.removeSpecie(this.model);
- },
- renderTypes: function () {
- if(this.typesView) {
- this.typesView.remove();
- }
- this.typesView = this.renderCollection(
- this.baseModel.domain.types,
- TypesView,
- this.queryByHook("species-types"),
- {"filter": function (model) {
- return model.typeID != 0;
- }}
- );
- },
- subviews: {
- inputName: {
- hook: 'input-name-container',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'name',
- label: '',
- tests: tests.nameTests,
- modelKey: 'name',
- valueType: 'string',
- value: this.model.name,
- });
- },
- },
- inputValue: {
- hook: 'input-diffusion-coeff-container',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'diffusion coeff',
- label: '',
- tests: tests.valueTests,
- modelKey: 'diffusionConst',
- valueType: 'number',
- value: this.model.diffusionConst,
- });
- },
- },
- },
-});
\ No newline at end of file
diff --git a/client/views/edit-specie.js b/client/views/edit-specie.js
deleted file mode 100644
index 1408a6a67e..0000000000
--- a/client/views/edit-specie.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-var tests = require('./tests');
-var modals = require('../modals');
-//views
-var View = require('ampersand-view');
-var InputView = require('./input');
-//templates
-var template = require('../templates/includes/editReactionVar.pug');
-
-module.exports = View.extend({
- template: template,
- bindings: {
- 'model.inUse': {
- hook: 'remove',
- type: 'booleanAttribute',
- name: 'disabled',
- },
- },
- events: {
- 'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
- 'click [data-hook=remove]' : 'removeSpecie',
- 'change [data-hook=input-name-container]' : 'setSpeciesName',
- },
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- this.previousName = this.model.name
- if(this.model.mode === null && this.model.collection.parent.defaultMode !== "") {
- this.model.mode = this.model.collection.parent.defaultMode;
- }
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- $(document).on('shown.bs.modal', function (e) {
- $('[autofocus]', e.target).focus();
- });
- $(document).on('hide.bs.modal', '.modal', function (e) {
- e.target.remove()
- });
- if(!this.model.annotation){
- $(this.queryByHook('edit-annotation-btn')).text('Add')
- }
- },
- update: function () {
- },
- updateValid: function (e) {
- },
- removeSpecie: function () {
- this.remove();
- this.collection.removeSpecie(this.model);
- this.parent.toggleSpeciesCollectionError();
- },
- setSpeciesName: function (e) {
- if(!e.target.value.trim()) {
- this.model.name = this.previousName;
- this.parent.renderEditSpeciesView();
- }else{
- this.previousName = this.model.name;
- this.model.collection.trigger('update-species', this.model.compID, this.model, true, false);
- this.model.collection.trigger('remove');
- }
- },
- editAnnotation: function () {
- var self = this;
- var name = this.model.name;
- var annotation = this.model.annotation;
- if(document.querySelector('#speciesAnnotationModal')) {
- document.querySelector('#speciesAnnotationModal').remove();
- }
- let modal = $(modals.annotationModalHtml("species", name, annotation)).modal();
- let okBtn = document.querySelector('#speciesAnnotationModal .ok-model-btn');
- let input = document.querySelector('#speciesAnnotationModal #speciesAnnotationInput');
- input.addEventListener("keyup", function (event) {
- if(event.keyCode === 13){
- event.preventDefault();
- okBtn.click();
- }
- });
- okBtn.addEventListener('click', function (e) {
- self.model.annotation = input.value.trim();
- self.parent.renderEditSpeciesView();
- modal.modal('hide');
- });
- },
- subviews: {
- inputName: {
- hook: 'input-name-container',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'name',
- label: '',
- tests: tests.nameTests,
- modelKey: 'name',
- valueType: 'string',
- value: this.model.name,
- });
- },
- },
- inputValue: {
- hook: 'input-value-container',
- prepareView: function (el) {
- return new InputView({
- parent: this,
- required: true,
- name: 'value',
- label: '',
- tests: tests.valueTests,
- modelKey: 'value',
- valueType: 'number',
- value: this.model.value,
- });
- },
- },
- },
-});
\ No newline at end of file
diff --git a/client/views/edit-species.js b/client/views/edit-species.js
new file mode 100644
index 0000000000..39a7e6f744
--- /dev/null
+++ b/client/views/edit-species.js
@@ -0,0 +1,304 @@
+/*
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+let $ = require('jquery');
+let _ = require('underscore');
+//support files
+let app = require('../app');
+let tests = require('./tests');
+let modals = require('../modals');
+//views
+let InputView = require('./input');
+let View = require('ampersand-view');
+let TypesView = require('./component-types');
+let SelectView = require('ampersand-select-view');
+//templates
+let editTemplate = require('../templates/includes/editSpecies.pug');
+let editSpatialTemplate = require('../templates/includes/editSpatialSpecies.pug');
+let viewTemplate = require('../templates/includes/viewSpecies.pug');
+let viewSpatialTemplate = require('../templates/includes/viewSpatialSpecies.pug');
+
+module.exports = View.extend({
+ bindings: {
+ 'model.inUse': {
+ hook: 'remove',
+ type: 'booleanAttribute',
+ name: 'disabled',
+ },
+ },
+ events: {
+ 'change [data-hook=input-name-container]' : 'setSpeciesName',
+ 'change [data-hook=specie-mode]' : 'setSpeciesMode',
+ 'change [data-hook=switching-tol]' : 'setSwitchingType',
+ 'change [data-hook=switching-min]' : 'setSwitchingType',
+ 'click [data-hook=edit-annotation-btn]' : 'editAnnotation',
+ 'click [data-hook=remove]' : 'removeSpecie',
+ 'click [data-hook=collapse-advanced]' : 'changeCollapseButtonText'
+ },
+ initialize: function (attrs, options) {
+ View.prototype.initialize.apply(this, arguments);
+ this.modelType = "species";
+ this.previousName = this.model.name;
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
+ if(this.viewMode && this.parent.spatial) {
+ let self = this;
+ this.types = [];
+ if(this.model.types) {
+ this.model.types.forEach(function (index) {
+ let type = self.model.collection.parent.domain.types.get(index, "typeID");
+ self.types.push(type.name);
+ });
+ }
+ }
+ if(this.model.mode === null && this.parent.defaultMode !== "") {
+ this.model.mode = this.parent.defaultMode;
+ }
+ this.switchingValWithLabel = this.model.isSwitchTol ?
+ "Switching Tolerance: " + this.model.switchTol :
+ "Minimum Value For Switching: " + this.model.switchMin;
+ },
+ render: function () {
+ if(this.parent.spatial){
+ this.template = this.viewMode ? viewSpatialTemplate : editSpatialTemplate;
+ }else{
+ this.template = this.viewMode ? viewTemplate : editTemplate;
+ }
+ View.prototype.render.apply(this, arguments);
+ $(document).on('shown.bs.modal', function (e) {
+ $('[autofocus]', e.target).focus();
+ });
+ $(document).on('hide.bs.modal', '.modal', function (e) {
+ e.target.remove();
+ });
+ if(!this.model.annotation){
+ $(this.queryByHook('edit-annotation-btn')).text('Add');
+ }
+ if(this.parent.defaultMode !== "dynamic") {
+ $(this.queryByHook("advanced-species")).css("display", "none");
+ }else{
+ $(this.queryByHook("advanced-species")).css("display", "block");
+ }
+ if(this.model.isSwitchTol){
+ $(this.queryByHook('switching-tol')).prop('checked', true);
+ }else{
+ $(this.queryByHook('switching-min')).prop('checked', true);
+ }
+ this.toggleSwitchingSettings();
+ this.updateInputValidation();
+ if(!this.viewMode){
+ this.model.on('change', _.bind(this.updateViewer, this));
+ if(this.parent.spatial) {
+ this.renderTypes();
+ }
+ }
+ },
+ changeCollapseButtonText: function (e) {
+ app.changeCollapseButtonText(this, e);
+ },
+ editAnnotation: function () {
+ let self = this;
+ let name = this.model.name;
+ let annotation = this.model.annotation;
+ if(document.querySelector('#speciesAnnotationModal')) {
+ document.querySelector('#speciesAnnotationModal').remove();
+ }
+ let modal = $(modals.annotationModalHtml("species", name, annotation)).modal();
+ let okBtn = document.querySelector('#speciesAnnotationModal .ok-model-btn');
+ let input = document.querySelector('#speciesAnnotationModal #speciesAnnotationInput');
+ input.addEventListener("keyup", function (event) {
+ if(event.keyCode === 13){
+ event.preventDefault();
+ okBtn.click();
+ }
+ });
+ okBtn.addEventListener('click', function (e) {
+ self.model.annotation = input.value.trim();
+ self.parent.renderEditSpeciesView();
+ modal.modal('hide');
+ });
+ },
+ removeSpecie: function () {
+ this.remove();
+ this.collection.removeSpecie(this.model);
+ this.parent.toggleSpeciesCollectionError();
+ },
+ renderTypes: function () {
+ if(this.typesView) {
+ this.typesView.remove();
+ }
+ this.typesView = this.renderCollection(
+ this.model.collection.parent.domain.types,
+ TypesView,
+ this.queryByHook("species-types"),
+ {"filter": function (model) {
+ return model.typeID != 0;
+ }}
+ );
+ },
+ setSpeciesMode: function (e) {
+ this.model.mode = e.target.value;
+ this.model.collection.trigger('update-species', this.model.compID, this.model, false, false);
+ this.updateInputValidation();
+ this.toggleSwitchingSettings();
+ },
+ setSpeciesName: function (e) {
+ if(!e.target.value.trim()) {
+ this.model.name = this.previousName;
+ this.parent.renderEditSpeciesView();
+ }else{
+ this.previousName = this.model.name;
+ this.model.collection.trigger('update-species', this.model.compID, this.model, true, false);
+ }
+ },
+ setSwitchingType: function (e) {
+ this.model.isSwitchTol = $(this.queryByHook('switching-tol')).is(":checked");
+ this.updateInputValidation();
+ this.toggleSwitchingSettingsInput();
+ },
+ toggleSwitchingSettings: function () {
+ if(this.model.mode === "dynamic"){
+ $(this.queryByHook('switching-tol')).prop('disabled', false);
+ $(this.queryByHook('switching-min')).prop('disabled', false);
+ this.toggleSwitchingSettingsInput();
+ }else{
+ $(this.queryByHook('switching-tol')).prop('disabled', true);
+ $(this.queryByHook('switching-min')).prop('disabled', true);
+ $(this.queryByHook('switching-threshold')).find('input').prop('disabled', true);
+ $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', true);
+ }
+ },
+ toggleSwitchingSettingsInput: function () {
+ if(this.model.isSwitchTol){
+ $(this.queryByHook('switching-threshold')).find('input').prop('disabled', true);
+ $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', false);
+ }else{
+ $(this.queryByHook('switching-tolerance')).find('input').prop('disabled', true);
+ $(this.queryByHook('switching-threshold')).find('input').prop('disabled', false);
+ }
+ },
+ update: function () {},
+ updateInputValidation: function () {
+ if(this.viewMode || this.parent.spatial) {return}
+ // Update validation requirements and re-run tests for inputSwitchTol.
+ // This removes error reporting not using switching tolerance
+ let shouldValidateTol = this.model.mode === "dynamic" && this.model.isSwitchTol
+ this.inputSwitchTol.required = shouldValidateTol;
+ this.inputSwitchTol.tests = shouldValidateTol ? tests.valueTests : []
+ this.inputSwitchTol.runTests()
+ // Update validation requirements and re-run tests for inputSwitchMin.
+ // This removes error reporting when not using minimum value for switching.
+ let shouldValidateMin = this.model.mode === "dynamic" && !this.model.isSwitchTol
+ this.inputSwitchMin.required = shouldValidateMin;
+ this.inputSwitchMin.tests = shouldValidateMin ? tests.valueTests : []
+ this.inputSwitchMin.runTests()
+ // Add/Remove 'input-invalid' class from inputSwitchTol and inputSwitchMin based on whether
+ // the user is using switching tolerance or minimum value for switching
+ let tolInput = $(this.queryByHook('switching-tolerance')).find('input')[0]
+ let minInput = $(this.queryByHook('switching-threshold')).find('input')[0]
+ if(this.model.mode !== "dynamic") {
+ $(tolInput).removeClass('input-invalid')
+ $(minInput).removeClass('input-invalid')
+ }else if(this.model.isSwitchTol){
+ $(minInput).removeClass('input-invalid')
+ if(this.model.switchTol === "" || isNaN(this.model.switchTol)){
+ $(tolInput).addClass('input-invalid')
+ }
+ }else{
+ $(tolInput).removeClass('input-invalid')
+ if(this.model.switchMin === "" || isNaN(this.model.switchMin)){
+ $(minInput).addClass('input-invalid')
+ }
+ }
+ },
+ updateValid: function (e) {},
+ updateViewer: function () {
+ this.parent.renderViewSpeciesView()
+ },
+ subviews: {
+ inputName: {
+ hook: 'input-name-container',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'name',
+ tests: tests.nameTests,
+ modelKey: 'name',
+ valueType: 'string',
+ value: this.model.name,
+ });
+ }
+ },
+ inputValue: {
+ hook: 'input-value-container',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: this.parent.spatial ? 'diffusion constant' : 'value',
+ tests: tests.valueTests,
+ modelKey: this.parent.spatial ? 'diffusionConst' : 'value',
+ valueType: 'number',
+ value: this.parent.spatial ? this.model.diffusionConst : this.model.value,
+ });
+ }
+ },
+ selectMode: {
+ hook: 'specie-mode',
+ prepareView: function (el) {
+ options = [['continuous', 'Concentration'], ['discrete', 'Population'],
+ ['dynamic', 'Hybrid Concentration/Population']]
+ return new SelectView({
+ name: 'mode',
+ required: true,
+ idAttributes: 'cid',
+ options: options,
+ value: this.model.mode,
+ });
+ }
+ },
+ inputSwitchTol: {
+ hook: 'switching-tolerance',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'switching-tolerance',
+ tests: tests.valueTests,
+ modelKey: 'switchTol',
+ valueType: 'number',
+ value: this.model.switchTol,
+ });
+ }
+ },
+ inputSwitchMin: {
+ hook: 'switching-threshold',
+ prepareView: function (el) {
+ return new InputView({
+ parent: this,
+ required: true,
+ name: 'switching-threshold',
+ tests: tests.valueTests,
+ modelKey: 'switchMin',
+ valueType: 'number',
+ value: this.model.switchMin,
+ });
+ }
+ }
+ }
+});
diff --git a/client/views/edit-stoich-specie.js b/client/views/edit-stoich-specie.js
index 162806b2e6..4f276620aa 100644
--- a/client/views/edit-stoich-specie.js
+++ b/client/views/edit-stoich-specie.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/event-assignments-editor.js b/client/views/event-assignments-editor.js
index 917820a137..3640c137e9 100644
--- a/client/views/event-assignments-editor.js
+++ b/client/views/event-assignments-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+let $ = require('jquery');
+//support files
+let app = require('../app');
//views
var View = require('ampersand-view');
var EditEventAssignment = require('./edit-event-assignment');
@@ -25,25 +28,56 @@ var template = require('../templates/includes/eventAssignmentsEditor.pug');
module.exports = View.extend({
template: template,
events: {
- 'click [data-hook=add-event-assignment]' : 'addAssignment',
+ 'click [data-hook=collapse-assignments]' : 'changeCollapseButtonText',
+ 'click [data-hook=add-event-assignment]' : 'addAssignment'
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
+ this.tooltips = attrs.tooltips;
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderCollection(
+ if(this.readOnly) {
+ $(this.queryByHook('edit-event-assignments')).removeClass('active');
+ $(this.queryByHook('view-event-assignments')).addClass('active');
+ $(this.queryByHook('event-assignments-header')).css("display", "none");
+ this.renderViewEventAssignment();
+ }else{
+ this.renderEditEventAssignment();
+ }
+ },
+ addAssignment: function () {
+ this.collection.addEventAssignment();
+ this.collection.parent.collection.trigger('change')
+ },
+ changeCollapseButtonText: function (e) {
+ app.changeCollapseButtonText(this, e);
+ },
+ renderEditEventAssignment: function () {
+ if(this.editEventAssignments) {
+ this.editEventAssignments.remove();
+ }
+ this.editEventAssignments = this.renderCollection(
this.collection,
EditEventAssignment,
- this.queryByHook('event-assignments-container')
+ this.queryByHook('edit-event-assignments-container')
+ );
+ },
+ renderViewEventAssignment: function () {
+ if(this.viewEventAssignments) {
+ this.viewEventAssignments.remove();
+ }
+ let options = {viewOptions: {viewMode: true}}
+ this.viewEventAssignments = this.renderCollection(
+ this.collection,
+ EditEventAssignment,
+ this.queryByHook('view-event-assignments-container'),
+ options
);
},
update: function () {
},
updateValid: function () {
- },
- addAssignment: function () {
- this.collection.addEventAssignment();
- this.collection.parent.collection.trigger('change')
- },
+ }
})
\ No newline at end of file
diff --git a/client/views/event-assignments-viewer.js b/client/views/event-assignments-viewer.js
deleted file mode 100644
index ee3551a067..0000000000
--- a/client/views/event-assignments-viewer.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-//views
-var View = require('ampersand-view');
-var ViewAssignments = require('./view-event-assignments');
-//templates
-var template = require('../templates/includes/eventAssignmentsViewer.pug');
-
-module.exports = View.extend({
- template: template,
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- this.renderCollection(this.collection, ViewAssignments, 'view-event-assignments-list');
- },
-});
\ No newline at end of file
diff --git a/client/views/event-details.js b/client/views/event-details.js
index 3d64cdb23d..a4cf72f6c9 100644
--- a/client/views/event-details.js
+++ b/client/views/event-details.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,8 +44,8 @@ module.exports = View.extend({
events: {
'change [data-hook=event-trigger-init-value]' : 'setTriggerInitialValue',
'change [data-hook=event-trigger-persistent]' : 'setTriggerPersistent',
- 'change [data-hook=trigger-time]' : 'setUseValuesFromTriggerTime',
- 'change [data-hook=assignment-time]' : 'setUseValuesFromTriggerTime',
+ 'change [data-hook=edit-trigger-time]' : 'setUseValuesFromTriggerTime',
+ 'change [data-hook=edit-assignment-time]' : 'setUseValuesFromTriggerTime',
'click [data-hook=advanced-event-button]' : 'changeCollapseButtonText',
},
initialize: function (attrs, options) {
@@ -54,16 +54,12 @@ module.exports = View.extend({
render: function () {
View.prototype.render.apply(this, arguments);
this.renderEventAssignments();
- var triggerExpressionField = this.queryByHook('event-trigger-expression').children[0].children[1];
- $(triggerExpressionField).attr("placeholder", "---No Expression Entered---");
- var delayField = this.queryByHook('event-delay').children[0].children[1];
- $(delayField).attr("placeholder", "---No Expression Entered---");
if(this.model.useValuesFromTriggerTime){
- $(this.queryByHook('trigger-time')).prop('checked', true)
+ $(this.queryByHook('edit-trigger-time')).prop('checked', true)
}else{
- $(this.queryByHook('assignment-time')).prop('checked', true)
+ $(this.queryByHook('edit-assignment-time')).prop('checked', true)
}
- $(document).ready(function () {
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
@@ -81,6 +77,7 @@ module.exports = View.extend({
}
this.eventAssignmentsView = new EventAssignment({
collection: this.model.eventAssignments,
+ tooltips: this.parent.tooltips
});
app.registerRenderSubview(this, this.eventAssignmentsView, 'event-assignments');
},
@@ -111,8 +108,7 @@ module.exports = View.extend({
parent: this,
required: false,
name: 'delay',
- label: '',
- tests: '',
+ placeholder: '---No Expression Entered---',
modelKey: 'delay',
valueType: 'string',
value: this.model.delay,
@@ -126,8 +122,6 @@ module.exports = View.extend({
parent: this,
required: true,
name: 'priority',
- label: '',
- tests: '',
modelKey: 'priority',
valueType: 'string',
value: this.model.priority,
@@ -141,8 +135,7 @@ module.exports = View.extend({
parent: this,
required: true,
name: 'trigger-expression',
- label: '',
- tests: '',
+ placeholder: '---No Expression Entered---',
modelKey: 'triggerExpression',
valueType: 'string',
value: this.model.triggerExpression,
diff --git a/client/views/event-listings.js b/client/views/event-listings.js
index 2f248816f7..0a7c7866fe 100644
--- a/client/views/event-listings.js
+++ b/client/views/event-listings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,52 +17,36 @@ along with this program. If not, see .
*/
var $ = require('jquery');
+let _ = require('underscore');
//support files
+let app = require('../app');
var tests = require('./tests');
var modals = require('../modals');
//views
var View = require('ampersand-view');
var InputView = require('./input');
+var EventAssignment = require('./event-assignments-editor');
//templates
-var template = require('../templates/includes/eventListings.pug');
-
-let eventAnnotationModalHtml = (eventName, annotation) => {
- return `
-
-
-
-
-
- Annotation:
-
-
-
-
-
-
- `
-}
+var editTemplate = require('../templates/includes/eventListings.pug');
+let viewTemplate = require('../templates/includes/viewEvents.pug');
module.exports = View.extend({
- template: template,
bindings: {
- 'model.name' : {
- type: 'value',
- hook: 'input-name-container'
- },
'model.selected' : {
type: function (el, value, previousValue) {
el.checked = value;
},
hook: 'select'
+ },
+ 'model.initialValue': {
+ hook: 'event-trigger-init-value',
+ type: 'booleanAttribute',
+ name: 'checked',
+ },
+ 'model.persistent': {
+ hook: 'event-trigger-persistent',
+ type: 'booleanAttribute',
+ name: 'checked',
}
},
events: {
@@ -72,8 +56,15 @@ module.exports = View.extend({
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
+ if(this.viewMode) {
+ this.delay = this.model.delay === "" ? "None" : this.model.delay;
+ }else{
+ this.model.on("change", _.bind(this.updateViewer, this));
+ }
},
render: function () {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
View.prototype.render.apply(this, arguments);
$(document).on('shown.bs.modal', function (e) {
$('[autofocus]', e.target).focus();
@@ -82,7 +73,15 @@ module.exports = View.extend({
e.target.remove()
});
if(!this.model.annotation){
- $(this.queryByHook('edit-annotation-btn')).text('Add')
+ $(this.queryByHook('edit-annotation-btn')).text('Add');
+ }
+ if(this.viewMode) {
+ this.renderViewEventAssignments();
+ if(this.model.useValuesFromTriggerTime) {
+ $(this.queryByHook("view-trigger-time")).prop('checked', true);
+ }else{
+ $(this.queryByHook("view-assignment-time")).prop('checked', true);
+ }
}
},
update: function () {
@@ -110,7 +109,7 @@ module.exports = View.extend({
});
okBtn.addEventListener('click', function (e) {
self.model.annotation = input.value.trim();
- self.parent.renderEventListingsView();
+ self.parent.renderEditEventListingsView();
modal.modal('hide');
});
},
@@ -118,6 +117,20 @@ module.exports = View.extend({
this.remove();
this.collection.removeEvent(this.model);
},
+ renderViewEventAssignments: function () {
+ if(this.viewEventAssignmentsView){
+ this.viewEventAssignmentsView.remove()
+ }
+ this.viewEventAssignmentsView = new EventAssignment({
+ collection: this.model.eventAssignments,
+ tooltips: this.parent.tooltips,
+ readOnly: true
+ });
+ app.registerRenderSubview(this, this.viewEventAssignmentsView, 'assignment-viewer');
+ },
+ updateViewer: function () {
+ this.parent.renderViewEventListingView();
+ },
subviews: {
inputName: {
hook: 'event-name-container',
diff --git a/client/views/events-editor.js b/client/views/events-editor.js
index 73bfbcca24..ff6b3b34f8 100644
--- a/client/views/events-editor.js
+++ b/client/views/events-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,54 +37,89 @@ module.exports = View.extend({
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
this.tooltips = Tooltips.eventsEditor
- this.opened = attrs.opened
- this.collection.on("select", function (event) {
- this.setSelectedEvent(event);
- this.setDetailsView(event);
- }, this);
- this.collection.on("remove", function (event) {
- // Select the last event by default
- // But only if there are other events other than the one we're removing
- if (event.detailsView)
- event.detailsView.remove();
- this.collection.removeEvent(event);
- if (this.collection.length) {
- var selected = this.collection.at(this.collection.length-1);
- this.collection.trigger("select", selected);
- }
- }, this);
- this.collection.parent.species.on('add remove', this.toggleAddEventButton, this);
- this.collection.parent.parameters.on('add remove', this.toggleAddEventButton, this);
+ if(!this.readOnly) {
+ this.collection.on("select", function (event) {
+ this.setSelectedEvent(event);
+ this.setDetailsView(event);
+ }, this);
+ this.collection.on("remove", function (event) {
+ // Select the last event by default
+ // But only if there are other events other than the one we're removing
+ if (event.detailsView)
+ event.detailsView.remove();
+ this.collection.removeEvent(event);
+ if (this.collection.length) {
+ var selected = this.collection.at(this.collection.length-1);
+ this.collection.trigger("select", selected);
+ }
+ }, this);
+ this.collection.parent.species.on('add remove', this.toggleAddEventButton, this);
+ this.collection.parent.parameters.on('add remove', this.toggleAddEventButton, this);
+ }
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderEventListingsView();
- this.detailsContainer = this.queryByHook('event-details-container');
- this.detailsViewSwitcher = new ViewSwitcher({
- el: this.detailsContainer,
- });
- if (this.collection.length) {
- this.setSelectedEvent(this.collection.at(0));
- this.collection.trigger("select", this.selectedEvent);
- }
- this.toggleAddEventButton()
- if(this.opened) {
- this.openEventsContainer();
+ if(this.readOnly) {
+ $(this.queryByHook('events-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('events-view-tab')).tab('show');
+ $(this.queryByHook('edit-events')).removeClass('active');
+ $(this.queryByHook('view-events')).addClass('active');
+ }else {
+ this.renderEditEventListingsView();
+ this.detailsContainer = this.queryByHook('event-details-container');
+ this.detailsViewSwitcher = new ViewSwitcher({
+ el: this.detailsContainer,
+ });
+ if(this.collection.length) {
+ this.setSelectedEvent(this.collection.at(0));
+ this.collection.trigger("select", this.selectedEvent);
+ }
+ this.toggleAddEventButton()
}
+ this.renderViewEventListingView();
},
update: function () {
},
updateValid: function () {
},
- renderEventListingsView: function () {
- if(this.eventListingsView){
- this.eventListingsView.remove();
+ renderEditEventListingsView: function () {
+ if(this.editEventListingsView){
+ this.editEventListingsView.remove();
+ }
+ this.editEventListingsView = this.renderCollection(
+ this.collection,
+ EventListings,
+ this.queryByHook('edit-event-listing-container')
+ );
+ $(document).ready(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ renderViewEventListingView: function () {
+ if(this.viewEventListingsView) {
+ this.viewEventListingsView.remove();
}
- this.eventListingsView = this.renderCollection(
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("events-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("events-annotation-header")).css("display", "block");
+ }
+ let options = {viewOptions: {parent: this, viewMode: true}};
+ this.viewEventListingsView = this.renderCollection(
this.collection,
EventListings,
- this.queryByHook('event-listing-container')
+ this.queryByHook('view-event-listing-container'),
+ options
);
$(document).ready(function () {
$('[data-toggle="tooltip"]').tooltip();
@@ -134,11 +169,6 @@ module.exports = View.extend({
this.parent.modelStateButtons.clickSaveHandler(e);
this.parent.renderEventsView(mode="view");
},
- openEventsContainer: function () {
- $(this.queryByHook('events')).collapse('show');
- let collapseBtn = $(this.queryByHook('collapse'))
- collapseBtn.trigger('click')
- },
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
},
diff --git a/client/views/events-viewer.js b/client/views/events-viewer.js
deleted file mode 100644
index fd5326b366..0000000000
--- a/client/views/events-viewer.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-//views
-var View = require('ampersand-view');
-var ViewEvent = require('./view-events');
-//templates
-var template = require('../templates/includes/eventsViewer.pug');
-
-module.exports = View.extend({
- template: template,
- events: {
- 'click [data-hook=collapse]' : 'changeCollapseButtonText',
- 'click [data-hook=edit-events]' : 'switchToEditMode'
- },
- 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);
- },
- changeCollapseButtonText: function (e) {
- app.changeCollapseButtonText(this, e);
- },
-});
\ No newline at end of file
diff --git a/client/views/file-browser-view.js b/client/views/file-browser-view.js
index de8ef0e6d2..b60f2bf2b9 100644
--- a/client/views/file-browser-view.js
+++ b/client/views/file-browser-view.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/initial-conditions-editor.js b/client/views/initial-conditions-editor.js
index 5e017ecde2..54a9c1d4f2 100644
--- a/client/views/initial-conditions-editor.js
+++ b/client/views/initial-conditions-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@ along with this program. If not, see .
var $ = require('jquery');
//support files
let app = require('../app');
+let Tooltips = require('../tooltips');
//views
var View = require('ampersand-view');
var EditInitialCondition = require('./edit-initial-condition');
@@ -36,22 +37,24 @@ module.exports = View.extend({
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
- this.opened = attrs.opened;
+ this.tooltips = Tooltips.initialConditionsEditor;
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderCollection(
- this.collection,
- EditInitialCondition,
- this.queryByHook('initial-conditions-collection')
- );
- if(this.opened) {
- this.openInitialConditionContainer();
+ if(this.readOnly) {
+ $(this.queryByHook('initial-conditions-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('initial-conditions-view-tab')).tab('show');
+ $(this.queryByHook('edit-initial-conditions')).removeClass('active');
+ $(this.queryByHook('view-initial-conditions')).addClass('active');
+ }else{
+ this.renderEditInitialConditionsView();
}
- },
- update: function () {
- },
- updateValid: function () {
+ this.renderViewInitialConditionsView();
},
addInitialCondition: function (e) {
var initialConditionType = e.target.textContent;
@@ -63,19 +66,51 @@ module.exports = View.extend({
}else {
var types = [];
}
- console.log(initialConditionType, types)
this.collection.addInitialCondition(initialConditionType, types);
},
- switchToViewMode: function (e) {
- this.parent.modelStateButtons.clickSaveHandler(e);
- this.parent.renderInitialConditions(mode="view");
- },
- openInitialConditionContainer: function () {
- $(this.queryByHook('initial-conditions')).collapse('show');
- let collapseBtn = $(this.queryByHook('initial-condition-button'))
- collapseBtn.trigger('click')
- },
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
- }
+ },
+ renderEditInitialConditionsView: function () {
+ if(this.editInitialConditionView) {
+ this.editInitialConditionView.remove()
+ }
+ this.editInitialConditionView = this.renderCollection(
+ this.collection,
+ EditInitialCondition,
+ this.queryByHook('edit-initial-conditions-collection')
+ );
+ $(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ renderViewInitialConditionsView: function () {
+ if(this.viewInitialConditionView) {
+ this.viewInitialConditionView.remove()
+ }
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("initial-conditions-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("initial-conditions-annotation-header")).css("display", "block");
+ }
+ let options = {viewOptions: {viewMode: true}};
+ this.viewInitialConditionView = this.renderCollection(
+ this.collection,
+ EditInitialCondition,
+ this.queryByHook('view-initial-conditions-collection'),
+ options
+ );
+ $(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ update: function () {},
+ updateValid: function () {}
});
\ No newline at end of file
diff --git a/client/views/initial-conditions-viewer.js b/client/views/initial-conditions-viewer.js
index 777c445851..66bfc3e51f 100644
--- a/client/views/initial-conditions-viewer.js
+++ b/client/views/initial-conditions-viewer.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/input.js b/client/views/input.js
index 4f4ee98a1a..7516be3463 100644
--- a/client/views/input.js
+++ b/client/views/input.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/job-listing.js b/client/views/job-listing.js
index 2398dc5861..e24c2166c9 100644
--- a/client/views/job-listing.js
+++ b/client/views/job-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/main.js b/client/views/main.js
index d432a10296..a62a9a4c2c 100644
--- a/client/views/main.js
+++ b/client/views/main.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/mesh-editor.js b/client/views/mesh-editor.js
index c3054cd9db..b9e9945025 100644
--- a/client/views/mesh-editor.js
+++ b/client/views/mesh-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/meta-data.js b/client/views/meta-data.js
index 37180ea829..f2f459e2a6 100644
--- a/client/views/meta-data.js
+++ b/client/views/meta-data.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/model-listing.js b/client/views/model-listing.js
index 5d753e17fe..24a37cc6a4 100644
--- a/client/views/model-listing.js
+++ b/client/views/model-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/model-state-buttons.js b/client/views/model-state-buttons.js
index f7d5bebf8a..82f4e40412 100644
--- a/client/views/model-state-buttons.js
+++ b/client/views/model-state-buttons.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -63,7 +63,7 @@ module.exports = View.extend({
Plotly.purge(el)
$(this.parent.queryByHook('preview-plot-buttons')).css("display", "none");
if(this.model.is_spatial) {
- this.saveModel(this.getPreviewSpecies.bind(this));
+ this.saveModel(this.getPreviewTarget.bind(this));
}else{
this.saveModel(this.runModel.bind(this));
}
@@ -94,19 +94,19 @@ module.exports = View.extend({
window.location.href = endpoint
})
},
- getPreviewSpecies: function () {
+ getPreviewTarget: function () {
this.saved();
let species = this.model.species.map(function (species) {
return species.name
});
let self = this;
- let modal = $(modals.selectSpeciesHTML(species)).modal();
- let okBtn = document.querySelector("#speciesSelectModal .ok-model-btn");
- let select = document.querySelector("#speciesSelectModal #speciesSelectList");
+ let modal = $(modals.selectPreviewTargetHTML(species)).modal();
+ let okBtn = document.querySelector("#previewTargetSelectModal .ok-model-btn");
+ let select = document.querySelector("#previewTargetSelectModal #previewTargetSelectList");
okBtn.addEventListener('click', function (e) {
modal.modal('hide');
- let specie = select.value;
- self.runModel(specie);
+ let target = select.value;
+ self.runModel(target);
});
},
togglePreviewWorkflowBtn: function () {
@@ -149,16 +149,16 @@ module.exports = View.extend({
saved.style.display = "none";
}, 5000);
},
- runModel: function (species=null) {
- if(typeof species !== "string") {
+ runModel: function (target=null) {
+ if(typeof target !== "string") {
this.saved();
}
this.running();
$(this.parent.queryByHook('model-run-container')).css("display", "block")
var model = this.model
var queryStr = "?cmd=start&outfile=none&path="+model.directory
- if(species) {
- queryStr += "&species=" + species;
+ if(target) {
+ queryStr += "&target=" + target;
}
var endpoint = path.join(app.getApiPath(), 'model/run')+queryStr;
var self = this;
diff --git a/client/views/model-viewer.js b/client/views/model-viewer.js
index 4006bc62be..c1919f2440 100644
--- a/client/views/model-viewer.js
+++ b/client/views/model-viewer.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,11 +20,11 @@ along with this program. If not, see .
let app = require('../app');
//views
let View = require('ampersand-view');
-let RulesViewer = require('./rules-viewer');
-let EventsViewer = require('./events-viewer');
-let SpeciesViewer = require('./species-viewer');
-let ReactionsViewer = require('./reactions-viewer');
-let ParametersEditor = require('./parameters-editor');
+let EventsViewer = require('./events-editor');
+let RulesViewer = require('./rules-editor');
+let SpeciesViewer = require('./species-editor');
+let ReactionsViewer = require('./reactions-editor');
+let ParametersViewer = require('./parameters-editor');
let SBMLComponentsView = require('./sbml-component-editor');
//templates
let template = require('../templates/includes/modelViewer.pug');
@@ -48,12 +48,13 @@ module.exports = View.extend({
},
renderEventsView: function () {
let eventsViewer = new EventsViewer({
- collection: this.model.eventsCollection
+ collection: this.model.eventsCollection,
+ readOnly: true
});
app.registerRenderSubview(this, eventsViewer, "events-viewer-container");
},
renderParametersView: function () {
- let parametersViewer = new ParametersEditor({
+ let parametersViewer = new ParametersViewer({
collection: this.model.parameters,
readOnly: true
});
@@ -61,26 +62,31 @@ module.exports = View.extend({
},
renderReactionsView: function () {
let reactionsViewer = new ReactionsViewer({
- collection: this.model.reactions
+ collection: this.model.reactions,
+ readOnly: true
});
app.registerRenderSubview(this, reactionsViewer, "reactions-viewer-container");
},
renderRulesView: function () {
let rulesViewer = new RulesViewer({
- collection: this.model.rules
+ collection: this.model.rules,
+ readOnly: true
});
app.registerRenderSubview(this, rulesViewer, "rules-viewer-container");
},
renderSBMLComponentsView: function () {
let sbmlComponentsView = new SBMLComponentsView({
functionDefinitions: this.model.functionDefinitions,
- viewMode: true
+ readOnly: true
});
app.registerRenderSubview(this, sbmlComponentsView, "sbml-components-viewer-container");
},
renderSpeciesView: function () {
let speciesViewer = new SpeciesViewer({
- collection: this.model.species
+ collection: this.model.species,
+ spatial: this.model.is_spatial,
+ defaultMode: this.model.defaultMode,
+ readOnly: true
});
app.registerRenderSubview(this, speciesViewer, "species-viewer-container");
},
diff --git a/client/views/parameter-settings.js b/client/views/parameter-settings.js
index 50f47229df..dcaba4fce5 100644
--- a/client/views/parameter-settings.js
+++ b/client/views/parameter-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/parameters-editor.js b/client/views/parameters-editor.js
index aa72c100c5..d7623c1a93 100644
--- a/client/views/parameters-editor.js
+++ b/client/views/parameters-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/quickview-domain-types.js b/client/views/quickview-domain-types.js
index 5b003200d3..967715448c 100644
--- a/client/views/quickview-domain-types.js
+++ b/client/views/quickview-domain-types.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/reactant-product.js b/client/views/reactant-product.js
index 7bd3858693..8a982bcc03 100644
--- a/client/views/reactant-product.js
+++ b/client/views/reactant-product.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/reaction-details.js b/client/views/reaction-details.js
index 36e1949844..00f27574a7 100644
--- a/client/views/reaction-details.js
+++ b/client/views/reaction-details.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -182,6 +182,7 @@ module.exports = View.extend({
var val = e.target.selectedOptions.item(0).text;
var param = this.getRateFromParameters(val);
this.model.rate = param || this.model.rate;
+ this.model.trigger("change");
this.model.collection.trigger("change");
}
},
diff --git a/client/views/reaction-listing.js b/client/views/reaction-listing.js
index 864c24a43d..2503be8ee3 100644
--- a/client/views/reaction-listing.js
+++ b/client/views/reaction-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@ along with this program. If not, see .
var $ = require('jquery');
var katex = require('katex');
+let _ = require('underscore');
//support files
var tests = require('./tests');
var modals = require('../modals');
@@ -25,10 +26,10 @@ var modals = require('../modals');
var View = require('ampersand-view');
var InputView = require('./input');
//templates
-var template = require('../templates/includes/reactionListing.pug');
+var editTemplate = require('../templates/includes/reactionListing.pug');
+let viewTemplate = require('../templates/includes/viewReactions.pug');
module.exports = View.extend({
- template: template,
bindings: {
'model.name' : {
type: 'value',
@@ -58,8 +59,23 @@ module.exports = View.extend({
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.viewMode = attrs.viewMode ? attrs.viewMode : false;
+ if(this.viewMode) {
+ this.rate = this.model.reactionType === "custom-propensity" ? this.model.propensity : this.model.rate.name;
+ this.types = [];
+ let self = this;
+ if(this.model.types) {
+ this.model.types.forEach(function (index) {
+ let type = self.model.collection.parent.domain.types.get(index, "typeID");
+ self.types.push(type.name)
+ });
+ }
+ }else{
+ this.model.on('change', _.bind(this.updateViewer, this));
+ }
},
render: function () {
+ this.template = this.viewMode ? viewTemplate : editTemplate;
View.prototype.render.apply(this, arguments);
$(document).on('shown.bs.modal', function (e) {
$('[autofocus]', e.target).focus();
@@ -100,10 +116,13 @@ module.exports = View.extend({
});
okBtn.addEventListener('click', function (e) {
self.model.annotation = input.value.trim();
- self.parent.renderReactionListingView();
+ self.parent.renderEditReactionListingView();
modal.modal('hide');
});
},
+ updateViewer: function () {
+ this.parent.renderViewReactionView();
+ },
subviews: {
inputName: {
hook: 'input-name-container',
diff --git a/client/views/reaction-types.js b/client/views/reaction-types.js
index f931b17510..e57eddcc06 100644
--- a/client/views/reaction-types.js
+++ b/client/views/reaction-types.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/reactions-editor.js b/client/views/reactions-editor.js
index c54ef00484..e6539a856e 100644
--- a/client/views/reactions-editor.js
+++ b/client/views/reactions-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,69 +45,83 @@ module.exports = View.extend({
'click [data-hook=four]' : 'handleAddReactionClick',
'click [data-hook=custom-massaction]' : 'handleAddReactionClick',
'click [data-hook=custom-propensity]' : 'handleAddReactionClick',
- 'click [data-hook=save-reactions]' : 'switchToViewMode',
'click [data-hook=collapse]' : 'changeCollapseButtonText'
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
this.tooltips = Tooltips.reactionsEditor
- this.opened = attrs.opened
- this.collection.on("select", function (reaction) {
- this.setSelectedReaction(reaction);
- this.setDetailsView(reaction);
- }, this);
- this.collection.on("remove", function (reaction) {
- // Select the last reaction by default
- // But only if there are other reactions other than the one we're removing
- if (reaction.detailsView)
- reaction.detailsView.remove();
- this.collection.removeReaction(reaction);
- if (this.collection.length) {
- var selected = this.collection.at(this.collection.length-1);
- this.collection.trigger("select", selected);
- }
- }, this);
- this.collection.parent.species.on('add remove', this.toggleAddReactionButton, this);
- this.collection.parent.parameters.on('add remove', this.toggleReactionTypes, this);
- this.collection.parent.on('change', this.toggleProcessError, this)
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
+ if(!this.readOnly) {
+ this.collection.on("select", function (reaction) {
+ this.setSelectedReaction(reaction);
+ this.setDetailsView(reaction);
+ }, this);
+ this.collection.on("remove", function (reaction) {
+ // Select the last reaction by default
+ // But only if there are other reactions other than the one we're removing
+ if (reaction.detailsView)
+ reaction.detailsView.remove();
+ this.collection.removeReaction(reaction);
+ if (this.collection.length) {
+ var selected = this.collection.at(this.collection.length-1);
+ this.collection.trigger("select", selected);
+ }
+ }, this);
+ this.collection.parent.species.on('add remove', this.toggleAddReactionButton, this);
+ this.collection.parent.parameters.on('add remove', this.toggleReactionTypes, this);
+ this.collection.parent.on('change', this.toggleProcessError, this)
+ }
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderReactionListingView();
- this.detailsContainer = this.queryByHook('reaction-details-container');
- this.detailsViewSwitcher = new ViewSwitcher({
- el: this.detailsContainer,
- });
- if (this.collection.length) {
- this.setSelectedReaction(this.collection.at(0));
- this.collection.trigger("select", this.selectedReaction);
- }
- this.collection.trigger("change");
- this.toggleAddReactionButton();
- if(this.collection.parent.parameters.length > 0){
- $(this.queryByHook('add-reaction-partial')).prop('hidden', true);
- }
- else{
- $(this.queryByHook('add-reaction-full')).prop('hidden', true);
- }
- this.renderReactionTypes();
- katex.render("\\emptyset", this.queryByHook('emptyset'), {
- displayMode: false,
- output: 'html',
- });
- if(this.opened) {
- this.openReactionsContainer();
+ if(this.readOnly) {
+ this.renderViewReactionView()
+ $(this.queryByHook('reactions-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('reactions-view-tab')).tab('show');
+ $(this.queryByHook('edit-reactions')).removeClass('active');
+ $(this.queryByHook('view-reactions')).addClass('active');
+ }else{
+ this.renderReactionListingViews();
+ this.detailsContainer = this.queryByHook('reaction-details-container');
+ this.detailsViewSwitcher = new ViewSwitcher({
+ el: this.detailsContainer,
+ });
+ if (this.collection.length) {
+ this.setSelectedReaction(this.collection.at(0));
+ this.collection.trigger("select", this.selectedReaction);
+ }
+ this.collection.trigger("change");
+ this.toggleAddReactionButton();
+ if(this.collection.parent.parameters.length > 0){
+ $(this.queryByHook('add-reaction-partial')).prop('hidden', true);
+ }
+ else{
+ $(this.queryByHook('add-reaction-full')).prop('hidden', true);
+ }
+ this.renderReactionTypes();
+ katex.render("\\emptyset", this.queryByHook('emptyset'), {
+ displayMode: false,
+ output: 'html',
+ });
+ this.toggleProcessError()
+ $(this.queryByHook('massaction-message')).prop('hidden', this.collection.parent.parameters.length > 0);
}
- this.toggleProcessError()
- $(this.queryByHook('massaction-message')).prop('hidden', this.collection.parent.parameters.length > 0);
},
update: function () {
},
updateValid: function () {
},
- renderReactionListingView: function () {
- if(this.reactionListingView){
- this.reactionListingView.remove();
+ renderReactionListingViews: function () {
+ this.renderEditReactionListingView();
+ this.renderViewReactionView();
+ },
+ renderEditReactionListingView: function () {
+ if(this.editReactionListingView){
+ this.editReactionListingView.remove();
}
if(this.collection.parent.parameters.length <= 0) {
for(var i = 0; i < this.collection.length; i++) {
@@ -116,10 +130,10 @@ module.exports = View.extend({
}
}
}
- this.reactionListingView = this.renderCollection(
+ this.editReactionListingView = this.renderCollection(
this.collection,
ReactionListingView,
- this.queryByHook('reaction-list')
+ this.queryByHook('edit-reaction-list')
);
$(document).ready(function () {
$('[data-toggle="tooltip"]').tooltip();
@@ -128,6 +142,27 @@ module.exports = View.extend({
});
});
},
+ renderViewReactionView: function () {
+ if(this.viewReactionListingView){
+ this.viewReactionListingView.remove();
+ }
+ if(!this.collection.parent.is_spatial){
+ $(this.queryByHook("reaction-types-header")).css("display", "none");
+ }
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("reaction-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("reaction-annotation-header")).css("display", "block");
+ }
+ let options = {viewOptions: {viewMode: true, hasAnnotations: this.containsMdlWithAnn}}
+ this.viewReactionListingView = this.renderCollection(
+ this.collection,
+ ReactionListingView,
+ this.queryByHook('view-reaction-list'),
+ options
+ );
+ },
toggleAddReactionButton: function () {
$(this.queryByHook('add-reaction-full')).prop('disabled', (this.collection.parent.species.length <= 0));
$(this.queryByHook('add-reaction-partial')).prop('disabled', (this.collection.parent.species.length <= 0));
@@ -186,10 +221,6 @@ module.exports = View.extend({
detailsView.parent = this;
return detailsView
},
- switchToViewMode: function (e) {
- this.parent.modelStateButtons.clickSaveHandler(e);
- this.parent.renderReactionsView(mode="view");
- },
openReactionsContainer: function () {
$(this.queryByHook('reactions-list-container')).collapse('show');
let collapseBtn = $(this.queryByHook('collapse'))
@@ -206,8 +237,9 @@ module.exports = View.extend({
return ReactionTypes[type].label
},
toggleProcessError: function () {
- let errorMsg = $(this.queryByHook('process-component-error'))
let model = this.collection.parent
+ if(model.is_spatial) {return};
+ let errorMsg = $(this.queryByHook('process-component-error'))
if(this.collection.length <= 0 && model.eventsCollection.length <= 0 && model.rules.length <= 0) {
errorMsg.addClass('component-invalid')
errorMsg.removeClass('component-valid')
diff --git a/client/views/reactions-viewer.js b/client/views/reactions-viewer.js
deleted file mode 100644
index ee31d9b390..0000000000
--- a/client/views/reactions-viewer.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-//views
-var View = require('ampersand-view');
-var ViewReactions = require('./view-reactions');
-//templates
-var template = require('../templates/includes/reactionsViewer.pug');
-
-module.exports = View.extend({
- template: template,
- events: {
- 'click [data-hook=collapse]' : 'changeCollapseButtonText',
- 'click [data-hook=edit-reactions]' : 'switchToEditMode'
- },
- 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);
- },
- changeCollapseButtonText: function (e) {
- app.changeCollapseButtonText(this, e);
- },
-});
\ No newline at end of file
diff --git a/client/views/rules-editor.js b/client/views/rules-editor.js
index fdba4cb842..489a41e770 100644
--- a/client/views/rules-editor.js
+++ b/client/views/rules-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,38 +31,70 @@ module.exports = View.extend({
events: {
'click [data-hook=rate-rule]' : 'addRule',
'click [data-hook=assignment-rule]' : 'addRule',
- 'click [data-hook=save-rules]' : 'switchToViewMode',
'click [data-hook=collapse]' : 'changeCollapseButtonText',
},
- initialize: function (args) {
+ initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
this.collection.parent.species.on('add remove', this.toggleAddRuleButton, this);
this.collection.parent.parameters.on('add remove', this.toggleAddRuleButton, this);
this.tooltips = Tooltips.rulesEditor
- this.opened = args.opened
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderRules();
- this.toggleAddRuleButton()
- if(this.opened) {
- this.openRulesContainer();
+ if(this.readOnly) {
+ $(this.queryByHook('rules-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('rules-view-tab')).tab('show');
+ $(this.queryByHook('edit-rules')).removeClass('active');
+ $(this.queryByHook('view-rules')).addClass('active');
+ }else {
+ this.renderEditRules();
+ this.toggleAddRuleButton();
}
+ this.renderViewRules();
},
update: function () {
},
updateValid: function () {
},
- renderRules: function () {
+ renderEditRules: function () {
if(this.rulesView) {
this.rulesView.remove();
}
this.rulesView = this.renderCollection(
this.collection,
RuleView,
- this.queryByHook('rule-list-container')
+ this.queryByHook('edit-rule-list-container')
+ );
+ $(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ renderViewRules: function () {
+ if(this.viewRulesView) {
+ this.viewRulesView.remove();
+ }
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("rules-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("rules-annotation-header")).css("display", "block");
+ }
+ let options = {viewOptions: {viewMode: true}};
+ this.viewRulesView = this.renderCollection(
+ this.collection,
+ RuleView,
+ this.queryByHook('view-rules-list-container'),
+ options
);
- $(document).ready(function () {
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
@@ -70,7 +102,7 @@ module.exports = View.extend({
});
},
toggleAddRuleButton: function () {
- this.renderRules();
+ this.renderEditRules();
var numSpecies = this.collection.parent.species.length;
var numParameters = this.collection.parent.parameters.length;
var disabled = numSpecies <= 0 && numParameters <= 0
@@ -79,7 +111,7 @@ module.exports = View.extend({
addRule: function (e) {
var type = e.target.dataset.name
this.collection.addRule(type);
- $(document).ready(function () {
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
@@ -87,15 +119,6 @@ module.exports = View.extend({
});
});
},
- switchToViewMode: function (e) {
- this.parent.modelStateButtons.clickSaveHandler(e);
- this.parent.renderRulesView(mode="view");
- },
- openRulesContainer: function () {
- $(this.queryByHook('rules-list-container')).collapse('show');
- let collapseBtn = $(this.queryByHook('collapse'))
- collapseBtn.trigger('click')
- },
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
},
diff --git a/client/views/rules-viewer.js b/client/views/rules-viewer.js
deleted file mode 100644
index a8fce201da..0000000000
--- a/client/views/rules-viewer.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-//views
-var View = require('ampersand-view');
-var ViewRules = require('./view-rules');
-//templates
-var template = require('../templates/includes/rulesViewer.pug');
-
-module.exports = View.extend({
- template: template,
- events: {
- 'click [data-hook=collapse]' : 'changeCollapseButtonText',
- 'click [data-hook=edit-rules]' : 'switchToEditMode'
- },
- 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);
- },
- changeCollapseButtonText: function (e) {
- app.changeCollapseButtonText(this, e);
- },
-});
\ No newline at end of file
diff --git a/client/views/sbml-component-editor.js b/client/views/sbml-component-editor.js
index 565b097bc4..678984682d 100644
--- a/client/views/sbml-component-editor.js
+++ b/client/views/sbml-component-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,22 +36,58 @@ module.exports = View.extend({
View.prototype.initialize.apply(this, arguments);
this.tooltips = Tooltips.sbmlComponentsEditor
this.functionDefinitions = attrs.functionDefinitions;
- this.viewMode = attrs.viewMode;
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
},
render: function () {
View.prototype.render.apply(this, arguments);
- this.renderEdirFunctionDefinitionView();
+ if(this.readOnly) {
+ $(this.queryByHook('function-definitions-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('function-definitions-view-tab')).tab('show');
+ $(this.queryByHook('edit-function-definitions')).removeClass('active');
+ $(this.queryByHook('view-function-definitions')).addClass('active');
+ }else {
+ this.renderEditFunctionDefinitionView();
+ }
+ this.renderViewFunctionDefinitionView();
},
- renderEdirFunctionDefinitionView: function () {
+ renderEditFunctionDefinitionView: function () {
if(this.editFunctionDefinitionView){
this.editFunctionDefinitionView.remove();
}
this.editFunctionDefinitionView = this.renderCollection(
this.functionDefinitions,
EditFunctionDefinition,
- this.queryByHook('function-definition-list')
+ this.queryByHook('edit-function-definition-list')
+ );
+ $(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+ });
+ });
+ },
+ renderViewFunctionDefinitionView: function () {
+ if(this.viewFunctionDefinitionView) {
+ this.viewFunctionDefinitionView.remove();
+ }
+ let options = {viewOptions: {viewMode: true}};
+ this.containsMdlWithAnn = this.functionDefinitions.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("function-definition-annotation-header")).css("display", "none");
+ }else{
+ $(this.queryByHook("function-definition-annotation-header")).css("display", "block");
+ }
+ this.viewFunctionDefinitionView = this.renderCollection(
+ this.functionDefinitions,
+ EditFunctionDefinition,
+ this.queryByHook('view-function-definition-list'),
+ options
);
- $(document).ready(function () {
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
diff --git a/client/views/settings-viewer.js b/client/views/settings-viewer.js
index 918bfddf2b..bb45c043a6 100644
--- a/client/views/settings-viewer.js
+++ b/client/views/settings-viewer.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/settings.js b/client/views/settings.js
index 3cec47d4f8..4905e37461 100644
--- a/client/views/settings.js
+++ b/client/views/settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/simulation-settings.js b/client/views/simulation-settings.js
index 024c7d381b..f6300beac2 100644
--- a/client/views/simulation-settings.js
+++ b/client/views/simulation-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/species-editor.js b/client/views/species-editor.js
index e144b43d22..9ac3ae456e 100644
--- a/client/views/species-editor.js
+++ b/client/views/species-editor.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,54 +16,53 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-var $ = require('jquery');
+let $ = require('jquery');
//support files
let app = require('../app');
-var modals = require('../modals');
-var Tooltips = require('../tooltips');
+let Tooltips = require('../tooltips');
//views
-var View = require('ampersand-view');
-var EditNonspatialSpecieView = require('./edit-specie');
-var EditSpatialSpecieView = require('./edit-spatial-specie');
-var EditAdvancedSpecie = require('./edit-advanced-specie');
+let View = require('ampersand-view');
+let SpecieView = require('./edit-species');
//templates
-var nonspatialSpecieTemplate = require('../templates/includes/speciesEditor.pug');
-var spatialSpecieTemplate = require('../templates/includes/spatialSpeciesEditor.pug');
+let speciesTemplate = require('../templates/includes/speciesEditor.pug');
+let spatialSpeciesTemplate = require('../templates/includes/spatialSpeciesEditor.pug');
module.exports = View.extend({
events: {
- 'change [data-hook=all-continuous]' : 'getDefaultSpeciesMode',
- 'change [data-hook=all-discrete]' : 'getDefaultSpeciesMode',
- 'change [data-hook=advanced]' : 'getDefaultSpeciesMode',
- 'click [data-hook=add-species]' : 'handleAddSpeciesClick',
- 'click [data-hook=save-species]' : 'switchToViewMode',
'click [data-hook=collapse]' : 'changeCollapseButtonText',
+ 'click [data-hook=add-species]' : 'handleAddSpeciesClick'
},
initialize: function (attrs, options) {
- var self = this;
View.prototype.initialize.apply(this, arguments);
- this.baseModel = this.collection.parent;
- this.tooltips = Tooltips.speciesEditor
+ this.spatial = attrs.spatial
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
+ this.template = this.spatial ? spatialSpeciesTemplate : speciesTemplate;
+ this.tooltips = Tooltips.speciesEditor;
+ this.defaultMode = attrs.defaultMode;
+ let self = this
this.collection.on('update-species', function (compID, specie, isNameUpdate, isDefaultMode) {
- self.collection.parent.reactions.map(function (reaction) {
- reaction.reactants.map(function (reactant) {
+ self.collection.parent.reactions.forEach(function (reaction) {
+ reaction.reactants.forEach(function (reactant) {
if(reactant.specie.compID === compID) {
reactant.specie = specie;
}
});
- reaction.products.map(function (product) {
+ reaction.products.forEach(function (product) {
if(product.specie.compID === compID) {
product.specie = specie;
}
});
if(isNameUpdate) {
reaction.buildSummary();
+ if(reaction.selected) {
+ self.parent.reactionsEditor.setDetailsView(reaction);
+ }
}else if(!isDefaultMode || specie.compID === self.collection.models[self.collection.length-1].compID){
reaction.checkModes();
}
});
- self.collection.parent.eventsCollection.map(function (event) {
- event.eventAssignments.map(function (assignment) {
+ self.collection.parent.eventsCollection.forEach(function (event) {
+ event.eventAssignments.forEach(function (assignment) {
if(assignment.variable.compID === compID) {
assignment.variable = specie;
}
@@ -72,140 +71,105 @@ module.exports = View.extend({
event.detailsView.renderEventAssignments();
}
});
- self.collection.parent.rules.map(function (rule) {
+ self.collection.parent.rules.forEach(function (rule) {
if(rule.variable.compID === compID) {
rule.variable = specie;
}
});
if(isNameUpdate) {
- self.renderSpeciesAdvancedView();
self.parent.renderRulesView();
}
});
},
render: function () {
- this.template = this.parent.model.is_spatial ? spatialSpecieTemplate : nonspatialSpecieTemplate;
View.prototype.render.apply(this, arguments);
- var defaultMode = this.collection.parent.defaultMode;
- if(defaultMode === "" && !this.collection.parent.is_spatial){
- this.getInitialDefaultSpeciesMode();
+ if(this.readOnly) {
+ $(this.queryByHook('species-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('species-view-tab')).tab('show');
+ $(this.queryByHook('edit-species')).removeClass('active');
+ $(this.queryByHook('view-species')).addClass('active');
}else{
- var dataHooks = {'continuous':'all-continuous', 'discrete':'all-discrete', 'dynamic':'advanced'}
- $(this.queryByHook(dataHooks[this.collection.parent.defaultMode])).prop('checked', true)
- if(defaultMode === "dynamic"){
- $(this.queryByHook('advanced-species')).collapse('show');
- }
+ this.toggleSpeciesCollectionError();
+ this.renderEditSpeciesView();
}
- this.renderEditSpeciesView();
- this.renderSpeciesAdvancedView();
- this.toggleSpeciesCollectionError();
+ this.renderViewSpeciesView();
},
- update: function () {
- },
- updateValid: function (e) {
- },
- getInitialDefaultSpeciesMode: function () {
- var self = this;
- if(document.querySelector('#defaultModeModal')) {
- document.querySelector('#defaultModeModal').remove()
+ addSpecies: function () {
+ if(this.parent.model.domain.types) {
+ var types = this.parent.model.domain.types.map(function (type) {
+ return type.typeID;
+ });
+ types.shift()
+ }else{
+ var types = []
}
- let modal = $(modals.renderDefaultModeModalHtml()).modal();
- let continuous = document.querySelector('#defaultModeModal .concentration-btn');
- let discrete = document.querySelector('#defaultModeModal .population-btn');
- let dynamic = document.querySelector('#defaultModeModal .hybrid-btn');
- continuous.addEventListener('click', function (e) {
- self.setInitialDefaultMode(modal, "continuous");
- });
- discrete.addEventListener('click', function (e) {
- self.setInitialDefaultMode(modal, "discrete");
- });
- dynamic.addEventListener('click', function (e) {
- self.setInitialDefaultMode(modal, "dynamic");
+ this.collection.addSpecie(types);
+ this.toggleSpeciesCollectionError()
+ $(function () {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="tooltip"]').click(function () {
+ $('[data-toggle="tooltip"]').tooltip("hide");
+
+ });
});
},
- setInitialDefaultMode: function (modal, mode) {
- var dataHooks = {'continuous':'all-continuous', 'discrete':'all-discrete', 'dynamic':'advanced'}
- modal.modal('hide')
- $(this.queryByHook(dataHooks[mode])).prop('checked', true)
- this.setAllSpeciesModes(mode)
- },
- getDefaultSpeciesMode: function (e) {
- var self = this;
- this.setAllSpeciesModes(e.target.dataset.name, function (specie) {
- self.collection.trigger('update-species', specie.compID, specie, false, true)
- });
+ changeCollapseButtonText: function (e) {
+ app.changeCollapseButtonText(this, e);
},
- setAllSpeciesModes: function (defaultMode, cb) {
- this.collection.parent.defaultMode = defaultMode;
- this.collection.forEach(function (specie) {
- specie.mode = defaultMode
- if(cb) {
- cb(specie)
- }
- });
- if(!this.collection.parent.is_spatial) {
- if(defaultMode === "continuous") {
- $(this.parent.queryByHook("system-volume-container")).collapse("hide")
- }else{
- $(this.parent.queryByHook("system-volume-container")).collapse("show")
- }
- if(defaultMode === "dynamic"){
- this.renderSpeciesAdvancedView()
- $(this.queryByHook('advanced-species')).collapse('show');
- }
- else{
- this.speciesAdvancedView.views[0].updateInputValidation()
- $(this.queryByHook('advanced-species')).collapse('hide');
- }
+ handleAddSpeciesClick: function (e) {
+ let self = this;
+ let defaultMode = this.collection.parent.defaultMode;
+ if(defaultMode === "" && !this.collection.parent.is_spatial){
+ this.parent.getInitialDefaultMode();
+ }else{
+ this.addSpecies();
}
},
renderEditSpeciesView: function () {
if(this.editSpeciesView){
this.editSpeciesView.remove();
}
- var editSpecieView = !this.collection.parent.is_spatial ? EditNonspatialSpecieView : EditSpatialSpecieView;
+ let options = {viewOptions: {parent: this}};
this.editSpeciesView = this.renderCollection(
this.collection,
- editSpecieView,
- this.queryByHook('specie-list')
+ SpecieView,
+ this.queryByHook('edit-specie-list')
);
- $(document).ready(function () {
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
- $('[data-toggle="tooltip"]').tooltip("hide");
- });
+ $('[data-toggle="tooltip"]').tooltip("hide");
+
+ });
});
},
- renderSpeciesAdvancedView: function () {
- if(this.collection.parent.is_spatial) {
- return
- }
- if(this.speciesAdvancedView) {
- this.speciesAdvancedView.remove()
+ renderViewSpeciesView: function () {
+ if(this.viewSpeciesView){
+ this.viewSpeciesView.remove();
}
- this.speciesAdvancedView = this.renderCollection(this.collection, EditAdvancedSpecie, this.queryByHook('edit-species-mode'));
- },
- handleAddSpeciesClick: function (e) {
- var self = this;
- var defaultMode = this.collection.parent.defaultMode;
- if(defaultMode === "" && !this.collection.parent.is_spatial){
- this.getInitialDefaultSpeciesMode();
+ if(this.defaultMode !== "dynamic") {
+ $(this.queryByHook("species-switching-header")).css("display", "none");
}else{
- this.addSpecies();
+ $(this.queryByHook("species-switching-header")).css("display", "block");
}
- },
- addSpecies: function () {
- if(this.parent.model.domain.types) {
- var types = this.parent.model.domain.types.map(function (type) {
- return type.typeID;
- });
- types.shift()
+ this.containsMdlWithAnn = this.collection.filter(function (model) {return model.annotation}).length > 0;
+ if(!this.containsMdlWithAnn) {
+ $(this.queryByHook("species-annotation-header")).css("display", "none");
}else{
- var types = []
+ $(this.queryByHook("species-annotation-header")).css("display", "block");
}
- this.collection.addSpecie(types);
- this.toggleSpeciesCollectionError()
- $(document).ready(function () {
+ let options = {viewOptions: {parent: this, viewMode: true}};
+ this.viewSpeciesView = this.renderCollection(
+ this.collection,
+ SpecieView,
+ this.queryByHook('view-specie-list'),
+ options
+ );
+ $(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').click(function () {
$('[data-toggle="tooltip"]').tooltip("hide");
@@ -214,6 +178,7 @@ module.exports = View.extend({
});
},
toggleSpeciesCollectionError: function () {
+ if(this.spatial) {return};
let errorMsg = $(this.queryByHook('species-collection-error'))
if(this.collection.length <= 0) {
errorMsg.addClass('component-invalid')
@@ -222,12 +187,5 @@ module.exports = View.extend({
errorMsg.addClass('component-valid')
errorMsg.removeClass('component-invalid')
}
- },
- switchToViewMode: function (e) {
- this.parent.modelStateButtons.clickSaveHandler(e);
- this.parent.renderSpeciesView(mode="view");
- },
- changeCollapseButtonText: function (e) {
- app.changeCollapseButtonText(this, e);
}
-});
\ No newline at end of file
+});
diff --git a/client/views/species-viewer.js b/client/views/species-viewer.js
deleted file mode 100644
index 7087d36bca..0000000000
--- a/client/views/species-viewer.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-//views
-var View = require('ampersand-view');
-var ViewSpecie = require('./view-specie');
-//templates
-var template = require('../templates/includes/speciesViewer.pug');
-
-module.exports = View.extend({
- template: template,
- events: {
- 'click [data-hook=collapse]' : 'changeCollapseButtonText',
- 'click [data-hook=edit-species]' : 'switchToEditMode'
- },
- 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();
- },
- changeCollapseButtonText: function (e) {
- app.changeCollapseButtonText(this, e);
- },
-});
\ No newline at end of file
diff --git a/client/views/sweep-parameter-range.js b/client/views/sweep-parameter-range.js
index 9b297388dc..00faa0a625 100644
--- a/client/views/sweep-parameter-range.js
+++ b/client/views/sweep-parameter-range.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/sweep-parameter.js b/client/views/sweep-parameter.js
index 29a092bdf3..1aebd9a482 100644
--- a/client/views/sweep-parameter.js
+++ b/client/views/sweep-parameter.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/tests.js b/client/views/tests.js
index 057fcf283a..ebee33007a 100644
--- a/client/views/tests.js
+++ b/client/views/tests.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/timespan-settings.js b/client/views/timespan-settings.js
index 22b8cd3fbf..c0f41ec245 100644
--- a/client/views/timespan-settings.js
+++ b/client/views/timespan-settings.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,15 +31,31 @@ module.exports = View.extend({
template: template,
events: {
'click [data-hook=collapse]' : 'changeCollapseButtonText',
- },
- bindings: {
+ 'input [data-hook=timestep-size-slider]' : 'viewTimestepValue',
+ 'change [data-hook=preview-time]' : 'updateViewer',
+ 'change [data-hook=time-units]' : 'updateViewer',
+ 'change [data-hook=timestep-size-slider]' : 'setTimestepSize'
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
+ this.readOnly = attrs.readOnly ? attrs.readOnly : false;
this.tooltips = Tooltips.modelSettings
+ let tssValues = {1e-5: 5, 1e-4: 4, 1e-3: 3, 1e-2: 2, 1e-1: 1, 1: 0}
+ this.tssValue = tssValues[this.model.timestepSize]
},
render: function () {
View.prototype.render.apply(this, arguments);
+ if(this.readOnly) {
+ $(this.queryByHook('timespan-edit-tab')).addClass("disabled");
+ $(".nav .disabled>a").on("click", function(e) {
+ e.preventDefault();
+ return false;
+ });
+ $(this.queryByHook('timespan-view-tab')).tab('show');
+ $(this.queryByHook('edit-timespan')).removeClass('active');
+ $(this.queryByHook('view-timespan')).addClass('active');
+ }
+ $(this.queryByHook("timestep-size-value")).html(this.model.timestepSize);
},
update: function (e) {
},
@@ -49,6 +65,18 @@ module.exports = View.extend({
changeCollapseButtonText: function (e) {
app.changeCollapseButtonText(this, e);
},
+ setTimestepSize: function (e) {
+ this.model.timestepSize = Number("1e-" + e.target.value);
+ $(this.queryByHook("view-timestep-size")).html(this.model.timestepSize);
+ },
+ updateViewer: function (e) {
+ $(this.queryByHook("view-end-sim")).html("0 to " + this.model.endSim);
+ $(this.queryByHook("view-time-step")).html(this.model.timeStep);
+ },
+ viewTimestepValue: function (e) {
+ let value = Number("1e-" + e.target.value);
+ $(this.queryByHook("timestep-size-value")).html(value);
+ },
subviews: {
inputSimEnd: {
hook: 'preview-time',
diff --git a/client/views/view-event-assignments.js b/client/views/view-event-assignments.js
deleted file mode 100644
index 709bab1ce8..0000000000
--- a/client/views/view-event-assignments.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-//views
-var View = require('ampersand-view');
-//templates
-var template = require('../templates/includes/viewEventAssignments.pug');
-
-module.exports = View.extend({
- template: template,
-});
\ No newline at end of file
diff --git a/client/views/view-events.js b/client/views/view-events.js
deleted file mode 100644
index 0b04864060..0000000000
--- a/client/views/view-events.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var $ = require('jquery');
-//support files
-let app = require('../app');
-//views
-var View = require('ampersand-view');
-var AssignmentsViewer = require('./event-assignments-viewer');
-//templates
-var template = require('../templates/includes/viewEvents.pug');
-
-module.exports = View.extend({
- template: template,
- bindings: {
- 'model.initialValue': {
- hook: 'event-trigger-init-value',
- type: 'booleanAttribute',
- name: 'checked',
- },
- 'model.persistent': {
- hook: 'event-trigger-persistent',
- type: 'booleanAttribute',
- name: 'checked',
- }
- },
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- this.delay = this.model.delay === "" ? "None" : this.model.delay
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- var assignmentsViewer = new AssignmentsViewer({
- collection: this.model.eventAssignments
- });
- app.registerRenderSubview(this, assignmentsViewer, 'assignment-viewer');
- if(this.model.useValuesFromTriggerTime) {
- $(this.queryByHook("trigger-time")).prop('checked', true)
- }else{
- $(this.queryByHook("assignment-time")).prop('checked', true)
- }
- }
-});
\ No newline at end of file
diff --git a/client/views/view-initial-condition.js b/client/views/view-initial-condition.js
index 451e5356e0..49ae01f0ae 100644
--- a/client/views/view-initial-condition.js
+++ b/client/views/view-initial-condition.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/view-particle.js b/client/views/view-particle.js
index 7126ff21fe..4948a2804d 100644
--- a/client/views/view-particle.js
+++ b/client/views/view-particle.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/view-reactions.js b/client/views/view-reactions.js
deleted file mode 100644
index be5a565ab5..0000000000
--- a/client/views/view-reactions.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-var katex = require('katex');
-//views
-var View = require('ampersand-view');
-//templates
-var template = require('../templates/includes/viewReactions.pug');
-
-module.exports = View.extend({
- template: template,
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- let self = this;
- this.types = [];
- if(this.model.types) {
- this.model.types.forEach(function (index) {
- let type = self.model.collection.parent.domain.types.get(index, "typeID");
- self.types.push(type.name)
- });
- }
- this.rate = this.model.reactionType === "custom-propensity" ?
- this.model.propensity : this.model.rate.name
- },
- render: function () {
- View.prototype.render.apply(this, arguments);
- katex.render(this.model.summary, this.queryByHook('summary'), {
- displayMode: false,
- output: 'html',
- throwOnError: false
- });
- },
-});
\ No newline at end of file
diff --git a/client/views/view-specie.js b/client/views/view-specie.js
deleted file mode 100644
index f0a5ee22be..0000000000
--- a/client/views/view-specie.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-//views
-var View = require('ampersand-view');
-//templates
-var template = require('../templates/includes/viewSpecies.pug');
-
-module.exports = View.extend({
- template: template,
- initialize: function (attrs, options) {
- View.prototype.initialize.apply(this, arguments);
- let self = this;
- this.types = [];
- if(this.model.types) {
- this.model.types.forEach(function (index) {
- let type = self.model.collection.parent.domain.types.get(index, "typeID");
- self.types.push(type.name)
- });
- }
- this.switchingValWithLabel = this.model.isSwitchTol ?
- "Switching Tolerance: " + this.model.switchTol :
- "Minimum Value For Switching: " + this.model.switchMin
- },
-});
\ No newline at end of file
diff --git a/client/views/view-sweep-parameter.js b/client/views/view-sweep-parameter.js
index bc64a1dab2..10d6b01fa3 100644
--- a/client/views/view-sweep-parameter.js
+++ b/client/views/view-sweep-parameter.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/workflow-group-listing.js b/client/views/workflow-group-listing.js
index 1e1d322211..c51e723eea 100644
--- a/client/views/workflow-group-listing.js
+++ b/client/views/workflow-group-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/workflow-info.js b/client/views/workflow-info.js
index cefad55a32..526ddc3514 100644
--- a/client/views/workflow-info.js
+++ b/client/views/workflow-info.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/workflow-listing.js b/client/views/workflow-listing.js
index 7ee0006b89..cde0be60b9 100644
--- a/client/views/workflow-listing.js
+++ b/client/views/workflow-listing.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/workflow-results.js b/client/views/workflow-results.js
index adc075079f..b0a9d8a153 100644
--- a/client/views/workflow-results.js
+++ b/client/views/workflow-results.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/client/views/workflow-status.js b/client/views/workflow-status.js
index c4d0947c39..ee221168f5 100644
--- a/client/views/workflow-status.js
+++ b/client/views/workflow-status.js
@@ -1,6 +1,6 @@
/*
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/__init__.py b/stochss/handlers/__init__.py
index 426635b43e..ce3865a3a9 100644
--- a/stochss/handlers/__init__.py
+++ b/stochss/handlers/__init__.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -75,6 +75,7 @@ def get_page_handlers(route_start):
(r"/stochss/api/model/to-sbml\/?", ModelToSBMLAPIHandler),
(r"/stochss/api/model/run\/?", RunModelAPIHandler),
(r"/stochss/api/model/exists\/?", ModelExistsAPIHandler),
+ (r"/stochss/api/model/new-bc\/?", CreateNewBoundCondAPIHandler),
(r"/stochss/api/spatial-model/domain-list\/?", LoadExternalDomains),
(r"/stochss/api/spatial-model/types-list\/?", LoadParticleTypesDescriptions),
(r"/stochss/api/spatial-model/domain-plot\/?", LoadDomainAPIHandler),
diff --git a/stochss/handlers/file_browser.py b/stochss/handlers/file_browser.py
index 50fbbb523f..2afb26ca41 100644
--- a/stochss/handlers/file_browser.py
+++ b/stochss/handlers/file_browser.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/log.py b/stochss/handlers/log.py
index 550e2473be..9d6d78bcd8 100644
--- a/stochss/handlers/log.py
+++ b/stochss/handlers/log.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py
index b4a4a62755..04c210ad94 100644
--- a/stochss/handlers/models.py
+++ b/stochss/handlers/models.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -209,14 +209,14 @@ async def get(self):
if outfile == 'none':
outfile = str(uuid.uuid4()).replace("-", "_")
log.debug("Temporary outfile: %s", outfile)
- species = self.get_query_argument(name="species", default=None)
+ target = self.get_query_argument(name="target", default=None)
resp = {"Running":False, "Outfile":outfile, "Results":""}
if run_cmd == "start":
exec_cmd = ['/stochss/stochss/handlers/util/scripts/run_preview.py',
f'{path}', f'{outfile}']
- if species is not None:
- exec_cmd.insert(1, "--species")
- exec_cmd.insert(2, f"{species}")
+ if target is not None:
+ exec_cmd.insert(1, "--target")
+ exec_cmd.insert(2, f"{target}")
log.debug("Script commands for running a preview: %s", exec_cmd)
subprocess.Popen(exec_cmd)
resp['Running'] = True
@@ -406,3 +406,34 @@ async def get(self):
except StochSSAPIError as err:
report_error(self, log, err)
self.finish()
+
+
+class CreateNewBoundCondAPIHandler(APIHandler):
+ '''
+ ################################################################################################
+ Handler creating new boundary conditions.
+ ################################################################################################
+ '''
+ @web.authenticated
+ async def post(self):
+ '''
+ Creates a new restricted boundary condition.
+
+ Attributes
+ ----------
+ '''
+ self.set_header('Content-Type', 'application/json')
+ data = json.loads(self.request.body.decode())
+ path = data['model_path']
+ kwargs = data['kwargs']
+ log.debug("Args passed to the boundary condition constructor: %s", kwargs)
+ try:
+ log.info("Creating the new boundary condition")
+ model = StochSSSpatialModel(path=path)
+ resp = model.create_boundary_condition(kwargs)
+ log.info("Successfully created the new boundary condition")
+ log.debug("Response Message: %s", resp)
+ self.write(resp)
+ except StochSSAPIError as err:
+ report_error(self, log, err)
+ self.finish()
diff --git a/stochss/handlers/pages.py b/stochss/handlers/pages.py
index 23cece06b1..e2961bb4fa 100644
--- a/stochss/handlers/pages.py
+++ b/stochss/handlers/pages.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py
index b0b727364a..fe1e95f962 100644
--- a/stochss/handlers/project.py
+++ b/stochss/handlers/project.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/__init__.py b/stochss/handlers/util/__init__.py
index eda8912745..d7351abbfc 100644
--- a/stochss/handlers/util/__init__.py
+++ b/stochss/handlers/util/__init__.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/ensemble_simulation.py b/stochss/handlers/util/ensemble_simulation.py
index 2b220e21fb..d2697e06db 100644
--- a/stochss/handlers/util/ensemble_simulation.py
+++ b/stochss/handlers/util/ensemble_simulation.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/parameter_scan.py b/stochss/handlers/util/parameter_scan.py
index be84dd7ef4..67e72e85a6 100644
--- a/stochss/handlers/util/parameter_scan.py
+++ b/stochss/handlers/util/parameter_scan.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/parameter_sweep.py b/stochss/handlers/util/parameter_sweep.py
index d1a4a909c2..43251bfabd 100644
--- a/stochss/handlers/util/parameter_sweep.py
+++ b/stochss/handlers/util/parameter_sweep.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/parameter_sweep_1d.py b/stochss/handlers/util/parameter_sweep_1d.py
index 33c580e115..e1744532a8 100644
--- a/stochss/handlers/util/parameter_sweep_1d.py
+++ b/stochss/handlers/util/parameter_sweep_1d.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/parameter_sweep_2d.py b/stochss/handlers/util/parameter_sweep_2d.py
index 0c909181de..b9718cc710 100644
--- a/stochss/handlers/util/parameter_sweep_2d.py
+++ b/stochss/handlers/util/parameter_sweep_2d.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/scripts/run_preview.py b/stochss/handlers/util/scripts/run_preview.py
index 013f2b3d91..97c07c6253 100755
--- a/stochss/handlers/util/scripts/run_preview.py
+++ b/stochss/handlers/util/scripts/run_preview.py
@@ -2,7 +2,7 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -75,7 +75,7 @@ def get_parsed_args():
parser = argparse.ArgumentParser(description=description)
parser.add_argument('path', help="The path from the user directory to the model.")
parser.add_argument('outfile', help="The temp file used to hold the results.")
- parser.add_argument('--species', help="Spatial species to preview.", default=None)
+ parser.add_argument('--target', help="Spatial species or property to preview.", default=None)
return parser.parse_args()
@@ -107,7 +107,7 @@ def run_preview(job):
is_spatial = args.path.endswith(".smdl")
if is_spatial:
model = StochSSSpatialModel(path=args.path)
- wkfl = SpatialSimulation(path="", preview=True, species=args.species)
+ wkfl = SpatialSimulation(path="", preview=True, target=args.target)
wkfl.s_py_model = model.convert_to_spatialpy()
wkfl.s_model = model.model
else:
diff --git a/stochss/handlers/util/scripts/start_job.py b/stochss/handlers/util/scripts/start_job.py
index fa880431a8..50996c50a7 100755
--- a/stochss/handlers/util/scripts/start_job.py
+++ b/stochss/handlers/util/scripts/start_job.py
@@ -2,7 +2,7 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/scripts/upload_remote_file.py b/stochss/handlers/util/scripts/upload_remote_file.py
index 5db60cc1b8..e92073cdd7 100755
--- a/stochss/handlers/util/scripts/upload_remote_file.py
+++ b/stochss/handlers/util/scripts/upload_remote_file.py
@@ -2,7 +2,7 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/spatial_simulation.py b/stochss/handlers/util/spatial_simulation.py
index c2fd231b00..3741e1dbf5 100644
--- a/stochss/handlers/util/spatial_simulation.py
+++ b/stochss/handlers/util/spatial_simulation.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ class SpatialSimulation(StochSSJob):
TYPE = "spatial"
- def __init__(self, path, preview=False, species=None):
+ def __init__(self, path, preview=False, target=None):
'''
Intitialize a spatial ensemble simulation job object
@@ -38,13 +38,17 @@ def __init__(self, path, preview=False, species=None):
----------
path : str
Path to the spatial ensemble simulation job
+ preview : bool
+ Indicates whether or not the simulation is a preview.
+ target : string
+ Results data target used for ploting
'''
super().__init__(path=path)
if not preview:
self.settings = self.load_settings()
self.s_py_model, self.s_model = self.load_models()
else:
- self.species = species
+ self.target = target
def __get_run_settings(self):
@@ -67,14 +71,20 @@ def run(self, preview=False, verbose=False):
if verbose:
self.log("info", "Running a preview spatial ensemble simulation")
results = self.s_py_model.run(timeout=60)
- # if self.species is None:
- # self.species = list(self.s_py_model.get_all_species().keys())[0]
+ properties = ["type", "rho", "mass", "nu"]
t_ndx_list = list(range(len(os.listdir(results.result_dir)) - 1))
- plot = results.plot_species(species=self.species, t_ndx_list=t_ndx_list, animated=True,
- concentration=self.s_model['defaultMode'] == "continuous",
- deterministic=self.s_model['defaultMode'] == "discrete",
- width=None, height=None, return_plotly_figure=True,
- f_duration=100, t_duration=100)
+ kwargs = {"t_ndx_list": t_ndx_list, "animated": True, "width": None, "height": None,
+ "return_plotly_figure": True, "f_duration": 100, "t_duration": 100}
+ if self.target in properties or self.target.startswith("v["):
+ if self.target.startswith("v["):
+ kwargs['p_ndx'] = int(self.target[2])
+ self.target = "v"
+ plot = results.plot_property(property_name=self.target, **kwargs)
+ else:
+ concentration = self.s_model['defaultMode'] == "continuous"
+ deterministic = self.s_model['defaultMode'] == "discrete"
+ plot = results.plot_species(species=self.target, concentration=concentration,
+ deterministic=deterministic, **kwargs)
plot["layout"]["autosize"] = True
plot["config"] = {"responsive": True, "displayModeBar": True}
return plot
diff --git a/stochss/handlers/util/stochss_base.py b/stochss/handlers/util/stochss_base.py
index c17075e87f..43a5b73ea8 100644
--- a/stochss/handlers/util/stochss_base.py
+++ b/stochss/handlers/util/stochss_base.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -87,7 +87,8 @@ def check_workflow_format(cls, path):
return True
- def get_new_path(self, dst_path):
+ @classmethod
+ def get_new_path(cls, dst_path):
'''
Gets the proper destination path for the file object to be moved
@@ -96,9 +97,9 @@ def get_new_path(self, dst_path):
dst_path : string
New path for the file object from the users home directory
'''
- new_path = os.path.join(self.user_dir, dst_path)
- if dst_path.startswith("trash/") and not "trash" in os.listdir(self.user_dir):
- os.mkdir(os.path.join(self.user_dir, "trash"))
+ new_path = os.path.join(cls.user_dir, dst_path)
+ if dst_path.startswith("trash/") and not "trash" in os.listdir(cls.user_dir):
+ os.mkdir(os.path.join(cls.user_dir, "trash"))
if new_path.split().pop().replace('.', '', 5).isdigit():
return new_path.replace(new_path.split().pop(), "").strip()
if "trash/" in new_path and os.path.exists(new_path):
@@ -292,14 +293,16 @@ def get_unique_copy_path(self, path=None):
# Check if the file object is an original or at least the second copy
if not '-copy' in file or '-copy(' in file:
cp_file = ''.join([name, '-copy', ext])
- if cp_file not in os.listdir(dirname if dirname else self.user_dir):
+ if cp_file not in os.listdir(os.path.join(self.user_dir, dirname) \
+ if dirname else self.user_dir):
return os.path.join(dirname, cp_file)
i = 2
cp_file = ''.join([name, f"-copy({i})", ext])
# Check if a copy exists with '-copy(2)' in the name
# If copy_file is still not unique iterate i until a unique name is found
- while cp_file in os.listdir(dirname if dirname else self.user_dir):
+ while cp_file in os.listdir(os.path.join(self.user_dir, dirname) \
+ if dirname else self.user_dir):
i += 1
cp_file = ''.join([name, f"-copy({i})", ext])
diff --git a/stochss/handlers/util/stochss_errors.py b/stochss/handlers/util/stochss_errors.py
index 3ee1cbd411..076916205c 100644
--- a/stochss/handlers/util/stochss_errors.py
+++ b/stochss/handlers/util/stochss_errors.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_file.py b/stochss/handlers/util/stochss_file.py
index fbe99c91d3..2c621494fc 100644
--- a/stochss/handlers/util/stochss_file.py
+++ b/stochss/handlers/util/stochss_file.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py
index d9dbc44d4c..70a7a20bb9 100644
--- a/stochss/handlers/util/stochss_folder.py
+++ b/stochss/handlers/util/stochss_folder.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_job.py b/stochss/handlers/util/stochss_job.py
index 612c513b62..b9beeaa818 100644
--- a/stochss/handlers/util/stochss_job.py
+++ b/stochss/handlers/util/stochss_job.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_model.py b/stochss/handlers/util/stochss_model.py
index bb2b9ba9d9..3d0dbaecbe 100644
--- a/stochss/handlers/util/stochss_model.py
+++ b/stochss/handlers/util/stochss_model.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -380,6 +380,8 @@ def convert_to_spatial(self):
if self.model is None:
model = self.load()
model['is_spatial'] = True
+ if "timestepSize" not in self.model['modelSettings'].keys():
+ self.model['modelSettings']['timestepSize'] = 1e-5
if "domain" not in model.keys():
model['domain'] = self.get_model_template()['domain']
for species in model['species']:
diff --git a/stochss/handlers/util/stochss_notebook.py b/stochss/handlers/util/stochss_notebook.py
index baaadd017b..ee84eaf346 100644
--- a/stochss/handlers/util/stochss_notebook.py
+++ b/stochss/handlers/util/stochss_notebook.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -72,6 +72,34 @@ def __init__(self, path, new=False, models=None, settings=None):
if changed:
self.path = n_path.replace(self.user_dir + '/', "")
+ def __create_boundary_condition_cells(self):
+ pad = " "
+ bc_cells = []
+ try:
+ for boundary_condition in self.s_model['boundaryConditions']:
+ bc_cell = [f'class {boundary_condition["name"]}(BoundaryCondition):',
+ f'{pad}def expression(self):',
+ f'{pad*2}return """{boundary_condition["expression"]}"""']
+ bc_cells.append(nbf.new_code_cell("\n".join(bc_cell)))
+ return bc_cells
+ except KeyError as err:
+ message = "Boundary conditions are not properly formatted or "
+ message += f"are referenced incorrectly for notebooks: {str(err)}"
+ raise StochSSModelFormatError(message, traceback.format_exc()) from err
+
+ def __create_boundary_condition_string(self, model, pad):
+ if self.s_model['boundaryConditions']:
+ bound_conds = ["", f"{pad}# Boundary Conditions"]
+ try:
+ for bound_cond in self.s_model['boundaryConditions']:
+ bc_str = f"{pad}self.add_boundary_condition({bound_cond['name']}())"
+ bound_conds.append(bc_str)
+ model.extend(bound_conds)
+ except KeyError as err:
+ message = "Boundary conditions are not properly formatted or "
+ message += f"are referenced incorrectly for notebooks: {str(err)}"
+ raise StochSSModelFormatError(message, traceback.format_exc()) from err
+
def __create_common_cells(self, interactive_backend=False):
cells = [self.__create_import_cell(interactive_backend=interactive_backend),
nbf.new_markdown_cell(f"# {self.get_name()}"),
@@ -137,7 +165,7 @@ def __create_event_strings(self, model, pad):
pad=pad)
a_names = self.__create_event_assignment_strings(assignments=assignments,
event=event, pad=pad)
- delay = f"{event['delay']}" if event['delay'] else None
+ delay = f'"{event["delay"]}"' if event['delay'] else None
ev_str = f'{pad}self.add_event(Event(name="{event["name"]}", '
ev_str += f'trigger={t_name}, assignments=[{a_names}], '
ev_str += f'delay={delay}, priority="{event["priority"]}", '
@@ -261,6 +289,7 @@ def __create_model_cell(self):
" def __init__(self):",
f'{pad}Model.__init__(self, name="{self.get_name()}")']
self.__create_mesh_string(model=model, pad=pad)
+ self.__create_boundary_condition_string(model=model, pad=pad)
self.__create_species_strings(model=model, pad=pad)
self.__create_initial_condition_strings(model=model, pad=pad)
self.__create_parameter_strings(model=model, pad=pad)
@@ -769,13 +798,14 @@ def __create_stoich_spec_string(self, stoich_species):
def __create_tspan_string(self, model, pad):
end = self.s_model['modelSettings']['endSim']
- step = self.s_model['modelSettings']['timeStep']
+ output_freq = self.s_model['modelSettings']['timeStep']
tspan = ["", f"{pad}# Timespan"]
- ts_str = f'{pad}self.timespan(np.arange(0, {end + step}, {step})'
if self.s_model['is_spatial']:
- ts_str += f", timestep_size={step})"
+ step_size = self.s_model['modelSettings']['timestepSize']
+ ts_str = f'{pad}self.timespan(np.arange(0, {end + step_size}, {output_freq})'
+ ts_str += f", timestep_size={step_size})"
else:
- ts_str += ")"
+ ts_str = f'{pad}self.timespan(np.arange(0, {end + output_freq}, {output_freq}))'
tspan.append(ts_str)
model.extend(tspan)
@@ -904,9 +934,16 @@ def create_ses_notebook(self):
self.nb_type = self.SPATIAL_SIMULATION
self.settings['solver'] = "Solver"
run_str = "kwargs = configure_simulation()\nresults = model.run(**kwargs)"
- species = self.s_model['species'][0]['name']
- plot_str = f"results.plot_species('{species}', animated=True, width=None, height=None)"
+ if self.s_model['species']:
+ species = self.s_model['species'][0]['name']
+ plot_str = f"results.plot_species('{species}', animated=True, width=None, height=None)"
+ else:
+ plot_str = f"results.plot_property('type', animated=True, width=None, height=None)"
cells = self.__create_common_cells()
+ if 'boundaryConditions' in self.s_model.keys():
+ bc_cells = self.__create_boundary_condition_cells()
+ for i, bc_cell in enumerate(bc_cells):
+ cells.insert(2 + i, bc_cell)
cells.extend([nbf.new_code_cell(run_str),
nbf.new_markdown_cell("# Visualization"),
nbf.new_code_cell(plot_str)])
diff --git a/stochss/handlers/util/stochss_project.py b/stochss/handlers/util/stochss_project.py
index 3b2c9327a4..215039b760 100644
--- a/stochss/handlers/util/stochss_project.py
+++ b/stochss/handlers/util/stochss_project.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_sbml.py b/stochss/handlers/util/stochss_sbml.py
index 7f3cf29486..4d4f334880 100644
--- a/stochss/handlers/util/stochss_sbml.py
+++ b/stochss/handlers/util/stochss_sbml.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/util/stochss_spatial_model.py b/stochss/handlers/util/stochss_spatial_model.py
index 1c930fed1e..60a9191783 100644
--- a/stochss/handlers/util/stochss_spatial_model.py
+++ b/stochss/handlers/util/stochss_spatial_model.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
import numpy
import plotly
-from spatialpy import Model, Species, Parameter, Reaction, Mesh, MeshError, \
+from spatialpy import Model, Species, Parameter, Reaction, Mesh, MeshError, BoundaryCondition, \
PlaceInitialCondition, UniformInitialCondition, ScatterInitialCondition
from .stochss_base import StochSSBase
@@ -69,6 +69,23 @@ def __init__(self, path, new=False, model=None):
self.model = None
+ @classmethod
+ def __build_boundary_condition(cls, boundary_condition):
+ class NewBC(BoundaryCondition): # pylint: disable=too-few-public-methods
+ '''
+ ########################################################################################
+ Custom SpatialPy Boundary Condition
+ ########################################################################################
+ '''
+ __class__ = f"__main__.{boundary_condition['name']}"
+ def expression(self): # pylint: disable=no-self-use
+ '''
+ Custom expression for boundary condition
+ '''
+ return boundary_condition['expression']
+ return NewBC()
+
+
@classmethod
def __build_stochss_domain(cls, s_domain, data=None):
particles = cls.__build_stochss_domain_particles(s_domain=s_domain, data=data)
@@ -121,6 +138,17 @@ def __build_stochss_domain_particles(cls, s_domain, data=None):
return particles
+ def __convert_boundary_conditions(self, model):
+ try:
+ for boundary_condition in self.model['boundaryConditions']:
+ s_bound_cond = self.__build_boundary_condition(boundary_condition)
+ model.add_boundary_condition(s_bound_cond)
+ except KeyError as err:
+ message = "Spatial model boundary conditions are not properly formatted or "
+ message += f"are referenced incorrectly: {str(err)}"
+ raise StochSSModelFormatError(message, traceback.format_exc()) from err
+
+
def __convert_domain(self, model):
try:
xlim = tuple(self.model['domain']['x_lim'])
@@ -161,7 +189,7 @@ def __convert_initial_conditions(self, model):
s_ic = UniformInitialCondition(species, count, types=types)
model.add_initial_condition(s_ic)
except KeyError as err:
- message = "Spatial model domain properties are not properly formatted or "
+ message = "Spatial model initial conditions are not properly formatted or "
message += f"are referenced incorrectly: {str(err)}"
raise StochSSModelFormatError(message, traceback.format_exc()) from err
@@ -169,8 +197,9 @@ def __convert_initial_conditions(self, model):
def __convert_model_settings(self, model):
try:
end = self.model['modelSettings']['endSim']
- step_size = self.model['modelSettings']['timeStep']
- tspan = numpy.arange(0, end + step_size, step_size)
+ output_freq = self.model['modelSettings']['timeStep']
+ step_size = self.model['modelSettings']['timestepSize']
+ tspan = numpy.arange(0, end + step_size, output_freq)
model.timespan(tspan, timestep_size=step_size)
except KeyError as err:
message = "Spatial model settings are not properly formatted or "
@@ -350,6 +379,8 @@ def convert_to_spatialpy(self):
s_model = Model(name=name)
self.__convert_model_settings(model=s_model)
self.__convert_domain(model=s_model)
+ if "boundaryConditions" in self.model.keys():
+ self.__convert_boundary_conditions(model=s_model)
self.__convert_species(model=s_model)
self.__convert_initial_conditions(model=s_model)
self.__convert_parameters(model=s_model)
@@ -358,6 +389,21 @@ def convert_to_spatialpy(self):
return s_model
+ def create_boundary_condition(self, kwargs):
+ '''
+ Create a new boundary condition using spatialpy.BoundaryCondition
+
+ Attributes
+ ----------
+ kwargs : dict
+ Arguments passed to the spatialpy.BoundaryCondition constructor
+ '''
+ model = self.convert_to_spatialpy()
+ new_bc = BoundaryCondition(model=model, **kwargs)
+ expression = new_bc.expression()
+ return {"expression": expression}
+
+
def get_domain(self, path=None, new=False):
'''
Get a prospective domain
@@ -525,10 +571,14 @@ def load(self):
self.model['name'] = self.get_name()
if not self.model['defaultMode']:
self.model['defaultMode'] = "discrete"
+ if "timestepSize" not in self.model['modelSettings'].keys():
+ self.model['modelSettings']['timestepSize'] = 1e-5
if "domain" not in self.model.keys() or len(self.model['domain'].keys()) < 6:
self.model['domain'] = self.get_model_template()['domain']
elif "static" not in self.model['domain'].keys():
self.model['domain']['static'] = True
+ if "boundaryConditions" not in self.model.keys():
+ self.model['boundaryConditions'] = []
for species in self.model['species']:
if "types" not in species.keys():
species['types'] = list(range(1, len(self.model['domain']['types'])))
diff --git a/stochss/handlers/util/stochss_workflow.py b/stochss/handlers/util/stochss_workflow.py
index c4646e5304..176c2a29e8 100644
--- a/stochss/handlers/util/stochss_workflow.py
+++ b/stochss/handlers/util/stochss_workflow.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/handlers/workflows.py b/stochss/handlers/workflows.py
index cb37ad715a..ae8bbc4c63 100644
--- a/stochss/handlers/workflows.py
+++ b/stochss/handlers/workflows.py
@@ -1,6 +1,6 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/stochss/tests/example_models.py b/stochss/tests/example_models.py
new file mode 100644
index 0000000000..17c415ac7c
--- /dev/null
+++ b/stochss/tests/example_models.py
@@ -0,0 +1,352 @@
+'''
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+'''
+
+import numpy as np
+
+from gillespy2.core import (
+ Model,
+ Species,
+ Reaction,
+ Parameter
+)
+
+# pylint: disable=line-too-long
+# pylint: disable=missing-class-docstring
+# pylint: disable=too-few-public-methods
+class Brusselator(Model):
+ def __init__(self):
+ Model.__init__(self, name="Brusselator")
+ self.volume = 1000
+
+ # Parameters
+ self.add_parameter(Parameter(name="rate1", expression="5000"))
+ self.add_parameter(Parameter(name="rate2", expression="50"))
+ self.add_parameter(Parameter(name="rate3", expression="5e-05"))
+ self.add_parameter(Parameter(name="rate4", expression="5"))
+
+ # Variables
+ self.add_species(Species(name="A", initial_value=100000, mode="discrete"))
+ self.add_species(Species(name="B", initial_value=100000, mode="discrete"))
+ self.add_species(Species(name="C", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="D", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="X", initial_value=2000, mode="discrete"))
+ self.add_species(Species(name="Y", initial_value=1000, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="reaction1", reactants={'A': 1}, products={'X': 1, 'A': 1}, propensity_function="rate1"))
+ self.add_reaction(Reaction(name="reaction2", reactants={'B': 1, 'X': 1}, products={'Y': 1, 'C': 1, 'B': 1}, propensity_function="rate2*X"))
+ self.add_reaction(Reaction(name="reaction3", reactants={'X': 2, 'Y': 1}, products={'X': 3}, propensity_function="rate3*Y*X*(X-1)/2"))
+ self.add_reaction(Reaction(name="reaction4", reactants={'X': 1}, products={'D': 1}, propensity_function="rate4*X"))
+
+ # Timespan
+ self.timespan(np.arange(0, 30, 0.01))
+
+
+class Degradation(Model):
+ def __init__(self):
+ Model.__init__(self, name="Degradation")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="decayrate", expression="0.05"))
+
+ # Variables
+ self.add_species(Species(name="protein", initial_value=50, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="reaction", reactants={'protein': 1}, products={}, rate=self.listOfParameters["decayrate"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 100, 1))
+
+
+class Dimerization(Model):
+ def __init__(self):
+ Model.__init__(self, name="Dimerization")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="k_c", expression="0.005"))
+ self.add_parameter(Parameter(name="k_d", expression="0.08"))
+
+ # Variables
+ self.add_species(Species(name="Monomer", initial_value=30, mode="discrete"))
+ self.add_species(Species(name="Dimer", initial_value=0, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="r_creation", reactants={'Monomer': 2}, products={'Dimer': 1}, rate=self.listOfParameters["k_c"]))
+ self.add_reaction(Reaction(name="r_dissociation", reactants={'Dimer': 1}, products={'Monomer': 2}, rate=self.listOfParameters["k_d"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 100, 1))
+
+
+class LotkavolterraOscillator(Model):
+ def __init__(self):
+ Model.__init__(self, name="Lotkavolterra_Oscillator")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="k1", expression="0.004"))
+ self.add_parameter(Parameter(name="k2", expression="0.5"))
+ self.add_parameter(Parameter(name="k3", expression="0.0045"))
+
+ # Variables
+ self.add_species(Species(name="R", initial_value=0.0095, mode="continuous"))
+ self.add_species(Species(name="W", initial_value=0.008, mode="continuous"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="r1", reactants={'R': 1}, products={'R': 2}, rate=self.listOfParameters["k1"]))
+ self.add_reaction(Reaction(name="r2", reactants={'R': 1, 'W': 1}, products={'W': 2}, rate=self.listOfParameters["k2"]))
+ self.add_reaction(Reaction(name="r3", reactants={'W': 1}, products={}, rate=self.listOfParameters["k3"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 9000, 1))
+
+
+class MichaelisMenten(Model):
+ def __init__(self):
+ Model.__init__(self, name="Michaelis_Menten")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="rate1", expression="0.0017"))
+ self.add_parameter(Parameter(name="rate2", expression="0.5"))
+ self.add_parameter(Parameter(name="rate3", expression="0.1"))
+
+ # Variables
+ self.add_species(Species(name="A", initial_value=301, mode="discrete"))
+ self.add_species(Species(name="B", initial_value=120, mode="discrete"))
+ self.add_species(Species(name="C", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="D", initial_value=0, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="r1", reactants={'A': 1, 'B': 1}, products={'C': 1}, rate=self.listOfParameters["rate1"]))
+ self.add_reaction(Reaction(name="r2", reactants={'C': 1}, products={'A': 1, 'B': 1}, rate=self.listOfParameters["rate2"]))
+ self.add_reaction(Reaction(name="r3", reactants={'C': 1}, products={'B': 1, 'D': 1}, rate=self.listOfParameters["rate3"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 100, 1))
+
+
+class Opioid(Model):
+ def __init__(self):
+ Model.__init__(self, name="Opioid")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="alpha", expression="0.15"))
+ self.add_parameter(Parameter(name="epsilon", expression="0.8"))
+ self.add_parameter(Parameter(name="beta_p", expression="0.00266"))
+ self.add_parameter(Parameter(name="beta_a", expression="0.00094"))
+ self.add_parameter(Parameter(name="gamma", expression="0.00744"))
+ self.add_parameter(Parameter(name="zeta", expression="0.2"))
+ self.add_parameter(Parameter(name="delta", expression="0.1"))
+ self.add_parameter(Parameter(name="sigma", expression="0.9"))
+ self.add_parameter(Parameter(name="mu", expression="0.00729"))
+ self.add_parameter(Parameter(name="mu_prime", expression="0.01159"))
+
+ # Variables
+ self.add_species(Species(name="Susceptible", initial_value=200, mode="discrete"))
+ self.add_species(Species(name="Prescribed_User", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Addicted", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Rehab", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Natural_Deaths", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Addicted_Deaths", initial_value=0, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="SP", reactants={'Susceptible': 1}, products={'Prescribed_User': 1}, rate=self.listOfParameters["alpha"]))
+ self.add_reaction(Reaction(name="SA_a", reactants={'Susceptible': 1}, products={'Addicted': 1}, rate=self.listOfParameters["beta_a"]))
+ self.add_reaction(Reaction(name="SA_p", reactants={'Susceptible': 1}, products={'Addicted': 1}, rate=self.listOfParameters["beta_p"]))
+ self.add_reaction(Reaction(name="PA", reactants={'Prescribed_User': 1}, products={'Addicted': 1}, rate=self.listOfParameters["gamma"]))
+ self.add_reaction(Reaction(name="PS", reactants={'Prescribed_User': 1}, products={'Susceptible': 1}, rate=self.listOfParameters["epsilon"]))
+ self.add_reaction(Reaction(name="AR", reactants={'Addicted': 1}, products={'Rehab': 1}, rate=self.listOfParameters["zeta"]))
+ self.add_reaction(Reaction(name="RA", reactants={'Rehab': 1}, products={'Addicted': 1}, rate=self.listOfParameters["delta"]))
+ self.add_reaction(Reaction(name="RS", reactants={'Rehab': 1}, products={'Susceptible': 1}, rate=self.listOfParameters["sigma"]))
+ self.add_reaction(Reaction(name="mu_S", reactants={'Susceptible': 1}, products={'Susceptible': 1, 'Natural_Deaths': 1}, rate=self.listOfParameters["mu"]))
+ self.add_reaction(Reaction(name="mu_P", reactants={'Prescribed_User': 1}, products={'Susceptible': 1, 'Natural_Deaths': 1}, rate=self.listOfParameters["mu"]))
+ self.add_reaction(Reaction(name="mu_R", reactants={'Rehab': 1}, products={'Susceptible': 1, 'Natural_Deaths': 1}, rate=self.listOfParameters["mu"]))
+ self.add_reaction(Reaction(name="mu_prime_A", reactants={'Addicted': 1}, products={'Susceptible': 1, 'Addicted_Deaths': 1}, rate=self.listOfParameters["mu_prime"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 200, 1))
+
+
+class Schlogl(Model):
+ def __init__(self):
+ Model.__init__(self, name="Schlogl")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="k1", expression="1"))
+ self.add_parameter(Parameter(name="k2", expression="1"))
+
+ # Variables
+ self.add_species(Species(name="s1", initial_value=300, mode="discrete"))
+ self.add_species(Species(name="s2", initial_value=300, mode="discrete"))
+ self.add_species(Species(name="s3", initial_value=300, mode="discrete"))
+ self.add_species(Species(name="s4", initial_value=300, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="r1", reactants={'s1': 1, 's4': 1}, products={'s4': 2}, rate=self.listOfParameters["k1"]))
+ self.add_reaction(Reaction(name="r2", reactants={'s2': 1, 's4': 1}, products={'s3': 1}, rate=self.listOfParameters["k2"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 100000, 1000))
+
+
+class ToggleSwitch(Model):
+ def __init__(self):
+ Model.__init__(self, name="Toggle_Switch")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="alpha1", expression="10"))
+ self.add_parameter(Parameter(name="alpha2", expression="10"))
+ self.add_parameter(Parameter(name="beta", expression="2"))
+ self.add_parameter(Parameter(name="gamma", expression="2"))
+ self.add_parameter(Parameter(name="mu", expression="1"))
+
+ # Variables
+ self.add_species(Species(name="A", initial_value=2, mode="discrete"))
+ self.add_species(Species(name="B", initial_value=2, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="cu", reactants={}, products={'A': 1}, propensity_function="alpha1/(1+pow(B, beta))"))
+ self.add_reaction(Reaction(name="cv", reactants={}, products={'B': 1}, propensity_function="alpha2/(1+pow(A, gamma))"))
+ self.add_reaction(Reaction(name="du", reactants={'A': 1}, products={}, rate=self.listOfParameters["mu"]))
+ self.add_reaction(Reaction(name="dv", reactants={'B': 1}, products={}, rate=self.listOfParameters["mu"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 250, 1))
+
+
+class VilarOscillator(Model):
+ def __init__(self):
+ Model.__init__(self, name="Vilar_Oscillator")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="alpha_a", expression="50"))
+ self.add_parameter(Parameter(name="alpha_a_prime", expression="500"))
+ self.add_parameter(Parameter(name="alpha_r", expression="0.01"))
+ self.add_parameter(Parameter(name="alpha_r_prime", expression="50"))
+ self.add_parameter(Parameter(name="beta_a", expression="50"))
+ self.add_parameter(Parameter(name="beta_r", expression="5"))
+ self.add_parameter(Parameter(name="delta_ma", expression="10"))
+ self.add_parameter(Parameter(name="delta_mr", expression="0.5"))
+ self.add_parameter(Parameter(name="delta_a", expression="1"))
+ self.add_parameter(Parameter(name="delta_r", expression="0.2"))
+ self.add_parameter(Parameter(name="gamma_a", expression="1"))
+ self.add_parameter(Parameter(name="gamma_r", expression="1"))
+ self.add_parameter(Parameter(name="gamma_c", expression="2"))
+ self.add_parameter(Parameter(name="theta_a", expression="50"))
+ self.add_parameter(Parameter(name="theta_r", expression="100"))
+
+ # Variables
+ self.add_species(Species(name="Da", initial_value=1, mode="discrete"))
+ self.add_species(Species(name="Da_prime", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Ma", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Dr", initial_value=1, mode="discrete"))
+ self.add_species(Species(name="Dr_prime", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="Mr", initial_value=0, mode="discrete"))
+ self.add_species(Species(name="C", initial_value=10, mode="discrete"))
+ self.add_species(Species(name="A", initial_value=10, mode="discrete"))
+ self.add_species(Species(name="R", initial_value=10, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="r1", reactants={'Da_prime': 1}, products={'Da': 1}, rate=self.listOfParameters["theta_a"]))
+ self.add_reaction(Reaction(name="r2", reactants={'Da': 1, 'A': 1}, products={'Da_prime': 1}, rate=self.listOfParameters["gamma_a"]))
+ self.add_reaction(Reaction(name="r3", reactants={'Dr_prime': 1}, products={'Dr': 1}, rate=self.listOfParameters["theta_r"]))
+ self.add_reaction(Reaction(name="r4", reactants={'Dr': 1, 'A': 1}, products={'Dr_prime': 1}, rate=self.listOfParameters["gamma_r"]))
+ self.add_reaction(Reaction(name="r5", reactants={'Da_prime': 1}, products={'Da_prime': 1, 'Ma': 1}, rate=self.listOfParameters["alpha_a_prime"]))
+ self.add_reaction(Reaction(name="r6", reactants={'Da': 1}, products={'Da': 1, 'Ma': 1}, rate=self.listOfParameters["alpha_a"]))
+ self.add_reaction(Reaction(name="r7", reactants={'Ma': 1}, products={}, rate=self.listOfParameters["delta_ma"]))
+ self.add_reaction(Reaction(name="r8", reactants={'Ma': 1}, products={'A': 1, 'Ma': 1}, rate=self.listOfParameters["beta_a"]))
+ self.add_reaction(Reaction(name="r9", reactants={'Da_prime': 1}, products={'Da_prime': 1, 'A': 1}, rate=self.listOfParameters["theta_a"]))
+ self.add_reaction(Reaction(name="r10", reactants={'Dr_prime': 1}, products={'Dr_prime': 1, 'A': 1}, rate=self.listOfParameters["theta_a"]))
+ self.add_reaction(Reaction(name="r11", reactants={'A': 1}, products={}, rate=self.listOfParameters["gamma_c"]))
+ self.add_reaction(Reaction(name="r12", reactants={'A': 1, 'R': 1}, products={'C': 1}, rate=self.listOfParameters["gamma_c"]))
+ self.add_reaction(Reaction(name="r13", reactants={'Dr_prime': 1}, products={'Dr_prime': 1, 'Mr': 1}, rate=self.listOfParameters["alpha_r_prime"]))
+ self.add_reaction(Reaction(name="r14", reactants={'Dr': 1}, products={'Dr': 1, 'Mr': 1}, rate=self.listOfParameters["alpha_r"]))
+ self.add_reaction(Reaction(name="r15", reactants={'Mr': 1}, products={}, rate=self.listOfParameters["delta_mr"]))
+ self.add_reaction(Reaction(name="r16", reactants={'Mr': 1}, products={'Mr': 1, 'R': 1}, rate=self.listOfParameters["beta_r"]))
+ self.add_reaction(Reaction(name="r17", reactants={'R': 1}, products={}, rate=self.listOfParameters["delta_r"]))
+ self.add_reaction(Reaction(name="r18", reactants={'C': 1}, products={'R': 1}, rate=self.listOfParameters["delta_a"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 200, 1))
+
+
+class Oregonator(Model):
+ def __init__(self):
+ Model.__init__(self, name="Oregonator")
+ self.volume = 1
+
+ # Parameters
+ self.add_parameter(Parameter(name="k1", expression="2"))
+ self.add_parameter(Parameter(name="k2", expression="0.1"))
+ self.add_parameter(Parameter(name="k3", expression="104"))
+ self.add_parameter(Parameter(name="k4", expression="4e-07"))
+ self.add_parameter(Parameter(name="k5", expression="26"))
+
+ # Variables
+ self.add_species(Species(name="F", initial_value=2, mode="continuous"))
+ self.add_species(Species(name="A", initial_value=250, mode="continuous"))
+ self.add_species(Species(name="B", initial_value=500, mode="continuous"))
+ self.add_species(Species(name="C", initial_value=1000, mode="continuous"))
+ self.add_species(Species(name="P", initial_value=0, mode="continuous"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="reaction1", reactants={'B': 1, 'F': 1}, products={'A': 1, 'F': 1}, rate=self.listOfParameters["k1"]))
+ self.add_reaction(Reaction(name="reaction2", reactants={'A': 1, 'B': 1}, products={'P': 1}, rate=self.listOfParameters["k2"]))
+ self.add_reaction(Reaction(name="reaction3", reactants={'A': 1, 'F': 1}, products={'A': 2, 'C': 1, 'F': 1}, rate=self.listOfParameters["k3"]))
+ self.add_reaction(Reaction(name="reaction4", reactants={'A': 2}, products={'P': 1}, rate=self.listOfParameters["k4"]))
+ self.add_reaction(Reaction(name="reaction5", reactants={'C': 1, 'F': 1}, products={'B': 1, 'F': 1}, rate=self.listOfParameters["k5"]))
+
+ # Timespan
+ self.timespan(np.arange(0, 5, 0.1))
+
+
+class TysonOscillator(Model):
+ def __init__(self):
+ Model.__init__(self, name="Tyson_Oscillator")
+ self.volume = 300
+
+ # Parameters
+ self.add_parameter(Parameter(name="P", expression="2"))
+ self.add_parameter(Parameter(name="kt", expression="20"))
+ self.add_parameter(Parameter(name="kd", expression="1"))
+ self.add_parameter(Parameter(name="a0", expression="0.005"))
+ self.add_parameter(Parameter(name="a1", expression="0.05"))
+ self.add_parameter(Parameter(name="a2", expression="0.1"))
+ self.add_parameter(Parameter(name="kdx", expression="1"))
+
+ # Variables
+ self.add_species(Species(name="X", initial_value=197, mode="discrete"))
+ self.add_species(Species(name="Y", initial_value=255, mode="discrete"))
+
+ # Reactions
+ self.add_reaction(Reaction(name="rxn1", reactants={}, products={'X': 1}, propensity_function="vol*1/(1+(Y*Y/((vol*vol))))"))
+ self.add_reaction(Reaction(name="rxn2", reactants={'X': 1}, products={}, rate=self.listOfParameters["kdx"]))
+ self.add_reaction(Reaction(name="rxn3", reactants={'X': 1}, products={'X': 1, 'Y': 1}, rate=self.listOfParameters["kt"]))
+ self.add_reaction(Reaction(name="rxn4", reactants={'Y': 1}, products={}, rate=self.listOfParameters["kd"]))
+ self.add_reaction(Reaction(name="rxn5", reactants={'Y': 1}, products={}, propensity_function="Y/(a0 + a1*(Y/vol)+a2*Y*Y/(vol*vol))"))
+
+ # Timespan
+ self.timespan(np.arange(0, 100, 1))
diff --git a/stochss/tests/mock_file_sys/sbml_files/test1.sbml b/stochss/tests/mock_file_sys/sbml_files/test1.sbml
deleted file mode 100644
index edd42e3c79..0000000000
--- a/stochss/tests/mock_file_sys/sbml_files/test1.sbml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/stochss/tests/mock_file_sys/sbml_files/test2.sbml b/stochss/tests/mock_file_sys/sbml_files/test2.sbml
deleted file mode 100644
index a87bc5eb1c..0000000000
--- a/stochss/tests/mock_file_sys/sbml_files/test2.sbml
+++ /dev/null
@@ -1 +0,0 @@
-{"is_spatial":false,"defaultID":10,"defaultMode":"discrete","modelSettings":{"endSim":20,"timeStep":0.05,"volume":1,"algorithm":"Hybrid-Tau-Leaping","realizations":1},"simulationSettings":{"isAutomatic":true,"relativeTol":0.001,"absoluteTol":0.000001,"realizations":1,"algorithm":"SSA","seed":-1,"tauTol":0.03},"parameterSweepSettings":{"is1D":true,"p1Min":0,"p1Max":0,"p1Steps":11,"p2Min":0,"p2Max":0,"p2Steps":11,"parameterOne":{},"parameterTwo":{},"speciesOfInterest":{"subdomains":[]}},"meshSettings":{"count":2},"species":[{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}],"initialConditions":[],"parameters":[{"compID":2,"name":"k1","expression":"0.5","annotation":""},{"compID":3,"name":"k2","expression":"0.1*500**-5","annotation":""}],"reactions":[{"compID":4,"name":"r1","reactionType":"creation","summary":"\\emptyset \\rightarrow s1","massaction":false,"propensity":"","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{"compID":3,"name":"k2","expression":"math.sin(1)","annotation":""},"reactants":[],"products":[{"ratio":1,"specie":{"compID":1,"name":"s1","value":500,"mode":"continuous","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]},{"compID":5,"name":"r2","reactionType":"destruction","summary":"s1 \\rightarrow \\emptyset","massaction":false,"propensity":"","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{"compID":2,"name":"k1","expression":"0.5","annotation":""},"reactants":[{"ratio":1,"specie":{"compID":1,"name":"s1","value":500,"mode":"continuous","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}],"products":[]},{"compID":6,"name":"r3","reactionType":"custom-propensity","summary":"2s1 \\rightarrow 3s1","massaction":false,"propensity":"sin(1)","annotation":"","subdomains":["subdomain 1:","subdomain 2:"],"rate":{},"reactants":[{"ratio":2,"specie":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}],"products":[{"ratio":3,"specie":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]}],"rules":[{"compID":8,"name":"rr1","type":"Rate Rule","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]},"expression":"sin(0.5)","annotation":""},{"compID":9,"name":"rr2","type":"Assignment Rule","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]},"expression":"8000","annotation":""}],"eventsCollection":[{"compID":7,"name":"e1","annotation":"","delay":"t-40","priority":"1","triggerExpression":"t>50","initialValue":true,"persistent":true,"useValuesFromTriggerTime":true,"eventAssignments":[{"expression":"2000","variable":{"compID":1,"name":"s1","value":500,"mode":"discrete","switchTol":0.03,"switchMin":100,"isSwitchTol":true,"annotation":"","diffusionCoeff":0,"subdomains":["subdomain 1:","subdomain 2:"]}}]}],"functionDefinitions":[]}
\ No newline at end of file
diff --git a/stochss/tests/run_tests.py b/stochss/tests/run_tests.py
index 5aa6cce0f0..896b1a3be4 100755
--- a/stochss/tests/run_tests.py
+++ b/stochss/tests/run_tests.py
@@ -2,7 +2,7 @@
'''
StochSS is a platform for simulating biochemical systems
-Copyright (C) 2019-2020 StochSS developers.
+Copyright (C) 2019-2021 StochSS developers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,31 +34,21 @@
args = parser.parse_args()
print(os.path.dirname(__file__))
- # import test_model_template
- # import test_settings_template
- # import test_convert_sbml
- # import test_upload_file
- # import test_rename
- # import test_generate_zip_file
- # import test_workflow_status
- # import test_ls
- # import test_duplicate
+ import test_model_template
+ import test_settings_template
+ import test_stochss_base
+ import test_gillespy2
modules = [
- # test_model_template,
- # test_settings_template,
- # test_convert_sbml,
- # test_rename,
- # test_upload_file,
- # test_generate_zip_file,
- # test_workflow_status,
- # test_ls,
- # test_duplicate
+ test_model_template,
+ test_settings_template,
+ test_gillespy2,
+ test_stochss_base
]
for module in modules:
suite = unittest.TestLoader().loadTestsFromModule(module)
- runner = unittest.TextTestRunner(failfast=args.mode == 'staging')
+ runner = unittest.TextTestRunner(failfast=args.mode == 'staging', verbosity=1)
print("Executing: {}".format(module))
result = runner.run(suite)
diff --git a/stochss/tests/test_convert_sbml.py b/stochss/tests/test_convert_sbml.py
deleted file mode 100644
index 1c5f940eda..0000000000
--- a/stochss/tests/test_convert_sbml.py
+++ /dev/null
@@ -1,205 +0,0 @@
-import unittest, sys, os, inspect
-import tempfile
-from gillespy2 import Model
-from gillespy2.solvers.numpy.basic_ode_solver import BasicODESolver
-
-currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
-parentdir = os.path.dirname(currentdir)
-sys.path.insert(0,parentdir)
-
-from handlers.util.convert_sbml_to_model import *
-from handlers.util.stochss_errors import StochSSAPIError, StochSSFileNotFoundError
-
-class TestConvertSBMLToModel(unittest.TestCase):
-
- def test_sbml_to_gillespy_success_with_stochss_model(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
- self.assertIsInstance(gillespy2_model, Model)
- self.assertIsInstance(errors, list)
-
-
- def test_sbml_to_gillespy_convert_error(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test2.sbml"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
- self.assertIsNone(gillespy2_model)
- self.assertIsInstance(errors, list)
-
-
- def test_sbml_to_gillespy_file_not_found_error(self):
- expected = StochSSFileNotFoundError("")
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test3.sbml"
-
- try:
- resp = convert_to_gillespy_model(sbml_file)
- self.assertNotIsInstance(resp, tuple)
- except StochSSAPIError as err:
- self.assertIsInstance(err, StochSSFileNotFoundError)
- self.assertEqual(err.status_code, expected.status_code)
- self.assertEqual(err.reason, expected.reason)
-
-
- def test_build_stochss_species_from_gillespy_species(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/specie.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- species_keys = sorted(list(get_species(gillespy2_model.listOfSpecies, 1)[0][0].keys()))
- self.assertEqual(species_keys, model_keys)
-
-
- def test_build_stochss_parameter_from_gillespy_parameter(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/parameter.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- parameter_keys = sorted(list(get_parameters(gillespy2_model.listOfParameters, 1)[0][0].keys()))
- self.assertEqual(parameter_keys, model_keys)
-
-
- def test_build_stochss_reaction_from_gillespy_reaction(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/reaction.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- collections = data.split("collections: {").pop().split('}')[0].split(',')
- children = data.split("children: {").pop().split('}')[0].split(',')
- model_keys = list(map(lambda item: item.strip().split(':')[0], props))
- model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections)))
- model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children)))
- model_keys.sort()
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- reaction_keys = sorted(list(get_reactions(gillespy2_model.listOfReactions, species, 1)[0][0].keys()))
- self.assertEqual(reaction_keys, model_keys)
-
-
- def test_build_stochss_reactant_from_gillespy_reactant(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/stoich-specie.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- children = data.split("children: {").pop().split('}')[0].split(',')
- model_keys = list(map(lambda item: item.strip().split(':')[0], props))
- model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children)))
- model_keys.sort()
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- reactant_keys = sorted(list(get_reactants(list(gillespy2_model.listOfReactions.popitem(last=False)).pop().reactants, species)[0].keys()))
- self.assertEqual(reactant_keys, model_keys)
-
-
- def test_build_stochss_product_from_gillespy_product(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/stoich-specie.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- children = data.split("children: {").pop().split('}')[0].split(',')
- model_keys = list(map(lambda item: item.strip().split(':')[0], props))
- model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children)))
- model_keys.sort()
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- product_keys = sorted(list(get_products(list(gillespy2_model.listOfReactions.popitem(last=False)).pop().products, species)[0].keys()))
- self.assertEqual(product_keys, model_keys)
-
-
- def test_build_stochss_event_from_gillespy_event(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/event.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- collections = data.split("collections: {").pop().split('}')[0].split(',')
- model_keys = list(map(lambda item: item.strip().split(':')[0], props))
- model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections)))
- model_keys.sort()
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0]
- event_keys = sorted(list(get_events(gillespy2_model.listOfEvents, species, parameters, 1)[0][0].keys()))
- self.assertEqual(event_keys, model_keys)
-
-
- def test_build_stochss_event_assignment_from_gillespy_event_assignment(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/event-assignment.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0]
- assignment_keys = sorted(list(get_event_assignment(list(gillespy2_model.listOfEvents.popitem(last=False)).pop().assignments, species, parameters)[0].keys()))
- self.assertEqual(assignment_keys, model_keys)
-
-
- def test_build_stochss_rate_rule_from_gillespy_rate_rule(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/rule.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0]
- rate_rule_keys = sorted(list(get_rate_rules(gillespy2_model.listOfRateRules, species, parameters, 1)[0][0].keys()))
- self.assertEqual(rate_rule_keys, model_keys)
-
-
- def test_build_stochss_assignment_rule_from_gillespy_assignment_rule(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/rule.js"
- gillespy2_model, errors = convert_to_gillespy_model(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- species = get_species(gillespy2_model.listOfSpecies, 1)[0]
- parameters = get_parameters(gillespy2_model.listOfParameters, 1)[0]
- assignment_rule_keys = sorted(list(get_assignment_rules(gillespy2_model.listOfAssignmentRules, species, parameters, 1)[0][0].keys()))
- self.assertEqual(assignment_rule_keys, model_keys)
-
-
- def test_build_stochss_function_definition_from_sbml_function_definition(self):
- sbml_file = "stochss/tests/mock_file_sys/sbml_files/test1.sbml"
- model_path = "client/models/function-definition.js"
- function_definitions = get_sbml_function_definitions(sbml_file)
-
- with open(model_path, "r") as model_file:
- data = model_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
- model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], props)))
-
- function_definition_keys = sorted(list(get_function_definitions(function_definitions, 1)[0][0].keys()))
- self.assertEqual(function_definition_keys, model_keys)
-
diff --git a/stochss/tests/test_duplicate.py b/stochss/tests/test_duplicate.py
deleted file mode 100644
index 80449c7cfa..0000000000
--- a/stochss/tests/test_duplicate.py
+++ /dev/null
@@ -1,325 +0,0 @@
-import unittest, os, tempfile
-from pathlib import Path
-from handlers.util.duplicate import *
-
-class TestDuplicate(unittest.TestCase):
-
- #unit tests for method get_unique_file_name
-
- def test_get_unique_file_name_notcopy_noext(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "test_file"
- test_filepath = os.path.join(tempdir, test_filename)
- assert get_unique_file_name(test_filepath) == os.path.join(tempdir,"test_file-copy")
-
- def test_get_unique_file_name_iscopy_noext(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "test_file-copy"
- test_filepath = os.path.join(tempdir, test_filename)
- assert get_unique_file_name(test_filepath) == os.path.join(tempdir, 'test_file-copy(2)')
-
- def test_get_unique_file_name_notcopy_hasext(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "test_file.sample"
- test_filepath = os.path.join(tempdir, test_filename)
- assert get_unique_file_name(test_filepath) == os.path.join(tempdir, 'test_file-copy.sample')
-
- def test_get_unique_file_name_iscopy_hasext(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "test_file-copy.sample"
- test_filepath = os.path.join(tempdir, test_filename)
- assert get_unique_file_name(test_filepath) == os.path.join(tempdir,"test_file-copy(2).sample")
-
- def test_get_unique_file_name_multiple_copies(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "test_file"
- test_filepath = os.path.join(tempdir, test_filename)
- for i in range(2):
- test_filepath = get_unique_file_name(test_filepath)
- assert test_filepath == os.path.join(tempdir,"test_file-copy(2)")
-
- #unit tests for method duplicate
-
- def test_duplicate_file_not_found_raise_error(self):
- from handlers.util.stochss_errors import StochSSFileNotFoundError
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"nonexistent_file")
- with self.assertRaises(StochSSFileNotFoundError):
- duplicate(test_filepath)
-
- def test_duplicate_file_not_found_no_new_file(self):
- from handlers.util.stochss_errors import StochSSFileNotFoundError
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"nonexistent_file")
- try:
- duplicate(test_filepath)
- except StochSSFileNotFoundError:
- pass
- tempdir_contents = os.listdir(tempdir)
- assert len(tempdir_contents) == 0
-
- def test_duplicate_permission_not_granted_raise_error(self):
- from handlers.util.stochss_errors import StochSSPermissionsError
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"existent_file")
- Path(test_filepath).touch()
- os.chmod(test_filepath,000)
- with self.assertRaises(StochSSPermissionsError):
- duplicate(test_filepath)
-
- def test_duplicate_permission_not_granted_no_new_file(self):
- from handlers.util.stochss_errors import StochSSPermissionsError
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"existent_file")
- Path(test_filepath).touch()
- os.chmod(test_filepath,000)
- try:
- duplicate(test_filepath)
- except StochSSPermissionsError:
- pass
- tempdir_contents = os.listdir(tempdir)
- assert len(tempdir_contents) == 1
-
-
- def test_duplicate_copy_successful(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"existent_file")
- Path(test_filepath).touch()
- duplicate(test_filepath)
- tempdir_contents = os.listdir(tempdir)
- assert os.path.isfile(os.path.join(tempdir,'existent_file-copy'))
-
- #unit tests for method extract_wkfl_model
-
- def test_extract_wkfl_model_path_changed(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- Path(test_model_path).touch()
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- test_extract_target="test_model"
- extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file=test_extract_target)
- assert os.path.isfile(os.path.join(tempdir,"test_model(1)"))
-
- def test_extract_wkfl_model_path_not_changed(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- Path(test_model_path).touch()
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- test_extract_target="test_model_extracted"
- extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file=test_extract_target)
- assert os.path.isfile(os.path.join(tempdir,test_extract_target))
-
- def test_extract_wkfl_model_file_not_found_raise_error(self):
- from handlers.util.stochss_errors import ModelNotFoundError
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- with self.assertRaises(ModelNotFoundError):
- extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model")
-
- def test_extract_wkfl_model_file_not_found_no_new_file(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- tempdir_contents = os.listdir(tempdir)
- assert len(tempdir_contents) == 0
-
- def test_extract_wkfl_model_permission_not_granted_raise_error(self):
- from handlers.util.stochss_errors import StochSSPermissionsError
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- Path(test_model_path).touch()
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- os.chmod(test_model_path,000)
- with self.assertRaises(StochSSPermissionsError):
- extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model")
-
- def test_extract_wkfl_model_permission_not_granted_no_new_file(self):
- from handlers.util.stochss_errors import StochSSPermissionsError
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- Path(test_model_path).touch()
- class Test_Workflow:
- wkfl_mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl,"wkfl_mdl_path",test_model_path)
- os.chmod(test_model_path,000)
- try:
- extract_wkfl_model(wkfl=test_wkfl,mdl_parent_path=tempdir,model_file="test_model")
- except StochSSPermissionsError:
- pass
- tempdir_contents = os.listdir(tempdir)
- assert len(tempdir_contents) == 1
-
- #unit tests for method get_wkfl_model_parent_path
-
- def test_get_wkfl_model_parent_path_model_only(self):
- assert get_wkfl_model_parent_path("test_path", True, "no wkfl") == "test_path"
-
- def test_get_wkfl_model_parent_path_does_not_exist(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_model_path=os.path.join(tempdir,"test_model")
- class Test_Workflow:
- wkfl_mdl_path = ""
- mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl, "",test_model_path)
- assert get_wkfl_model_parent_path("path_does_not_exist", False, test_wkfl) == "path_does_not_exist"
-
- def test_get_wkfl_model_parent_path_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_dir_path=os.path.join(tempdir,'test_directory')
- os.mkdir(test_dir_path)
- test_file_path = os.path.join(test_dir_path,"test_file")
- class Test_Workflow:
- mdl_path = ""
- test_wkfl= Test_Workflow()
- setattr(test_wkfl, "mdl_path", test_file_path)
- Path(test_file_path).touch()
- assert get_wkfl_model_parent_path("path_does_not_exist", False, test_wkfl) == test_dir_path
-
- #unit tests for method get_model_path
-
- def test_get_model_path_only_model(self):
- assert get_model_path("test_wkfl_parent_path", "test_mdl_parent_path", "test_mdl_file", True) == (os.path.join("test_wkfl_parent_path","test_mdl_file"), "")
-
- def test_get_model_path_wkfl_parent_path_equals_mdl_parent_path_and_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_dual_parent_dir = os.path.join(tempdir, "test_dual_parent_dir")
- test_model_path = os.path.join(test_dual_parent_dir,"test_model")
- os.mkdir(test_dual_parent_dir)
- Path(test_model_path).touch()
- assert get_model_path(test_dual_parent_dir, test_dual_parent_dir, "test_model", False) == (os.path.join(test_dual_parent_dir,"test_model"), "")
-
- def test_get_model_path_mdl_file_in_wkfl_parent_path_directory(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir")
- os.mkdir(test_wkfl_parent_dir)
- test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir")
- os.mkdir(test_model_parent_dir)
- test_model_path = os.path.join(test_wkfl_parent_dir,"test_model")
- Path(test_model_path).touch()
- assert get_model_path(test_wkfl_parent_dir, "", "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "")
-
-
- def test_get_model_path_mdl_file_in_mdl_parent_path_directory(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir")
- os.mkdir(test_wkfl_parent_dir)
- test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir")
- os.mkdir(test_model_parent_dir)
- test_model_path = os.path.join(test_model_parent_dir,"test_model")
- Path(test_model_path).touch()
- assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_model_parent_dir,"test_model"), "")
-
-
- def test_get_model_path_mdl_file_in_mdl_and_wkfl_parent_path_directory(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir")
- os.mkdir(test_wkfl_parent_dir)
- test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir")
- os.mkdir(test_model_parent_dir)
- test_model_path = os.path.join(test_model_parent_dir,"test_model")
- Path(test_model_path).touch()
- test_model_path2 = os.path.join(test_wkfl_parent_dir,"test_model")
- Path(test_model_path2).touch()
- assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "")
-
-
- def test_get_model_path_mdl_file_not_found(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_wkfl_parent_dir = os.path.join(tempdir, "test_wkfl_parent_dir")
- os.mkdir(test_wkfl_parent_dir)
- test_model_parent_dir = os.path.join(tempdir, "test_model_parent_dir")
- os.mkdir(test_model_parent_dir)
- assert get_model_path(test_wkfl_parent_dir, test_model_parent_dir, "test_model", False) == (os.path.join(test_wkfl_parent_dir,"test_model"), "The model file {0} could not be found. To edit the model or run the workflow you will need to update the path to the model or extract the model from the workflow.".format("test_model"))
-
-
- #unit tests for method duplicate_wkfl_as_new
-
- def test_duplicate_wkfl_as_new_wkfl_file_not_found(self):
- from handlers.util.stochss_errors import StochSSFileNotFoundError
- with tempfile.TemporaryDirectory() as tempdir:
- with self.assertRaises(StochSSFileNotFoundError):
- duplicate_wkfl_as_new(os.path.join(tempdir,"nonexistent_wkfl"), False, "timestamp")
-
- def test_duplicate_wkfl_as_new_not_JSON_decodable(self):
- from handlers.util.stochss_errors import FileNotJSONFormatError
- with tempfile.TemporaryDirectory() as tempdir:
- Path(os.path.join(tempdir,"info.json")).touch()
- with self.assertRaises(FileNotJSONFormatError):
- duplicate_wkfl_as_new(os.path.join(tempdir), False, "timestamp")
-
-
- def test_duplicate_wkfl_as_new_only_model(self):
- #from json import load
- from unittest import mock
- from handlers.util.run_model import GillesPy2Workflow
- from handlers.util.stochss_errors import FileNotJSONFormatError
- with tempfile.TemporaryDirectory() as tempdir:
- test_dict={"type":"gillespy","source_model":"test_source_model"}
- test_path = os.path.join(tempdir,"test_wkfl_dir")
- os.mkdir(test_path)
- Path(os.path.join(test_path,"info.json")).touch()
- test_source_model_path = os.path.join(test_path,"test_source_model")
- Path(test_source_model_path).touch()
- with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings:
- mock_settings.return_value = None
- with mock.patch("json.load") as mock_json:
- mock_json.return_value = test_dict
- test_return = duplicate_wkfl_as_new(test_path, True, "timestamp")
- assert test_return == {'message': 'A copy of the model in {0} has been created'.format(test_path),"mdlPath":os.path.join(tempdir,"test_source_model"),"File":"test_source_model"}
-
- def test_duplicate_wkfl_as_new_model_file_not_found(self):
- #from json import load
- from unittest import mock
- from handlers.util.run_model import GillesPy2Workflow
- from handlers.util.stochss_errors import FileNotJSONFormatError
- with tempfile.TemporaryDirectory() as tempdir:
- test_dict={"type":"gillespy","source_model":"test_source_model"}
- test_path = os.path.join(tempdir,"test_wkfl_dir")
- os.mkdir(test_path)
- Path(os.path.join(test_path,"info.json")).touch()
- test_source_model_path = os.path.join(test_path,"test_source_model")
- Path(test_source_model_path).touch()
- with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings:
- mock_settings.return_value = None
- with mock.patch("json.load") as mock_json:
- mock_json.return_value = test_dict
- test_return = duplicate_wkfl_as_new(test_path, False, "timestamp")
- assert test_return == {'message': 'A new workflow has been created from {0}'.format(test_path), 'wkflPath': test_path+"timestamp.wkfl", 'mdlPath': os.path.join(tempdir,"test_source_model"), 'File': 'test_wkfl_dirtimestamp.wkfl', 'mdl_file': 'test_source_model', 'error': 'The model file test_source_model could not be found. To edit the model or run the workflow you will need to update the path to the model or extract the model from the workflow.'}
-
- def test_duplicate_wkfl_as_new_model_file_exists(self):
- #from json import load
- from unittest import mock
- from handlers.util.run_model import GillesPy2Workflow
- from handlers.util.stochss_errors import FileNotJSONFormatError
- with tempfile.TemporaryDirectory() as tempdir:
- test_dict={"type":"gillespy","source_model":"test_source_model"}
- test_path = os.path.join(tempdir,"test_wkfl_dir")
- os.mkdir(test_path)
- Path(os.path.join(test_path,"info.json")).touch()
- test_source_model_path = os.path.join(test_path,"test_source_model")
- Path(test_source_model_path).touch()
- Path(os.path.join(tempdir,"test_source_model")).touch()
- with mock.patch("handlers.util.run_model.GillesPy2Workflow.get_settings") as mock_settings:
- mock_settings.return_value = None
- with mock.patch("json.load") as mock_json:
- mock_json.return_value = test_dict
- test_return = duplicate_wkfl_as_new(test_path, False, "timestamp")
- assert test_return == {'message': 'A new workflow has been created from {0}'.format(test_path), 'wkflPath': test_path+"timestamp.wkfl", 'mdlPath': os.path.join(tempdir,"test_source_model"), 'File': 'test_wkfl_dirtimestamp.wkfl', 'mdl_file': 'test_source_model'}
diff --git a/stochss/tests/test_generate_zip_file.py b/stochss/tests/test_generate_zip_file.py
deleted file mode 100644
index 4806ad9173..0000000000
--- a/stochss/tests/test_generate_zip_file.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import os
-import unittest
-import tempfile
-import handlers.util.generate_zip_file as generate_zip_file
-import handlers.util.stochss_errors as stochss_errors
-
-class TestGenerateZipFile(unittest.TestCase):
-
- #unit tests for method generate_zip_file
-
- def test_generate_zip_file(self):
- test_file = "test_file.foo"
- test_path = os.path.join("test_path", test_file)
- test_dir = "test_dir"
- test_target = "test_target"
- with unittest.mock.patch("shutil.make_archive") as mock_make_archive:
- generate_zip_file.generate_zip_file(test_path, test_dir, test_target)
- correct_filepath = os.path.join(test_dir, "test_file")
- mock_make_archive.assert_called_with(correct_filepath, 'zip', test_dir, test_target)
-
- #unit tests for method get_zip_file_data
-
- def test_get_zip_file_data(self):
- with unittest.mock.patch("builtins.open", unittest.mock.mock_open(read_data="foo")):
- assert generate_zip_file.get_zip_file_data("placeholder") == "foo"
-
- #unit tests for method get_results_csv_dir
-
- def test_get_results_csv_dir_not_found(self):
- test_file = "results_csv"
- test_path = "placeholder"
- assert generate_zip_file.get_results_csv_dir(test_file, test_path) is None
-
- def test_get_results_csv_dir_is_found(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_dir = os.path.join(tempdir, "results_csv")
- os.mkdir(test_dir)
- assert generate_zip_file.get_results_csv_dir(test_dir, tempdir) == test_dir
-
- #unit tests for method download_zip
-
- def test_download_zip_file_invalid_path(self):
- with self.assertRaises(stochss_errors.StochSSFileNotFoundError):
- generate_zip_file.download_zip("placeholder_path", "placeholder_action")
-
- def test_download_zip_file_calls_generate_zip_file(self):
- test_path = "test_dir/test_path.foo"
- test_action = "generate"
- with unittest.mock.patch("os.path.exists"):
- with unittest.mock.patch("handlers.util.generate_zip_file.get_unique_file_name",\
- return_value="test_path"):
- with unittest.mock.patch("handlers.util.generate_zip_file.generate_zip_file")\
- as mock_generate:
- generate_zip_file.download_zip(test_path, test_action)
- mock_generate.assert_called_with("t", os.path.join("/home/jovyan", "test_dir"), \
- os.path.join("/home/jovyan", test_path))
-
- def test_download_zip_file_action_generate(self):
- test_path = "test_dir/test_path.foo"
- test_action = "generate"
- test_resp = {"Message":"Successfully created t", "Path":"t",}
- with unittest.mock.patch("os.path.exists"):
- with unittest.mock.patch("handlers.util.generate_zip_file.get_unique_file_name",\
- return_value="test_path"):
- with unittest.mock.patch("handlers.util.generate_zip_file.generate_zip_file"):
- assert generate_zip_file.download_zip(test_path, test_action) == test_resp
-
- #download_zip action resultscsv is not covered pending refactor of user dir from /home/jovyan
diff --git a/stochss/tests/test_gillespy2.py b/stochss/tests/test_gillespy2.py
new file mode 100644
index 0000000000..b16fbfa94a
--- /dev/null
+++ b/stochss/tests/test_gillespy2.py
@@ -0,0 +1,167 @@
+'''
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+'''
+
+import os
+import unittest
+
+from gillespy2 import GillesPySolver
+
+from example_models import (
+ Brusselator,
+ Degradation,
+ Dimerization,
+ LotkavolterraOscillator,
+ MichaelisMenten,
+ Opioid,
+ Schlogl,
+ ToggleSwitch,
+ VilarOscillator,
+ Oregonator,
+ TysonOscillator
+)
+
+os.chdir('/stochss')
+
+# pylint: disable=import-outside-toplevel
+class TestGillesPy2Dependency(unittest.TestCase):
+ '''
+ ################################################################################################
+ Unit tests for GillesPy2 dependency.
+ ################################################################################################
+ '''
+ def setUp(self):
+ ''' Create a list of common example paths for each test. '''
+ self.test_models = [Brusselator, Degradation, Dimerization, LotkavolterraOscillator,
+ MichaelisMenten, Opioid, Schlogl, ToggleSwitch, VilarOscillator]
+
+ ################################################################################################
+ # Unit tests for GillesPy2 dependency check_cpp_support.
+ ################################################################################################
+
+ def test_check_cpp_support(self):
+ ''' Check if the check cpp support functions works in StochSS. '''
+ from gillespy2.solvers.utilities.cpp_support_test import check_cpp_support
+
+ self.assertIsInstance(check_cpp_support(), bool)
+
+ ################################################################################################
+ # Unit tests for GillesPy2 dependency get_best_solver.
+ ################################################################################################
+
+ def test_get_best_solver(self):
+ ''' Check if the get best solver function works in StochSS. '''
+ test_model = self.test_models[0]()
+ test_solver = test_model.get_best_solver()
+ self.assertIsInstance(test_solver(), GillesPySolver)
+
+ ################################################################################################
+ # Unit tests for GillesPy2 dependency get_best_solver_algo.
+ ################################################################################################
+
+ def test_get_best_solver_algo(self):
+ ''' Check if the get best solver algo function works in StochSS. '''
+ test_algos = ["ODE", "SSA", "Tau-Leaping"]
+ test_model = self.test_models[0]()
+ for test_algo in test_algos:
+ with self.subTest(test_algo=test_algo):
+ test_solver = test_model.get_best_solver_algo(algorithm=test_algo)
+ self.assertIsInstance(test_solver(), GillesPySolver)
+
+ ################################################################################################
+ # Unit tests for GillesPy2 dependency solvers.
+ ################################################################################################
+
+ def test_ode_solver(self):
+ ''' Check if the test_models run with the ODESolver. '''
+ from gillespy2 import ODESolver
+
+ self.test_models.append(Oregonator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_model.run(solver=ODESolver)
+
+
+ def test_ode_c_solver(self):
+ ''' Check if the test_models run with the ODECSolver. '''
+ from gillespy2 import ODECSolver
+
+ self.test_models.append(Oregonator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_solver = ODECSolver(model=test_model)
+ test_model.run(solver=test_solver)
+
+
+ def test_numpy_ssa_solver(self):
+ ''' Check if the test_models run with the NumPySSASolver. '''
+ from gillespy2 import NumPySSASolver
+
+ self.test_models.append(TysonOscillator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_model.run(solver=NumPySSASolver)
+
+
+ def test_ssa_c_solver(self):
+ ''' Check if the test_models run with the SSACSolver. '''
+ from gillespy2 import SSACSolver
+
+ self.test_models.append(TysonOscillator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_solver = SSACSolver(model=test_model)
+ test_model.run(solver=test_solver)
+
+
+ def test_tau_leaping_solver(self):
+ ''' Check if the test_models run with the TauLeapingSolver. '''
+ from gillespy2 import TauLeapingSolver
+
+ self.test_models.append(TysonOscillator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_model.run(solver=TauLeapingSolver)
+
+
+ def test_tau_leaping_c_solver(self):
+ ''' Check if the test_models run with the TauLeapingCSolver. '''
+ from gillespy2 import TauLeapingCSolver
+
+ self.test_models.append(TysonOscillator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_solver = TauLeapingCSolver(model=test_model)
+ test_model.run(solver=test_solver)
+
+
+ def test_tau_hybrid_solver(self):
+ ''' Check if the test_models run with the TauHybridSolver. '''
+ from gillespy2 import TauHybridSolver
+
+ self.test_models.append(Oregonator)
+ self.test_models.append(TysonOscillator)
+ for model in self.test_models:
+ test_model = model()
+ with self.subTest(model=test_model.name):
+ test_model.run(solver=TauHybridSolver)
diff --git a/stochss/tests/test_ls.py b/stochss/tests/test_ls.py
deleted file mode 100644
index e5d6f3b7e9..0000000000
--- a/stochss/tests/test_ls.py
+++ /dev/null
@@ -1,228 +0,0 @@
-"""Unit tests for handlers.util.ls.py"""
-import unittest
-import os
-import tempfile
-from pathlib import Path
-
-import handlers.util.ls as ls
-from handlers.util.stochss_errors import StochSSFileNotFoundError
-
-class TestLS(unittest.TestCase):
- """Unit test container for handlers.util.ls.py"""
-
- #unit tests for method get_file_system_data
-
- def test_get_file_system_data_dir_not_found(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "nonexistent_dir")
- with self.assertRaises(StochSSFileNotFoundError):
- ls.get_file_system_data(test_path, tempdir)
-
- @classmethod
- def test_get_file_system_data_no_children(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "empty_dir")
- os.mkdir(test_path)
- children = ls.get_file_system_data(test_path, tempdir)
- assert len(children) == 0
-
- @classmethod
- def test_get_file_system_data_child_is_wkfl(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.wkfl")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with \
- (text="test_file.wkfl", f_type="workflow", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_mdl(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.mdl")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.mdl", f_type="nonspatial", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_smdl(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.smdl")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.smdl", f_type="spatial", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_mesh(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.mesh")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.mesh", f_type="mesh", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_ipynb(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.ipynb")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.ipynb", f_type="notebook", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_sbml(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.sbml")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.sbml", f_type="sbml-model", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_dir(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_dir_path = os.path.join(test_path, "test_dir")
- os.mkdir(test_dir_path)
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_dir", f_type="folder", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_other(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_file_path = os.path.join(test_path, "test_file.foo")
- Path(test_file_path).touch()
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_file.foo", f_type="other", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_exp(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_dir_path = os.path.join(test_path, "test_dir.wkgp")
- os.mkdir(test_dir_path)
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_dir.wkgp", f_type="workflow-group", p_path=tempdir)
-
- @classmethod
- def test_get_file_system_data_child_is_proj(cls):
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "parent_dir")
- os.mkdir(test_path)
- test_dir_path = os.path.join(test_path, "test_dir.proj")
- os.mkdir(test_dir_path)
- with unittest.mock.patch("handlers.util.ls.build_child") as mock_build_child:
- ls.get_file_system_data(test_path, tempdir)
- mock_build_child.assert_called_once_with\
- (text="test_dir.proj", f_type="project", p_path=tempdir)
-
- #unit tests for method build_child
-
- @classmethod
- def test_build_child_top_level(cls):
- with tempfile.TemporaryDirectory():
- test_p_path = "none"
- test_text = "test_text"
- test_f_type = "test_f_type"
- assert ls.build_child(text=test_text, f_type=test_f_type, p_path=test_p_path) ==\
- {"text" : "test_text", "type" : "test_f_type", \
- "_path" : "test_text", "children" : False}
-
- @classmethod
- def test_build_child_sub_level(cls):
- with tempfile.TemporaryDirectory():
- test_p_path = "test_p_path"
- test_text = "test_text"
- test_f_type = "test_f_type"
- assert ls.build_child(text=test_text, f_type=test_f_type, p_path=test_p_path) == \
- {"text" : "test_text", "type" : "test_f_type", \
- "_path" : os.path.join(test_p_path, test_text), "children" : False}
-
- @classmethod
- def test_build_child_wkfl_calls_get_status(cls):
- with tempfile.TemporaryDirectory():
- test_p_path = "test_p_path"
- test_text = "test_text"
- test_f_type = "workflow"
- with unittest.mock.patch("handlers.util.ls.get_status") as mock_get_status:
- ls.build_child(text=test_text, p_path=test_p_path, f_type=test_f_type)
- mock_get_status.assert_called()
-
- #unit tests for method build_root
-
- @classmethod
- def test_build_root(cls):
- test_children = "test_children"
- assert ls.build_root(test_children) ==\
- [{"text":"/", "type":"root", "_path":"/", \
- "children":"test_children", "state":{"opened":True}}]
-
- #unit tests for method check_extension
-
- @classmethod
- def test_check_extension_true(cls):
- test_str = "test"
- test_target = "target"
- test_name = test_str + test_target
- assert ls.check_extension(test_name, test_target)
-
- @classmethod
- def test_check_extension_false(cls):
- test_str = "test"
- test_target = "target"
- test_name = test_str
- assert not ls.check_extension(test_name, test_target)
-
- #unit tests for method list_files
-
- @classmethod
- def test_ls_p_path_none(cls):
- test_p_path = "none"
- with unittest.mock.patch("handlers.util.ls.build_root") as mock_build_root:
- with unittest.mock.patch("handlers.util.ls.get_file_system_data", \
- return_value="test_return") as mock_get_file_system_data:
- with unittest.mock.patch("json.dumps"):
- ls.list_files(p_path=test_p_path)
- mock_get_file_system_data.assert_called()
- mock_build_root.assert_called_with("test_return")
-
- @classmethod
- def test_ls_p_path_not_none(cls):
- test_p_path = "test_p_path"
- test_full_path = os.path.join("/home/jovyan", test_p_path)
- with unittest.mock.patch("handlers.util.ls.build_root"):
- with unittest.mock.patch("handlers.util.ls.get_file_system_data", \
- return_value="test_return") as mock_get_file_system_data:
- with unittest.mock.patch("json.dumps"):
- ls.list_files(p_path=test_p_path)
- mock_get_file_system_data.assert_called_with(test_full_path, test_p_path)
diff --git a/stochss/tests/test_model_template.py b/stochss/tests/test_model_template.py
index d40e639bd5..3e6812f079 100644
--- a/stochss/tests/test_model_template.py
+++ b/stochss/tests/test_model_template.py
@@ -1,19 +1,48 @@
+'''
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+'''
+
import unittest
import json
import os
os.chdir('/stochss')
-template_path = "stochss_templates/nonSpatialModelTemplate.json"
+class TestModelTemplate(unittest.TestCase):
+ '''
+ ################################################################################################
+ Unit tests for model template completeness.
+ ################################################################################################
+ '''
+ def setUp(self):
+ '''
+ Get the model template prior to each test.
+ '''
+ template_path = "stochss_templates/nonSpatialModelTemplate.json"
+ with open(template_path, "r") as template_file:
+ self.template = json.load(template_file)
-class TestNonSpatialModelTemplate(unittest.TestCase):
def test_model_elements(self):
- with open(template_path, "r") as template_file:
- template = json.load(template_file)
-
- template_keys = sorted(list(template.keys()))
+ '''
+ Check if the model template has all of the properties currently in the model model.
+ '''
+ template_keys = sorted(list(self.template.keys()))
model_path = "client/models/model.js"
with open(model_path, "r") as model_file:
@@ -24,21 +53,40 @@ def test_model_elements(self):
model_keys = list(map(lambda item: item.strip().split(':')[0], props))
model_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections)))
model_keys.extend(list(map(lambda item: item.strip().split(':')[0], children)))
-
+
model_keys.sort()
self.assertEqual(template_keys, model_keys)
- def test_model_settings_elements(self):
- with open(template_path, "r") as template_file:
- template = json.load(template_file)
+ def test_timespan_settings_elements(self):
+ '''
+ Check if the timespan settings in the model template has
+ all of the properties currently in the timespan settings model.
+ '''
+ template_keys = sorted(list(self.template['modelSettings'].keys()))
+ mdl_settings_path = "client/models/timespan-settings.js"
- template_keys = sorted(list(template['modelSettings'].keys()))
- mdl_settings_path = "client/models/model-settings.js"
-
with open(mdl_settings_path, "r") as mdl_settings_file:
data = mdl_settings_file.read().split("props: {").pop().split('}')[0].split(',')
mdl_settings_keys = sorted(list(map(lambda item: item.strip().split(':')[0], data)))
self.assertEqual(template_keys, mdl_settings_keys)
+
+ def test_model_domain_elements(self):
+ '''
+ Check if the domain in the model template has all of the
+ properties currently in the domain model.
+ '''
+ template_keys = sorted(list(self.template['domain'].keys()))
+ domain_path = "client/models/domain.js"
+
+ with open(domain_path, "r") as domain_file:
+ data = domain_file.read()
+ props = data.split("props: {").pop().split('}')[0].split(',')
+ collections = data.split("collections: {").pop().split('}')[0].split(',')
+ domain_keys = list(map(lambda item: item.strip().split(':')[0], props))
+ domain_keys.extend(list(map(lambda item: item.strip().split(':')[0], collections)))
+
+ domain_keys.sort()
+ self.assertEqual(template_keys, domain_keys)
diff --git a/stochss/tests/test_rename.py b/stochss/tests/test_rename.py
deleted file mode 100644
index 7940647080..0000000000
--- a/stochss/tests/test_rename.py
+++ /dev/null
@@ -1,130 +0,0 @@
-import unittest, os, tempfile
-from pathlib import Path
-from handlers.util.rename import *
-
-class TestRename(unittest.TestCase):
-
- #unit tests for method get_unique_file_name
-
- def test_get_unique_file_name_target_does_not_exist(self):
- with tempfile.TemporaryDirectory() as tempdir:
- gufn_return_filepath = os.path.join(tempdir,"nonexistent_file")
- gufn_return_tuple = (gufn_return_filepath, False)
- assert get_unique_file_name("nonexistent_file", tempdir) == (gufn_return_tuple)
-
- def test_get_unique_file_name_target_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"existent_file")
- Path(test_filepath).touch()
- gufn_return_filepath = os.path.join(tempdir,"existent_file(1)")
- gufn_return_tuple = (gufn_return_filepath, True)
- assert get_unique_file_name("existent_file", tempdir) == gufn_return_tuple
-
- def test_get_unique_file_name_numbered_target_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filepath = os.path.join(tempdir,"existent_file(1)")
- Path(test_filepath).touch()
- gufn_return_filepath = os.path.join(tempdir,"existent_file(2)")
- gufn_return_tuple = (gufn_return_filepath, True)
- assert get_unique_file_name("existent_file(1)", tempdir) == gufn_return_tuple
-
- def test_get_unique_file_name_with_extension_target_does_not_exist(self):
- with tempfile.TemporaryDirectory() as tempdir:
- gufn_return_filepath = os.path.join(tempdir,"nonexistent_file.foo")
- gufn_return_tuple = (gufn_return_filepath, False)
- assert get_unique_file_name("nonexistent_file.foo", tempdir) == (gufn_return_tuple)
-
- def test_get_unique_file_name_with_extension_target_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "existent_file.foo"
- test_filepath = os.path.join(tempdir,test_filename)
- Path(test_filepath).touch()
- gufn_return_filepath = os.path.join(tempdir,"existent_file(1).foo")
- gufn_return_tuple = (gufn_return_filepath, True)
- assert get_unique_file_name(test_filename, tempdir) == gufn_return_tuple
-
-
- def test_get_unique_file_name_iterated(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_filename = "existent_file"
- test_filepath = os.path.join(tempdir, test_filename)
- Path(test_filepath).touch()
- for i in range(3):
- test_filename, placeholder = get_unique_file_name(test_filename, tempdir)
- Path(test_filename).touch()
- test_filename = test_filename.split('/').pop()
- assert len(os.listdir(tempdir)) == 4
-
- def test_get_unique_file_name_invalid_path(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_dirpath = os.path.join(tempdir,"invalid_directory")
- with self.assertRaises(FileNotFoundError):
- get_unique_file_name("nonexistent_file", test_dirpath)
-
- #unit tests for method rename
-
- def test_rename_file(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_file = "test_file"
- test_path = os.path.join(tempdir,test_file)
- Path(test_path).touch()
- rename(test_path, "test_file2")
- test_new_path = os.path.join(tempdir, "test_file2")
- assert os.path.isfile(test_new_path)
-
- def test_rename_directory(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_dir = "test_dir"
- test_path = os.path.join(tempdir, test_dir)
- os.mkdir(test_path)
- rename(test_path, "test_dir2")
- test_new_path = os.path.join(tempdir, "test_dir2")
- assert os.path.isdir(test_new_path)
-
- def test_rename_permission_error(self):
- from handlers.util.stochss_errors import StochSSPermissionsError
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- test_dir = "test_dir"
- test_file = "test_file"
- test_dir_path = os.path.join(tempdir,test_dir)
- os.mkdir(test_dir_path)
- test_path = os.path.join(test_dir_path,test_file)
- Path(test_path).touch()
- with mock.patch("shutil.move", side_effect=StochSSPermissionsError('test_error')) as mock_shutil:
- with self.assertRaises(StochSSPermissionsError):
- rename(test_path, "test_file2")
-
- def test_rename_file_not_found_error(self):
- from handlers.util.stochss_errors import StochSSFileNotFoundError
- with tempfile.TemporaryDirectory() as tempdir:
- test_file = "test_file"
- test_path = os.path.join(tempdir,test_file)
- with self.assertRaises(StochSSFileNotFoundError):
- rename(test_path, "test_file2")
-
- def test_rename_target_exists(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_file = "test_file"
- test_path = os.path.join(tempdir, test_file)
- Path(test_path).touch()
- test_file2 = "test_file2"
- test_path2 = os.path.join(tempdir, test_file2)
- Path(test_path2).touch()
- resp = rename(test_path, "test_file2")
- assert resp["changed"] == True
-
- def test_rename_running_wkfl(self):
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- with mock.patch("json.dump") as mock_dump:
- with mock.patch("json.load") as mock_json:
- with mock.patch('builtins.open', mock.mock_open(read_data="foo")) as m:
- test_file = "test_file.wkfl"
- test_path = os.path.join(tempdir, test_file)
- target_path = os.path.join(tempdir, "test_file2")
- os.mkdir(test_path)
- os.mkdir(target_path)
- Path(os.path.join(target_path,"RUNNING")).touch()
- rename(test_path, "test_file2")
- m.assert_called_with(os.path.join(target_path, "info.json"), 'r+')
diff --git a/stochss/tests/test_settings_template.py b/stochss/tests/test_settings_template.py
index a53f417704..8db314b230 100644
--- a/stochss/tests/test_settings_template.py
+++ b/stochss/tests/test_settings_template.py
@@ -1,33 +1,62 @@
+'''
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+'''
+
import unittest
import json
import os
os.chdir('/stochss')
-template_path = "stochss_templates/workflowSettingsTemplate.json"
-
-
class TestWorkflowSettingsTemplate(unittest.TestCase):
+ '''
+ ################################################################################################
+ Unit tests for settings template completeness.
+ ################################################################################################
+ '''
+ def setUp(self):
+ '''
+ Get the settings template prior to each test.
+ '''
+ template_path = "stochss_templates/workflowSettingsTemplate.json"
- def test_settings_elements(self):
with open(template_path, "r") as template_file:
- template = json.load(template_file)
+ self.template = json.load(template_file)
- template_keys = sorted(list(template.keys()))
+ def test_workflow_settings_elements(self):
+ '''
+ Check if the settings template has all of the properties currently in the settings model.
+ '''
+ template_keys = sorted(list(self.template.keys()))
model_path = "client/models/settings.js"
with open(model_path, "r") as model_file:
children = model_file.read().split("children: {").pop().split('}')[0].split(',')
model_keys = sorted(list(map(lambda item: item.strip().split(':')[0], children)))
-
- self.assertEqual(template_keys, model_keys)
+ self.assertEqual(template_keys, model_keys)
- def test_simulation_settings_elements(self):
- with open(template_path, "r") as template_file:
- template = json.load(template_file)
- template_keys = sorted(list(template['simulationSettings'].keys()))
+ def test_workflow_simulation_settings_elements(self):
+ '''
+ Check if the simulation settings in the settings template has
+ all of the properties currently in the simulation settings model.
+ '''
+ template_keys = sorted(list(self.template['simulationSettings'].keys()))
sim_settings_path = "client/models/simulation-settings.js"
with open(sim_settings_path, "r") as sim_settings_file:
@@ -37,29 +66,32 @@ def test_simulation_settings_elements(self):
self.assertEqual(template_keys, sim_settings_keys)
- def test_psweep_settings_elements(self):
- with open(template_path, "r") as template_file:
- template = json.load(template_file)
-
- template_keys = sorted(list(template['parameterSweepSettings'].keys()))
+ def test_workflow_parameter_sweep_settings_elements(self):
+ '''
+ Check if the parameter sweep settings in the settings template has
+ all of the properties currently in the parameter sweep settings model.
+ '''
+ template_keys = sorted(list(self.template['parameterSweepSettings'].keys()))
psweep_settings_path = "client/models/parameter-sweep-settings.js"
with open(psweep_settings_path, "r") as psweep_settings_file:
data = psweep_settings_file.read()
- props = data.split("props: {").pop().split('}')[0].split(',')
+ collections = data.split("collections: {").pop().split('}')[0].split(',')
children = data.split("children: {").pop().split('}')[0].split(',')
- psweep_settings_keys = list(map(lambda item: item.strip().split(':')[0], props))
- psweep_settings_keys.extend(list(map(lambda item: item.strip().split(':')[0], children)))
+ psweep_settings_keys = list(map(lambda item: item.strip().split(':')[0], collections))
+ psweep_settings_keys.extend(list(map(lambda item: item.strip().split(':')[0],
+ children)))
psweep_settings_keys.sort()
self.assertEqual(template_keys, psweep_settings_keys)
- def test_results_settings_elements(self):
- with open(template_path, "r") as template_file:
- template = json.load(template_file)
-
- template_keys = sorted(list(template['resultsSettings'].keys()))
+ def test_workflow_results_settings_elements(self):
+ '''
+ Check if the results settings in the settings template has
+ all of the properties currently in the results settings model.
+ '''
+ template_keys = sorted(list(self.template['resultsSettings'].keys()))
results_settings_path = "client/models/results-settings.js"
with open(results_settings_path, "r") as results_settings_file:
@@ -68,3 +100,17 @@ def test_results_settings_elements(self):
self.assertEqual(template_keys, results_settings_keys)
+
+ def test_workflow_timespan_settings_elements(self):
+ '''
+ Check if the timespan settings in the model template has
+ all of the properties currently in the timespan settings model.
+ '''
+ template_keys = sorted(list(self.template['timespanSettings'].keys()))
+ tspan_settings_path = "client/models/timespan-settings.js"
+
+ with open(tspan_settings_path, "r") as tspan_settings_file:
+ data = tspan_settings_file.read().split("props: {").pop().split('}')[0].split(',')
+ tspan_settings_keys = sorted(list(map(lambda item: item.strip().split(':')[0], data)))
+
+ self.assertEqual(template_keys, tspan_settings_keys)
diff --git a/stochss/tests/test_stochss_base.py b/stochss/tests/test_stochss_base.py
new file mode 100644
index 0000000000..11e2f1f920
--- /dev/null
+++ b/stochss/tests/test_stochss_base.py
@@ -0,0 +1,857 @@
+'''
+StochSS is a platform for simulating biochemical systems
+Copyright (C) 2019-2021 StochSS developers.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+'''
+
+import os
+import json
+import shutil
+import logging
+import unittest
+import tempfile
+import datetime
+
+from unittest import mock
+from pathlib import Path
+
+from stochss.handlers import StochSSBase
+from stochss.handlers.util.stochss_errors import StochSSFileNotFoundError, FileNotJSONFormatError, \
+ StochSSPermissionsError
+
+os.chdir('/stochss')
+
+# pylint: disable=too-many-public-methods
+# pylint: disable=line-too-long
+class TestStochSSBaseObject(unittest.TestCase):
+ '''
+ ################################################################################################
+ Unit tests for the StochSS base class.
+ ################################################################################################
+ '''
+ def setUp(self):
+ ''' Create a temporary directory with a file and folder for each base test. '''
+ self.user_dir = os.path.expanduser("~")
+ self.tempdir = tempfile.TemporaryDirectory()
+ test_filename = "test_base_file"
+ test_foldername = "test_base_folder"
+ self.test_filepath = os.path.join(self.tempdir.name, test_filename)
+ Path(self.test_filepath).touch()
+ self.test_folderpath = os.path.join(self.tempdir.name, test_foldername)
+ os.mkdir(self.test_folderpath)
+
+
+ def tearDown(self):
+ ''' Cleanup the temp directory after each test. '''
+ self.tempdir.cleanup()
+ if StochSSBase.user_dir != os.path.expanduser("~"):
+ StochSSBase.user_dir = os.path.expanduser("~")
+
+ ################################################################################################
+ # Unit tests for the StochSS base class check_project_format function.
+ ################################################################################################
+
+ def test_check_project_format__old_with_mdl(self):
+ ''' Check if the project is identified as old when it contains a model. '''
+ test_files = ["test_model.mdl", "test_model.smdl"]
+ for test_file in test_files:
+ with self.subTest(test_file=test_file):
+ test_file_path = os.path.join(self.test_folderpath, test_file)
+ Path(test_file_path).touch()
+ self.assertFalse(StochSSBase.check_project_format(path=self.test_folderpath))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_check_project_format__old_with_wkgp1(self):
+ ''' Check if the project is identified as old when it contains one
+ workflow group with the name WorkflowGroup1.wkgp. '''
+ test_wkgp = os.path.join(self.test_folderpath, "WorkflowGroup1.wkgp")
+ os.mkdir(test_wkgp)
+ self.assertFalse(StochSSBase.check_project_format(path=self.test_folderpath))
+
+
+ def test_check_project_format__new_empty(self):
+ ''' Check if the project is identified as new when empty. '''
+ self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath))
+
+
+ def test_check_project_format__new_with_one_wkgp_not_wkgp1(self):
+ ''' Check if the project is identified as new with one workflow group. '''
+ test_wkgp = os.path.join(self.test_folderpath, "test_wkgp.wkgp")
+ os.mkdir(test_wkgp)
+ self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath))
+
+
+ def test_check_project_format__new_with_x_wkgps(self):
+ ''' Check if the project is identified as new with multiple workflow groups. '''
+ test_wkgp1 = os.path.join(self.test_folderpath, "test_wkgp1.wkgp")
+ os.mkdir(test_wkgp1)
+ test_wkgp2 = os.path.join(self.test_folderpath, "test_wkgp2.wkgp")
+ os.mkdir(test_wkgp2)
+ self.assertTrue(StochSSBase.check_project_format(path=self.test_folderpath))
+
+ ################################################################################################
+ # Unit tests for the StochSS base class check_workflow_format function.
+ ################################################################################################
+
+ def test_check_workflow_format__old_with_old_files(self):
+ ''' Check if the workflow is identified as old when it an old file. '''
+ test_files = ["info.json", "logs.txt", "RUNNING", "ERROR", "COMPLETE", "test_model.mdl"]
+ for test_file in test_files:
+ with self.subTest(test_file=test_file):
+ test_file_path = os.path.join(self.test_folderpath, test_file)
+ Path(test_file_path).touch()
+ self.assertFalse(StochSSBase.check_workflow_format(path=self.test_folderpath))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_check_workflow_format__old_with_results(self):
+ ''' Check if the workflow is identified as old when it a results folder. '''
+ test_dir = os.path.join(self.test_folderpath, "results")
+ os.mkdir(test_dir)
+ self.assertFalse(StochSSBase.check_workflow_format(path=self.test_folderpath))
+
+
+ def test_check_workflow_format__new(self):
+ ''' Check if the workflow is identified as old. '''
+ self.assertTrue(StochSSBase.check_workflow_format(path=self.test_folderpath))
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_new_path function.
+ ################################################################################################
+
+ def test_get_new_path(self):
+ ''' Check if the new path is generated correctly. '''
+ test_dst_path = os.path.join(self.test_folderpath, "test_file")
+ test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path)
+ self.assertEqual(test_file_path, os.path.join(self.user_dir, test_dst_path))
+
+
+ def test_get_new_path__no_trash_folder(self):
+ ''' Check if the trash directory is created. '''
+ test_dst_path = os.path.join("trash", "test_file")
+ StochSSBase.user_dir = self.test_folderpath
+ StochSSBase.get_new_path(dst_path=test_dst_path)
+ self.assertTrue(os.path.exists(os.path.join(self.test_folderpath, "trash")))
+
+
+
+ def test_get_new_path__remove_trash_datetime_stamp(self):
+ ''' Check if the trash datetime stamp is removed from files moving out of trash. '''
+ test_dst_path = os.path.join(self.test_folderpath, "trash", "test_file 2021.06.28.08.50.30")
+ test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path)
+ expected_path = os.path.join(self.user_dir, os.path.join(self.test_folderpath, "trash", "test_file"))
+ self.assertEqual(test_file_path, expected_path)
+
+ def test_get_new_path__add_trash_datetime_stamp(self):
+ ''' Check if the trash datetime stamp is added to duplicate files moved into trash. '''
+ os.mkdir(os.path.join(self.test_folderpath, "trash"))
+ test_dst_path = os.path.join(self.test_folderpath, "trash", "test_file")
+ Path(test_dst_path).touch()
+ test_file_path = StochSSBase.get_new_path(dst_path=test_dst_path)
+ stamp = datetime.datetime.now().strftime(" %y.%m.%d.%H.%M.%S")
+ expected_path = os.path.join(self.user_dir, os.path.join(self.test_folderpath, "trash", f"test_file{stamp}"))
+ self.assertEqual(test_file_path, expected_path)
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_file function.
+ ################################################################################################
+
+ def test_get_file__no_path_passed(self):
+ ''' Check if the file from self.path of StochSSBase is returned. '''
+ test_base = StochSSBase(path=self.test_folderpath)
+ self.assertEqual(test_base.get_file(), "test_base_folder")
+
+
+ def test_get_file__path_passed(self):
+ ''' Check is the file from the passed in path is returned. '''
+ test_base = StochSSBase(path=self.test_folderpath)
+ self.assertEqual(test_base.get_file(path=self.test_filepath), "test_base_file")
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_model_template function.
+ ################################################################################################
+
+ def test_get_model_template__as_dict(self):
+ ''' Check if the model template is returned as a dictionary. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ test_template = test_base.get_model_template()
+ self.assertIsInstance(test_template, dict)
+
+
+ def test_get_model_template__as_str(self):
+ ''' Check is the model template is returned as a string. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ test_template = test_base.get_model_template(as_string=True)
+ self.assertIsInstance(test_template, str)
+
+
+ def test_get_model_template__file_not_found_error(self):
+ ''' Check if the StochSSFileNotFoundError is raised when the template file is missing. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ with mock.patch("builtins.open", mock.mock_open()) as mock_file:
+ mock_file.side_effect = FileNotFoundError
+ with self.assertRaises(StochSSFileNotFoundError):
+ test_base.get_model_template()
+
+
+ def test_get_model_template__json_decoder_error(self):
+ ''' Check is the FileNotJSONFormatError is raised when the template is not properly formatted. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ with mock.patch("json.load") as mock_load:
+ mock_load.side_effect = json.decoder.JSONDecodeError(msg="", doc="", pos=1)
+ with self.assertRaises(FileNotJSONFormatError):
+ test_base.get_model_template()
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_settings_template function.
+ ################################################################################################
+
+ def test_get_settings_template__as_dict(self):
+ ''' Check if the settings template is returned as a dictionary. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ test_template = test_base.get_settings_template()
+ self.assertIsInstance(test_template, dict)
+
+
+ def test_get_settings_template__as_str(self):
+ ''' Check is the settings template is returned as a string. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ test_template = test_base.get_settings_template(as_string=True)
+ self.assertIsInstance(test_template, str)
+
+
+ def test_get_settings_template__file_not_found_error(self):
+ ''' Check if the StochSSFileNotFoundError is raised when the template file is missing. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ with mock.patch("builtins.open", mock.mock_open()) as mock_file:
+ mock_file.side_effect = FileNotFoundError
+ with self.assertRaises(StochSSFileNotFoundError):
+ test_base.get_settings_template()
+
+
+ def test_get_settings_template__json_decoder_error(self):
+ ''' Check is the FileNotJSONFormatError is raised when the template is not properly formatted. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ with mock.patch("json.load") as mock_load:
+ mock_load.side_effect = json.decoder.JSONDecodeError(msg="", doc="", pos=1)
+ with self.assertRaises(FileNotJSONFormatError):
+ test_base.get_settings_template()
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_name function.
+ ################################################################################################
+
+ def test_get_name__no_path_passed(self):
+ ''' Check in the names are return correctly when a path is not passed in. '''
+ test_paths = ["test_file", "test_file/", "test_folder/test_file", "test_file.txt"]
+ for test_path in test_paths:
+ with self.subTest(test_path=test_path):
+ test_base = StochSSBase(path=test_path)
+ self.assertEqual(test_base.get_name(), "test_file")
+
+
+ def test_get_name__path_passed(self):
+ ''' Check in the names are return correctly when a path is passed in. '''
+ test_paths = ["test_file", "test_file/", "test_folder/test_file", "test_file.txt"]
+ test_base = StochSSBase(path=self.test_folderpath)
+ for test_path in test_paths:
+ with self.subTest(test_path=test_path):
+ self.assertEqual(test_base.get_name(path=test_path), "test_file")
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_path function.
+ ################################################################################################
+
+ def test_get_path__with_out_user_dir(self):
+ ''' Check if the path is returned w/o the user directory. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ self.assertEqual(test_base.get_path(), self.test_filepath)
+
+ def test_get_path__with_user_dir(self):
+ ''' Check if the path is returneded with the user directory. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ self.assertEqual(test_base.get_path(full=True), os.path.join(self.user_dir, self.test_filepath))
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_dir_name function.
+ ################################################################################################
+
+ def test_get_dir_name__with_out_user_dir__root(self):
+ ''' Check if the dirname is an empty string. '''
+ test_base = StochSSBase(path="test_file")
+ self.assertEqual(test_base.get_dir_name(), "")
+
+
+ def test_get_dir_name__with_out_user_dir__not_root(self):
+ ''' Check if the dirname is returned w/o the user directory. '''
+ test_base = StochSSBase(path="test_folder/test_file")
+ self.assertEqual(test_base.get_dir_name(), "test_folder")
+
+
+ def test_get_dir_name__with_user_dir__root(self):
+ ''' Check if the dirname is the user directory. '''
+ test_base = StochSSBase(path="test_file")
+ self.assertEqual(test_base.get_dir_name(full=True), self.user_dir)
+
+
+ def test_get_dir_name__with_user_dir__not_root(self):
+ ''' Check if the dirname is returned with the user directory. '''
+ test_base = StochSSBase(path="test_folder/test_file")
+ self.assertEqual(test_base.get_dir_name(full=True), os.path.join(self.user_dir, "test_folder"))
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_status function.
+ ################################################################################################
+
+ def test_get_status__ready__no_path_passed(self):
+ ''' Check if ready status is returned when no status file are found and no path is passed in. '''
+ test_base = StochSSBase(path=self.test_folderpath)
+ self.assertEqual(test_base.get_status(), "ready")
+
+
+ def test_get_status__ready__path_passed(self):
+ ''' Check if ready status is returned when no status file are found and a path is passed in. '''
+ test_base = StochSSBase(path=self.test_filepath)
+ self.assertEqual(test_base.get_status(path=self.test_folderpath), "ready")
+
+
+ def test_get_status__other__no_path_passed(self):
+ ''' Check if the status is returned correctly for status files when no path is passed in. '''
+ test_files = ["COMPLETE", "ERROR", "RUNNING"]
+ expected_results = ["complete", "error", "running"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_path = os.path.join(self.test_folderpath, test_file)
+ Path(test_path).touch()
+ test_base = StochSSBase(path=self.test_folderpath)
+ self.assertEqual(test_base.get_status(), expected_results[i])
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_status__other__path_passed(self):
+ ''' Check if the status is returned correctly for status files when no path is passed in. '''
+ test_files = ["COMPLETE", "ERROR", "RUNNING"]
+ expected_results = ["complete", "error", "running"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_path = os.path.join(self.test_folderpath, test_file)
+ Path(test_path).touch()
+ test_base = StochSSBase(path=self.test_filepath)
+ self.assertEqual(test_base.get_status(path=self.test_folderpath), expected_results[i])
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_status__file_not_found_error(self):
+ ''' Check if the StochSSFileNotFoundError is raised when the job is missing. '''
+ test_base = StochSSBase(path=self.test_folderpath)
+ with mock.patch("os.listdir") as mock_folder:
+ mock_folder.side_effect = FileNotFoundError
+ with self.assertRaises(StochSSFileNotFoundError):
+ test_base.get_status()
+
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_unique_path function.
+ ################################################################################################
+
+ def test_get_unique_path__with_out_dirname__dirname_is_root__unique(self):
+ ''' Check if you get the correct unique name for a file in root. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"]
+ for test_file in test_files:
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path="test_base_file")
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertFalse(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, test_file))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_is_root__one_iter(self):
+ ''' Check if you get the correct unique name for a file in root when file already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ test_base = StochSSBase(path="test_base_file")
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_is_root__two_iter(self):
+ ''' Check if you get the correct unique name for a file in root when a file and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt",
+ "test_file(one)(2)", "test_file(one)(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ Path(os.path.join(self.test_folderpath, test_preqs[i])).touch()
+ test_base = StochSSBase(path="test_base_file")
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_is_root__first_iter_removed(self):
+ ''' Check if you get the correct unique name for a file in root when a iter already exists. '''
+ test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"]
+ test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ Path(os.path.join(self.test_folderpath, test_preqs[1])).touch()
+ test_base = StochSSBase(path="test_base_file")
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_not_root__unique(self):
+ ''' Check if you get the correct unique name for a file not in root. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"]
+ for test_file in test_files:
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ test_base = StochSSBase(path=os.path.join("test_folder/test_base_file"))
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertFalse(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", test_file))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_not_root__one_iter(self):
+ ''' Check if you get the correct unique name for a file not in root when file already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch()
+ test_base = StochSSBase(path=os.path.join("test_folder/test_base_file"))
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_not_root__two_iter(self):
+ ''' Check if you get the correct unique name for a file not in root when a file and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt",
+ "test_file(one)(2)", "test_file(one)(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch()
+ Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[i])).touch()
+ test_base = StochSSBase(path=os.path.join("test_folder/test_base_file"))
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_out_dirname__dirname_not_root__first_iter_removed(self):
+ ''' Check if you get the correct unique name for a file not in root when a iter already exists. '''
+ test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"]
+ test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ Path(os.path.join(self.test_folderpath, "test_folder", test_file)).touch()
+ Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[1])).touch()
+ test_base = StochSSBase(path="test_folder/test_base_file")
+ test_base.user_dir = self.test_folderpath
+ unique_path, changed = test_base.get_unique_path(name=test_file)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, "test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_dirname__unique(self):
+ ''' Check if you get the correct unique name for a file. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(2)", "test_file(2).txt", "test_file(one)", "test_file(one).txt"]
+ for test_file in test_files:
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_path, changed = test_base.get_unique_path(name=test_file,
+ dirname=self.test_folderpath)
+ self.assertFalse(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, test_file))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_dirname__one_iter(self):
+ ''' Check if you get the correct unique name for a file when file already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_path, changed = test_base.get_unique_path(name=test_file,
+ dirname=self.test_folderpath)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_dirname__two_iter(self):
+ ''' Check if you get the correct unique name for a file when a file and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file(1)", "test_file(1).txt",
+ "test_file(one)", "test_file(one).txt"]
+ test_preqs = ["test_file(1)", "test_file(1).txt", "test_file(2)", "test_file(2).txt",
+ "test_file(one)(1)", "test_file(one)(1).txt"]
+ expected_results = ["test_file(2)", "test_file(2).txt", "test_file(3)", "test_file(3).txt",
+ "test_file(one)(2)", "test_file(one)(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ Path(os.path.join(self.test_folderpath, test_preqs[i])).touch()
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_path, changed = test_base.get_unique_path(name=test_file,
+ dirname=self.test_folderpath)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_path__with_dirname__dirname__first_iter_removed(self):
+ ''' Check if you get the correct unique name for a file in root when a iter already exists. '''
+ test_files = ["test_file(2)", "test_file(2).txt", "test_file(one)(2)", "test_file(one)(2).txt"]
+ test_preqs = ["test_file", "test_file.txt", "test_file(one)", "test_file(one).txt"]
+ expected_results = ["test_file(1)", "test_file(1).txt", "test_file(one)(1)", "test_file(one)(1).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_file)).touch()
+ Path(os.path.join(self.test_folderpath, test_preqs[1])).touch()
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_path, changed = test_base.get_unique_path(name=test_file,
+ dirname=self.test_folderpath)
+ self.assertTrue(changed)
+ self.assertEqual(unique_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+ ################################################################################################
+ # Unit tests for the StochSS base class get_unique_copy_path function.
+ ################################################################################################
+
+ def test_get_unique_copy_path__with_out_path__dirname_is_root__one_iter(self):
+ ''' Check if you get the correct copy path for a file in root when path already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path=test_file)
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, expected_results[i])
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_out_path__dirname_is_root__two_iter(self):
+ ''' Check if you get the correct copy path for a file in root when path and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_preqs[i])).touch()
+ test_base = StochSSBase(path=test_file)
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, expected_results[i])
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_out_path__dirname_is_root__first_iter_removed(self):
+ ''' Check if you get the correct copy path for a file in root when a iter already exists. '''
+ test_files = ["test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path=test_file)
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, expected_results[i])
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_out_path__dirname_not_root__one_iter(self):
+ ''' Check if you get the correct copy path for a file not in root when path already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ test_base = StochSSBase(path=os.path.join("test_folder", test_file))
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_out_path__dirname_not_root__two_iter(self):
+ ''' Check if you get the correct copy path for a file not in root when path and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ Path(os.path.join(self.test_folderpath, "test_folder", test_preqs[i])).touch()
+ test_base = StochSSBase(path=os.path.join("test_folder", test_file))
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_out_path__dirname_not_root__first_iter_removed(self):
+ ''' Check if you get the correct copy for a file not in root when a iter already exists. '''
+ test_files = ["test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ os.mkdir(os.path.join(self.test_folderpath, "test_folder"))
+ test_base = StochSSBase(path=os.path.join("test_folder", test_file))
+ test_base.user_dir = self.test_folderpath
+ unique_copy_path = test_base.get_unique_copy_path()
+ self.assertEqual(unique_copy_path, os.path.join("test_folder", expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_path__one_iter(self):
+ ''' Check if you get the correct copy path for a file when path already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file))
+ self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_path__two_iter(self):
+ ''' Check if you get the correct copy path for a file when path and iter already exists. '''
+ test_files = ["test_file", "test_file.txt", "test_file-copy", "test_file-copy.txt"]
+ test_preqs = ["test_file-copy", "test_file-copy.txt", "test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy(2)", "test_file-copy(2).txt", "test_file-copy(3)", "test_file-copy(3).txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ Path(os.path.join(self.test_folderpath, test_preqs[i])).touch()
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file))
+ self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+
+ def test_get_unique_copy_path__with_path__first_iter_removed(self):
+ ''' Check if you get the correct copy for a file when a iter already exists. '''
+ test_files = ["test_file-copy(2)", "test_file-copy(2).txt"]
+ expected_results = ["test_file-copy", "test_file-copy.txt"]
+ for i, test_file in enumerate(test_files):
+ with self.subTest(test_file=test_file):
+ test_base = StochSSBase(path=self.test_filepath)
+ unique_copy_path = test_base.get_unique_copy_path(path=os.path.join(self.test_folderpath, test_file))
+ self.assertEqual(unique_copy_path, os.path.join(self.test_folderpath, expected_results[i]))
+ self.tearDown()
+ self.setUp()
+
+ ################################################################################################
+ # Unit tests for the StochSS base class log function.
+ ################################################################################################
+
+ def test_log(self):
+ ''' Check if log is added correctly '''
+ test_base = StochSSBase(path=self.test_filepath)
+ test_log = {"level": "debug", "message": "testing base log"}
+ test_base.log("debug", "testing base log")
+ self.assertIn(test_log, test_base.logs)
+
+ ################################################################################################
+ # Unit tests for the StochSS base class make_parent_dirs function.
+ ################################################################################################
+
+ def test_make_parent_dirs__one_missing_dir(self):
+ ''' Check if the parent directories are made correctly. '''
+ test_path = os.path.join(self.test_folderpath, "test_folder")
+ test_base = StochSSBase(path=self.test_folderpath)
+ with mock.patch('stochss.handlers.util.StochSSBase.get_dir_name') as mock_get_dir_name:
+ mock_get_dir_name.return_value = test_path
+ test_base.make_parent_dirs()
+ self.assertIn("test_folder", os.listdir(self.test_folderpath))
+
+
+ def test_make_parent_dirs__multiple_missing_dir(self):
+ ''' Check if the parent directories are made correctly. '''
+ test_path = os.path.join(self.test_folderpath, "test_folder1", "test_folder2")
+ test_base = StochSSBase(path=self.test_folderpath)
+ with mock.patch('stochss.handlers.util.StochSSBase.get_dir_name') as mock_get_dir_name:
+ mock_get_dir_name.return_value = test_path
+ test_base.make_parent_dirs()
+ self.assertIn("test_folder1", os.listdir(self.test_folderpath))
+ self.assertIn("test_folder2", os.listdir(os.path.join(self.test_folderpath, "test_folder1")))
+
+ ################################################################################################
+ # Unit tests for the StochSS base class print_logs function.
+ ################################################################################################
+
+ def test_print_logs__debug(self):
+ ''' Check if debug log is logged correctly. '''
+ log = logging.getLogger('stochss')
+ test_base = StochSSBase(path=self.test_folderpath)
+ test_base.log("debug", "testing debug log")
+ with mock.patch("stochss.handlers.log.log.debug") as mock_debug_log:
+ test_base.print_logs(log)
+ mock_debug_log.assert_called_once_with("testing debug log")
+
+
+ def test_print_logs__info(self):
+ ''' Check if info log is logged correctly. '''
+ log = logging.getLogger('stochss')
+ test_base = StochSSBase(path=self.test_folderpath)
+ test_base.log("info", "testing info log")
+ with mock.patch("stochss.handlers.log.log.info") as mock_debug_log:
+ test_base.print_logs(log)
+ mock_debug_log.assert_called_once_with("testing info log")
+
+
+ def test_print_logs__warning(self):
+ ''' Check if warning log is logged correctly. '''
+ log = logging.getLogger('stochss')
+ test_base = StochSSBase(path=self.test_folderpath)
+ test_base.log("warning", "testing warning log")
+ with mock.patch("stochss.handlers.log.log.warning") as mock_debug_log:
+ test_base.print_logs(log)
+ mock_debug_log.assert_called_once_with("testing warning log")
+
+
+ def test_print_logs__error(self):
+ ''' Check if error log is logged correctly. '''
+ log = logging.getLogger('stochss')
+ test_base = StochSSBase(path=self.test_folderpath)
+ test_base.log("error", "testing error log")
+ with mock.patch("stochss.handlers.log.log.error") as mock_debug_log:
+ test_base.print_logs(log)
+ mock_debug_log.assert_called_once_with("testing error log")
+
+
+ def test_print_logs__critical(self):
+ ''' Check if critical log is logged correctly. '''
+ log = logging.getLogger('stochss')
+ test_base = StochSSBase(path=self.test_folderpath)
+ test_base.log("critical", "testing critical log")
+ with mock.patch("stochss.handlers.log.log.critical") as mock_debug_log:
+ test_base.print_logs(log)
+ mock_debug_log.assert_called_once_with("testing critical log")
+
+ ################################################################################################
+ # Unit tests for the StochSS base class rename function.
+ ################################################################################################
+
+ def test_rename__unique_name(self):
+ ''' Check if file was renamed to the given name. '''
+ test_path = os.path.join(self.test_folderpath, "test_file")
+ Path(test_path).touch()
+ test_base = StochSSBase(path=test_path)
+ resp = test_base.rename(name="new_test_file")
+ self.assertIsInstance(resp, dict)
+ self.assertFalse(resp['changed'])
+ self.assertEqual(resp['_path'], os.path.join(self.test_folderpath, "new_test_file"))
+
+
+ def test_rename__name_already_exists(self):
+ ''' Check if file was renamed correctly when name is in use. '''
+ test_path = os.path.join(self.test_folderpath, "test_file")
+ Path(test_path).touch()
+ test_preq = os.path.join(self.test_folderpath, "new_test_file")
+ Path(test_preq).touch()
+ test_base = StochSSBase(path=test_path)
+ resp = test_base.rename(name="new_test_file")
+ self.assertIsInstance(resp, dict)
+ self.assertTrue(resp['changed'])
+ self.assertEqual(resp['_path'], os.path.join(self.test_folderpath, "new_test_file(1)"))
+
+
+ def test_rename__file_not_found_error(self):
+ ''' Check if the StochSSFileNotFoundError is raised when the file is missing. '''
+ test_base = StochSSBase(path="test_file")
+ with self.assertRaises(StochSSFileNotFoundError):
+ test_base.rename(name="new_test_file")
+
+
+ def test_rename_permission_error(self):
+ ''' Check if the StochSSPermissionsError is raised when the user doesn't have the correct permissions. '''
+ test_base = StochSSBase(path="test_file")
+ with mock.patch("shutil.move") as mock_move:
+ mock_move.side_effect = PermissionError
+ with self.assertRaises(StochSSPermissionsError):
+ test_base.rename(name="new_test_file")
diff --git a/stochss/tests/test_upload_file.py b/stochss/tests/test_upload_file.py
deleted file mode 100644
index 404c863166..0000000000
--- a/stochss/tests/test_upload_file.py
+++ /dev/null
@@ -1,115 +0,0 @@
-import os
-import unittest
-from unittest import mock
-import tempfile
-from pathlib import Path
-
-from handlers.util.upload_file import *
-
-class TestUploadFile(unittest.TestCase):
-
- #unit tests for method validate_model
-
- def test_validate_model_json_decode_error(self):
- with tempfile.TemporaryDirectory() as tempdir:
- test_file = "non_json_file"
- test_path = os.path.join(tempdir, test_file)
- Path(test_path).touch()
- assert validate_model(test_path, test_file) == \
- (False, False, "The file {0} is not in JSON format.".format(test_file))
-
- def test_validate_model_valid_keys(self):
- test_keys = ("is_spatial", "defaultID", "defaultMode", "modelSettings",
- "simulationSettings", "parameterSweepSettings", "species",
- "parameters", "reactions", "eventsCollection", "rules",
- "functionDefinitions", "meshSettings", "initialConditions")
- class TestKeychain():
- def keys(self):
- return test_keys
-
- complete_keychain = TestKeychain()
- with mock.patch("json.loads", return_value=complete_keychain):
- assert validate_model("", "") == (True, True, "")
-
- def test_validate_model_missing_keys(self):
- test_keys = ("species","parameters","reactions","eventsCollection",
- "rules","functionDefinitions")
-
- class TestKeychain():
- def keys(self):
- return ()
-
- complete_keychain = TestKeychain()
- with mock.patch("json.loads", return_value=complete_keychain):
- assert validate_model("", "") == (False, True, \
- "The following keys are missing from {0}: {1}".format("", ", ".join(test_keys)))
-
- #unit tests for method upload_model_file
-
- def test_upload_model_file_is_valid(self):
- test_valid = True
- test_json = False
- test_error = ""
- predicted_name = ".".join(["some_name", "mdl"])
- with mock.patch("handlers.util.upload_file.get_unique_file_name",\
- return_value=("some_path", False)):
- with mock.patch("handlers.util.upload_file.validate_model",\
- return_value=(test_valid, test_json, test_error)):
- with mock.patch("builtins.open", mock.mock_open(read_data="foo")):
- assert upload_model_file("some_path", "some_file_name", "some_name", None)\
- ['message'] == "{0} was successfully uploaded to {1}".format(\
- predicted_name, "some_path")
-
- def test_upload_model_file_not_valid(self):
- test_valid = False
- test_json = False
- test_error = ""
- predicted_name = ".".join(["some_name", "json"])
- with mock.patch("handlers.util.upload_file.get_unique_file_name",\
- return_value=("some_path", False)):
- with mock.patch("handlers.util.upload_file.validate_model",\
- return_value=(test_valid, test_json, test_error)):
- with mock.patch("builtins.open", mock.mock_open(read_data="foo")):
- assert upload_model_file("some_path",\
- "some_file_name", "some_name", None)['message'] ==\
- "{0} could not be validated as a Model file and was uploaded as {1} to {2}"\
- .format("some_file_name", predicted_name, "some_path")
-
- def test_upload_model_file_error(self):
- test_valid = False
- test_json = False
- test_error = "test_error"
- with mock.patch("handlers.util.upload_file.get_unique_file_name",\
- return_value=("some_path", False)):
- with mock.patch("handlers.util.upload_file.validate_model", return_value=\
- (test_valid, test_json, test_error)):
- with mock.patch("builtins.open", mock.mock_open(read_data="foo")):
- assert upload_model_file("some_path", "some_file_name", "some_name", None)\
- ['errors'] == ['test_error']
-
- def test_upload_model_file_name_changed(self):
- test_valid = False
- test_json = False
- test_error = ""
- predicted_name = "some_file"
- with mock.patch("handlers.util.upload_file.get_unique_file_name",\
- return_value=(os.path.join("some_parent", "some_file"), True)):
- with mock.patch("handlers.util.upload_file.validate_model", \
- return_value=(test_valid, test_json, test_error)):
- with mock.patch("builtins.open", mock.mock_open(read_data="foo")):
- assert upload_model_file("some_path", "some_file_name", "some_name", None)['message'] ==\
- "{0} could not be validated as a Model file and was uploaded as {1} to {2}"\
- .format("some_file_name", predicted_name, "some_path")
-
- def test_upload_model_file_json(self):
- test_valid = True
- test_json = True
- test_error = ""
- with mock.patch("handlers.util.upload_file.get_unique_file_name",\
- return_value=("some_path", False)):
- with mock.patch("handlers.util.upload_file.validate_model", return_value=\
- (test_valid, test_json, test_error)):
- with mock.patch("builtins.open", mock.mock_open(read_data="foo")):
- with mock.patch("json.loads", return_value="mock_return") as mock_json_loads:
- upload_model_file("some_path", "some_file_name", "some_name", None)
- mock_json_loads.assert_called()
diff --git a/stochss/tests/test_workflow_status.py b/stochss/tests/test_workflow_status.py
deleted file mode 100644
index 36e890c31e..0000000000
--- a/stochss/tests/test_workflow_status.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import os
-import unittest
-import tempfile
-from pathlib import Path
-
-from handlers.util.workflow_status import get_status
-
-class TestWorkflow_Status(unittest.TestCase):
-
- #unit tests for method get_status
-
- def test_get_status_complete(self):
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "test_dir")
- os.mkdir(test_path)
- test_status = "COMPLETE"
- test_file = os.path.join(test_path, test_status)
- Path(test_file).touch()
- with mock.patch("os.path.join",return_value = test_path) as mock_join:
- assert get_status("") == "complete"
-
-
- def test_get_status_error(self):
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "test_dir")
- os.mkdir(test_path)
- test_status = "ERROR"
- test_file = os.path.join(test_path, test_status)
- Path(test_file).touch()
- with mock.patch("os.path.join",return_value = test_path) as mock_join:
- assert get_status("") == "error"
-
- def test_get_status_running(self):
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "test_dir")
- os.mkdir(test_path)
- test_status = "RUNNING"
- test_file = os.path.join(test_path, test_status)
- Path(test_file).touch()
- with mock.patch("os.path.join",return_value = test_path) as mock_join:
- assert get_status("") == "running"
-
- def test_get_status_ready(self):
- from unittest import mock
- with tempfile.TemporaryDirectory() as tempdir:
- test_path = os.path.join(tempdir, "test_dir")
- os.mkdir(test_path)
- with mock.patch("os.path.join",return_value = test_path) as mock_join:
- assert get_status("") == "ready"
diff --git a/stochss_templates/nonSpatialModelTemplate.json b/stochss_templates/nonSpatialModelTemplate.json
index 248896e2cc..b48bc4cbd9 100644
--- a/stochss_templates/nonSpatialModelTemplate.json
+++ b/stochss_templates/nonSpatialModelTemplate.json
@@ -6,7 +6,8 @@
"volume": 1,
"modelSettings": {
"endSim": 20,
- "timeStep": 0.05
+ "timeStep": 0.05,
+ "timestepSize": 1e-5
},
"domain": {
"size": null,
@@ -40,5 +41,6 @@
"reactions": [],
"rules": [],
"eventsCollection": [],
- "functionDefinitions": []
+ "functionDefinitions": [],
+ "boundaryConditions": []
}
diff --git a/stochss_templates/workflowSettingsTemplate.json b/stochss_templates/workflowSettingsTemplate.json
index 85bfd2de1a..b1a402f656 100644
--- a/stochss_templates/workflowSettingsTemplate.json
+++ b/stochss_templates/workflowSettingsTemplate.json
@@ -19,6 +19,7 @@
},
"timespanSettings": {
"endSim": 20,
- "timeStep": 0.05
+ "timeStep": 0.05,
+ "timestepSize": 1e-5
}
}
\ No newline at end of file