diff --git a/SingularityUI/app/collections/RequestHistoricalTasks.coffee b/SingularityUI/app/collections/RequestHistoricalTasks.coffee index 044ea21255..c26103d3ed 100644 --- a/SingularityUI/app/collections/RequestHistoricalTasks.coffee +++ b/SingularityUI/app/collections/RequestHistoricalTasks.coffee @@ -4,7 +4,7 @@ PaginableCollection = require './PaginableCollection' class HistoricalTasks extends PaginableCollection model: class TaskHistoryItem extends Backbone.Model - ignoreAttributes: ['id'] + ignoreAttributes: ['id', 'canBeRunNow'] url: -> "#{ config.apiRoot }/history/request/#{ @requestId }/tasks" diff --git a/SingularityUI/app/controllers/RequestDetail.coffee b/SingularityUI/app/controllers/RequestDetail.coffee index d91896df47..4207566c70 100644 --- a/SingularityUI/app/controllers/RequestDetail.coffee +++ b/SingularityUI/app/controllers/RequestDetail.coffee @@ -56,7 +56,7 @@ class RequestDetailController extends Controller @subviews.header = new SimpleSubview model: @models.request template: @templates.header - + # would have used header subview for this info, # but header expects a request model that # no longer exists if a request is deleted @@ -109,6 +109,10 @@ class RequestDetailController extends Controller app.showView @view + addRequestInfo: => + for t in @collections.taskHistory.models + t.attributes.canBeRunNow = @models.request.attributes.canBeRunNow + refresh: -> requestFetch = @models.request.fetch() @@ -124,7 +128,7 @@ class RequestDetailController extends Controller @collections.activeTasks.fetch().error @ignore404 @collections.scheduledTasks.fetch().error @ignore404 @collections.scheduledTasks.fetch({reset: true}).error @ignore404 - + if @collections.requestHistory.currentPage is 1 requestHistoryFetch = @collections.requestHistory.fetch() requestHistoryFetch.error => @ignore404 @@ -133,8 +137,11 @@ class RequestDetailController extends Controller if @collections.requestHistory.length is 0 app.router.notFound() - if @collections.taskHistory.currentPage is 1 - @collections.taskHistory.fetch().error @ignore404 + requestFetch.done => + if @collections.taskHistory.currentPage is 1 + @collections.taskHistory.fetch + error: @ignore404 + success: @addRequestInfo if @collections.deployHistory.currentPage is 1 @collections.deployHistory.fetch().error @ignore404 diff --git a/SingularityUI/app/models/Request.coffee b/SingularityUI/app/models/Request.coffee index 164ea19551..d5ea48e670 100644 --- a/SingularityUI/app/models/Request.coffee +++ b/SingularityUI/app/models/Request.coffee @@ -7,6 +7,7 @@ runTemplate = require '../templates/vex/requestRun' removeTemplate = require '../templates/vex/requestRemove' bounceTemplate = require '../templates/vex/requestBounce' exitCooldownTemplate = require '../templates/vex/exitCooldown' +TaskHistory = require '../models/TaskHistory' class Request extends Model @@ -74,7 +75,7 @@ class Request extends Model options.processData = false $.ajax options - + scale: (confirmedOrPromptData) => $.ajax url: "#{ @url() }/instances?user=#{ app.getUsername() }" @@ -83,7 +84,7 @@ class Request extends Model data: JSON.stringify id: @get "id" instances: confirmedOrPromptData - + bounce: => $.ajax url: "#{ @url() }/bounce?user=#{ app.getUsername() }" @@ -114,7 +115,7 @@ class Request extends Model promptScale: (callback) => vex.dialog.prompt - message: scaleTemplate + message: scaleTemplate id: @get "id" buttons: [ $.extend _.clone(vex.dialog.buttons.YES), text: 'Scale' @@ -134,8 +135,12 @@ class Request extends Model promptRun: (callback) => vex.dialog.prompt - message: "" - input: runTemplate id: @get "id" + message: "

Run Task

" + input: runTemplate + id: @get "id" + prefix: @localStorageCommandLineInputKeyPrefix + commands: localStorage.getItem(@localStorageCommandLineInputKeyPrefix + @id) + buttons: [ $.extend _.clone(vex.dialog.buttons.YES), text: 'Run now' vex.dialog.buttons.NO @@ -143,7 +148,7 @@ class Request extends Model beforeClose: => return if @data is false - + fileName = @data.filename.trim() commandLineInput = @data.commandLineInput.trim() @@ -152,7 +157,16 @@ class Request extends Model return false else - localStorage.setItem(@localStorageCommandLineInputKeyPrefix + @id, commandLineInput) if commandLineInput? + history = localStorage.getItem(@localStorageCommandLineInputKeyPrefix + @id) + + if history? + last = history.split(",")[history.split(",").length - 1] + history += "," + else + history = "" + + if commandLineInput != last + localStorage.setItem(@localStorageCommandLineInputKeyPrefix + @id, history + commandLineInput) if commandLineInput? localStorage.setItem('taskRunRedirectFilename', fileName) if filename? localStorage.setItem('taskRunAutoTail', @data.autoTail) @data.id = @get 'id' @@ -160,14 +174,64 @@ class Request extends Model @run( @data.commandLineInput ).done callback( @data ) return true - afterOpen: => + afterOpen: => $('#filename').val localStorage.getItem('taskRunRedirectFilename') - $('#commandLineInput').val localStorage.getItem(@localStorageCommandLineInputKeyPrefix + @id) $('#autoTail').prop 'checked', (localStorage.getItem('taskRunAutoTail') is 'on') + cmdString = localStorage.getItem(@localStorageCommandLineInputKeyPrefix + @id) + commands = if cmdString then cmdString.split(",").reverse() else [] + $('#commandLineInput').val commands[0] + localStorage.setItem(@localStorageCommandLineInputKeyPrefix + "historyIndex", 0); + localStorage.setItem(@localStorageCommandLineInputKeyPrefix + "historyLength", commands.length); callback: (data) => @data = data + + promptRerun: (taskId, callback) => + task = new TaskHistory {taskId} + task.fetch() + .done => + command = task.attributes.task.taskRequest.pendingTask.cmdLineArgsList + vex.dialog.prompt + message: "

