Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/job-view/job-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ module.exports = View.extend({
},
render: function (attrs, options) {
View.prototype.render.apply(this, arguments);
if(this.model.status !== "error") {
if(this.model.status === "complete") {
this.renderResultsView();
}
if(!this.readOnly) {
if(!this.readOnly && this.model.status !== "running") {
this.renderLogsView();
}
this.renderSettingsView();
Expand Down
7 changes: 7 additions & 0 deletions client/models/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ module.exports = State.extend({
// timeZone = timeZone.replace('(', '').replace(')', '') // remove the '()' from the timezone
return stamp + hours + ":" + minutes + " " + ampm + " " + timeZone;
}
},
sortTime: {
deps: ["startTime"],
fn: function () {
let date = new Date(this.startTime);
return Math.round(date.getTime() / 1000);
}
}
}
});
3 changes: 2 additions & 1 deletion client/models/jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ let Collection = require('ampersand-collection');
let Job = require('./job');

module.exports = Collection.extend({
model: Job
model: Job,
comparator: 'sortTime'
});
63 changes: 46 additions & 17 deletions client/pages/workflow-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ let WorkflowManager = PageView.extend({
'click [data-target=start-job]' : 'clickStartJobHandler',
'click [data-hook=edit-model]' : 'clickEditModelHandler',
'click [data-hook=collapse-jobs]' : 'changeCollapseButtonText',
'click [data-hook=return-to-project-btn]' : 'handleReturnToProject'
'click [data-hook=return-to-project-btn]' : 'handleReturnToProject',
'click [data-hook=manual-view-control]' : 'setActiveJobViewControl'
},
initialize: function (attrs, options) {
PageView.prototype.initialize.apply(this, arguments);
let urlParams = new URLSearchParams(window.location.search);
let jobID = urlParams.has('job') ? urlParams.get('job') : null;
this.viewingActiveJob = false;
this.model = new Workflow({
directory: urlParams.get('path')
});
Expand Down Expand Up @@ -227,8 +229,9 @@ let WorkflowManager = PageView.extend({
this.jobListingView = this.renderCollection(
this.model.jobs,
JobListingView,
this.queryByHook("job-listing")
this.queryByHook("job-listing"),
);
this.setActiveJobIndicator();
},
renderModelLocationSelectView: function (model) {
if(this.modelLocationSelectView) {
Expand Down Expand Up @@ -287,14 +290,13 @@ let WorkflowManager = PageView.extend({
}else if(this.model.activeJob.status !== "ready") {
this.renderStatusView();
}
let detailsStatus = ["error", "complete"];
if(jobID !== null) {
let activeJob = this.model.jobs.filter((job) => { return job.name === jobID; })[0] || null;
if(activeJob !== null) {
this.model.activeJob = activeJob;
}
}
if(this.model.activeJob && detailsStatus.includes(this.model.activeJob.status)) {
if(this.model.activeJob) {
this.renderActiveJob();
}
},
Expand All @@ -309,8 +311,20 @@ let WorkflowManager = PageView.extend({
setActiveJob: function (job) {
this.removeActiveJob();
this.model.activeJob = job;
this.viewingActiveJob = false;
this.setActiveJobViewControl();
this.renderActiveJob();
},
setActiveJobIndicator: function () {
this.jobListingView.views.forEach((view) => {
view.updateActiveJob(this.model.activeJob.directory);
});
},
setActiveJobViewControl: function (e) {
this.viewingActiveJob = !this.viewingActiveJob;
$(this.queryByHook("manual-view-control")).text(this.viewingActiveJob ? "Finished" : "View");
this.setActiveJobIndicator();
},
setupSettingsView: function () {
if(!this.model.newFormat) {
$(this.queryByHook("of-start-job")).css('display', 'inline-block');
Expand Down Expand Up @@ -375,31 +389,46 @@ let WorkflowManager = PageView.extend({
let runEndpoint = `${path.join(app.getApiPath(), "workflow/run-job")}${runQuery}`;
app.getXHR(runEndpoint, {
success: (err, response, body) => {
this.updateWorkflow(true);
this.updateWorkflow({newJob: true});
}
});
}
});
},
updateWorkflow: function (newJob) {
let self = this;
updateWorkflow: function ({newJob=false}={}) {
if(this.model.newFormat) {
let hadActiveJob = Boolean(this.model.activeJob.status)
app.getXHR(this.model.url(), {
success: function (err, response, body) {
self.model.set({jobs: body.jobs, activeJob: body.activeJob});
if(!Boolean(self.model.activeJob.status)){
self.removeActiveJob();
}else if(!hadActiveJob && Boolean(self.model.activeJob.status)) {
self.renderActiveJob();
success: (err, response, body) => {
this.model.set({jobs: body.jobs});
if(newJob || this.viewingActiveJob) {
setTimeout(() => { this.setActiveJobIndicator(); });
}else if (!Boolean(body.activeJob.status)) {
this.removeActiveJob();
}else {
this.model.set({activeJob: body.activeJob});
this.setActiveJobViewControl();
this.renderActiveJob();
}
if(newJob) {
setTimeout(() => { this.setActiveJobIndicator(); });
}else {
if(!Boolean(this.model.activeJob.status)) {
this.removeActiveJob();
}else if(!this.viewingActiveJob){
this.model.set({activeJob: body.activeJob});
this.renderActiveJob();
this.setActiveJobViewControl();
}else {
setTimeout(() => { this.setActiveJobIndicator(); });
}
}
}
});
}else if(!this.model.newFormat){
app.getXHR(this.model.url(), {
success: function (err, response, body) {
self.model.set(body)
self.renderSubviews();
success: (err, response, body) => {
this.model.set(body)
this.renderSubviews();
}
});
}
Expand Down
3 changes: 2 additions & 1 deletion client/settings-view/views/well-mixed-settings-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ module.exports = View.extend({
}else {
if(!this.model.isAutomatic){
$(this.queryByHook('select-ode')).prop('checked', Boolean(this.model.algorithm === "ODE"));
$(this.queryByHook('select-ssa')).prop('checked', Boolean(this.model.algorithm === "SSA"));
$(this.queryByHook('select-ssa')).prop('checked', Boolean(this.model.algorithm === "SSA"));
$(this.queryByHook('select-cle')).prop('checked', Boolean(this.model.algorithm === "CLE"));
$(this.queryByHook('select-tau-leaping')).prop('checked', Boolean(this.model.algorithm === "Tau-Leaping"));
$(this.queryByHook('select-hybrid-tau')).prop('checked', Boolean(this.model.algorithm === "Hybrid-Tau-Leaping"));
}else{
Expand Down
17 changes: 16 additions & 1 deletion client/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -884,4 +884,19 @@ input:checked + .slider:before {
position: absolute;
left: 15px;
top: 40%;
}
}

.active-job-listing {
background-color: rgba(0, 255, 255, 1.0);
}

.job-listing-btn {
color: rgb(108, 117, 125);
background-color: rgb(255, 255, 255) !important;
}

.job-listing-btn:hover {
color: rgb(255, 255, 255);
background-color: rgb(108, 117, 125) !important;
}

24 changes: 13 additions & 11 deletions client/templates/includes/jobListing.pug
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@ div(data-hook=this.model.elementID)
if(this.model.collection.indexOf(this.model) !== 0)
hr

div.row
div.py-1.pl-1(data-hook="is-active-job")

div.col-md-3
div.row

button.btn.btn-outline-secondary.box-shadow(data-hook=this.model.elementID + "-open" style="width: 100%")=this.model.name
div.col-md-3

div.col-md-4
button.btn.btn-outline-secondary.box-shadow.job-listing-btn(data-hook=this.model.elementID + "-open" style="width: 100%")=this.model.name

div.py-2=this.model.fmtStartTime
div.col-md-4

div.col-md-3
div.py-2=this.model.fmtStartTime

div.py-2
div.col-md-3

div.inline(data-hook=this.model.elementID + "-status")=this.model.status
div.py-2

div.inline.spinner-border.status(data-hook=this.model.elementID + "-running-spinner")
div.inline(data-hook=this.model.elementID + "-status")=this.model.status

div.col-md-2
div.inline.spinner-border.status(data-hook=this.model.elementID + "-running-spinner")

button.btn.btn-outline-secondary.box-shadow(data-hook=this.model.elementID + "-remove") X
div.col-md-2

button.btn.btn-outline-secondary.box-shadow.job-listing-btn(data-hook=this.model.elementID + "-remove") X
8 changes: 7 additions & 1 deletion client/templates/pages/workflowManager.pug
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,13 @@ section.page

div.mt-4(data-hook="active-job-header-container" style="display: none")

h2(data-hook="active-job-header") Job:
div.inline

h2(data-hook="active-job-header") Job:

div.mr-3.inline(style="float: right;")

button.btn.btn-outline-secondary.box-shadow(data-hook="manual-view-control") View

div(data-hook="active-job-container")

Expand Down
14 changes: 13 additions & 1 deletion client/views/job-listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,15 @@ module.exports = View.extend({
},
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
this.isActiveJob = false;
console.log(this.model.startTime, this.model.sortTime)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console log again, might want to remove

},
render: function (attrs, options) {
View.prototype.render.apply(this, arguments);
if(this.isActiveJob) {
$(this.queryByHook("is-active-job")).addClass("active-job-listing");
}
if(this.model.status === "running") {
$(this.queryByHook(this.model.elementID + "-open")).prop("disabled", true);
this.getJobStatus();
}else{
$(this.queryByHook(this.model.elementID + '-running-spinner')).css('display', "none")
Expand Down Expand Up @@ -80,5 +84,13 @@ module.exports = View.extend({
},
openActiveJob: function (e) {
this.parent.setActiveJob(this.model);
},
updateActiveJob: function (activeJob) {
this.isActiveJob = Boolean(activeJob) && activeJob === this.model.directory;
if(this.isActiveJob) {
$(this.queryByHook("is-active-job")).addClass("active-job-listing");
}else {
$(this.queryByHook("is-active-job")).removeClass("active-job-listing");
}
}
});
14 changes: 8 additions & 6 deletions client/views/workflow-group-listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ module.exports = View.extend({
initialize: function (attrs, options) {
View.prototype.initialize.apply(this, arguments);
let links = [];
this.model.model.refLinks.forEach((link) => {
links.push(
`<a class="text-break" href='stochss/workflow/edit?path=${link.path}&type=none'>${link.name}</a>`
);
});
this.htmlLinks = links.join('')
if(this.model.model.refLinks) {
this.model.model.refLinks.forEach((link) => {
links.push(
`<a class="text-break" href='stochss/workflow/edit?path=${link.path}&type=none'>${link.name}</a>`
);
});
}
this.htmlLinks = links.join('');
},
render: function (attrs, options) {
View.prototype.render.apply(this, arguments);
Expand Down
2 changes: 1 addition & 1 deletion jupyterhub/.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ JUPYTER_CONFIG_DIR=/opt/stochss-config/.jupyter

#AUTH_CLASS=jupyterhub.auth.DummyAuthenticator

JUPYTERHUB_VERSION=1.1.0
JUPYTERHUB_VERSION=3.1.1

DOCKER_HUB_IMAGE=stochss-hub

Expand Down
12 changes: 12 additions & 0 deletions stochss/handlers/util/stochss_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,18 @@ def get_time_stamp(self):
return time_stamp
return None

def get_update_time(self):
os.chdir(self.get_path(full=True))
if os.path.exists("COMPLETE"):
mod_time = os.path.getctime("COMPLETE")
elif os.path.exists("ERROR"):
mod_time = os.path.getctime("ERROR")
elif os.path.exists("RUNNING"):
mod_time = os.path.getctime("RUNNING")
else:
mod_time = None
os.chdir(self.user_dir)
return mod_time

def load(self, new=False):
'''
Expand Down
15 changes: 8 additions & 7 deletions stochss/handlers/util/stochss_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,21 @@ def __load_annotation(self):

def __load_jobs(self):
self.workflow['jobs'] = []
time = 0
mrm_time = 0
last_job = None
for file_obj in os.listdir(self.get_path(full=True)):
if file_obj.startswith("job_"):
path = os.path.join(self.path, file_obj)
job = StochSSJob(path=path).load()
self.workflow['jobs'].append(job)
if os.path.getmtime(path) > time and job['status'] != "running":
time = os.path.getmtime(path)
last_job = job
job = StochSSJob(path=path)
self.workflow['jobs'].append(job.load())
cm_time = job.get_update_time()
if cm_time > mrm_time:
mrm_time = cm_time
last_job = len(self.workflow['jobs']) - 1
if last_job is None:
self.workflow['activeJob'] = None
else:
self.workflow['activeJob'] = last_job
self.workflow['activeJob'] = self.workflow['jobs'][last_job]


def __load_settings(self):
Expand Down