Rerun Task

" + input: runTemplate + id: @get "id" + command: command + buttons: [ + $.extend _.clone(vex.dialog.buttons.YES), text: 'Run now' + vex.dialog.buttons.NO + ] + + beforeClose: => + return if @data is false + + fileName = @data.filename.trim() + commandLineInput = @data.commandLineInput.trim() + + if fileName.length is 0 and @data.autoTail is 'on' + $(window.noFilenameError).removeClass('hide') + return false + + else + localStorage.setItem('taskRunRedirectFilename', fileName) if filename? + localStorage.setItem('taskRunAutoTail', @data.autoTail) + @data.id = @get 'id' + + @run( @data.commandLineInput ).done callback( @data ) + return true + + afterOpen: => + $('#filename').val localStorage.getItem('taskRunRedirectFilename') + if command is "" + history = localStorage.getItem(@localStorageCommandLineInputKeyPrefix + @id) + if !!history + history = history.split(",") + $('#commandLineInput').val history[history.length - 1] + $('#autoTail').prop 'checked', (localStorage.getItem('taskRunAutoTail') is 'on') + + callback: (data) => + @data = data + promptRemove: (callback) => vex.dialog.confirm message: removeTemplate id: @get "id" diff --git a/SingularityUI/app/templates/deployDetail/deployInfo.hbs b/SingularityUI/app/templates/deployDetail/deployInfo.hbs index 48e63d9f15..401f970095 100644 --- a/SingularityUI/app/templates/deployDetail/deployInfo.hbs +++ b/SingularityUI/app/templates/deployDetail/deployInfo.hbs @@ -4,57 +4,81 @@
diff --git a/SingularityUI/app/templates/requestDetail/requestHistoricalTasks.hbs b/SingularityUI/app/templates/requestDetail/requestHistoricalTasks.hbs index 46cecba758..af47aebbfa 100644 --- a/SingularityUI/app/templates/requestDetail/requestHistoricalTasks.hbs +++ b/SingularityUI/app/templates/requestDetail/requestHistoricalTasks.hbs @@ -27,6 +27,9 @@ {{! Actions }} + + {{! Actions }} + @@ -53,9 +56,18 @@ - ... + ··· + {{#if canBeRunNow}} + + + ↺ + + + {{else}} + + {{/if}} { } diff --git a/SingularityUI/app/templates/taskDetail/taskInfo.hbs b/SingularityUI/app/templates/taskDetail/taskInfo.hbs index e9a4480d48..923ce7d9dc 100644 --- a/SingularityUI/app/templates/taskDetail/taskInfo.hbs +++ b/SingularityUI/app/templates/taskDetail/taskInfo.hbs @@ -44,5 +44,21 @@ {{/if}} + {{#if data.task.taskRequest.deploy.executorData.extraCmdLineArgs}} +
  • +
    +

    Extra Cmd Line Arguments (for Deploy)

    +

    {{ data.task.taskRequest.deploy.executorData.extraCmdLineArgs }}

    +
    +
  • + {{/if}} + {{#if data.task.taskRequest.pendingTask.cmdLineArgsList }} +
  • +
    +

    Extra Cmd Line Arguments (for Task)

    +

    {{ data.task.taskRequest.pendingTask.cmdLineArgsList }}

    +
    +
  • + {{/if}} diff --git a/SingularityUI/app/templates/vex/requestRun.hbs b/SingularityUI/app/templates/vex/requestRun.hbs index e582a2c563..6d221841c9 100644 --- a/SingularityUI/app/templates/vex/requestRun.hbs +++ b/SingularityUI/app/templates/vex/requestRun.hbs @@ -3,7 +3,7 @@

    Additional command line input: (optional)

    - +

    diff --git a/SingularityUI/app/views/request.coffee b/SingularityUI/app/views/request.coffee index 85578a295e..2b1b161814 100644 --- a/SingularityUI/app/views/request.coffee +++ b/SingularityUI/app/views/request.coffee @@ -16,6 +16,7 @@ class RequestView extends View 'click [data-action="remove"]': 'removeRequest' 'click [data-action="run-request-now"]': 'runRequest' + 'click [data-action="rerun-task"]': 'rerunTask' 'click [data-action="pause"]': 'pauseRequest' 'click [data-action="scale"]': 'scaleRequest' 'click [data-action="unpause"]': 'unpauseRequest' @@ -76,6 +77,23 @@ class RequestView extends View @trigger 'refreshrequest' setTimeout ( => @trigger 'refreshrequest'), 2500 + rerunTask: (e) => + taskId = e.target.getAttribute 'data-taskId' + @model.promptRerun taskId, (data) => + # If user wants to redirect to a file after the task starts + if data.autoTail is 'on' + autoTailer = new AutoTailer({ + requestId: @requestId + autoTailFilename: data.filename + autoTailTimestamp: +new Date() + }) + + autoTailer.startAutoTailPolling() + + else + @trigger 'refreshrequest' + setTimeout ( => @trigger 'refreshrequest'), 2500 + scaleRequest: (e) => @model.promptScale => @trigger 'refreshrequest'