class @Gush
constructor: -> @workflows = {} @machines = {} initialize: (jobs) -> @registerSockets() @displayCurrentWorkflows() @displayJobsOverview(jobs) registerSockets: -> @registerWorkersSocket() @registerWorkflowsSocket() @registerMachinesSocket() displayCurrentWorkflows: -> $("table.workflows tbody").empty() ($("table.workflows").data("workflows") || []).each (workflow) => @_addWorkflow(workflow) filterJobs: (filter) -> table = $("table.jobs tbody") table.find("tr").hide() if filter == "all" table.find("tr").show() else table.find("tr.#{filter}").show() refreshJobList: -> filter = $('.jobs-filter dd.active a').data('filter') @filterJobs(filter) displayJobsOverview: (jobs) -> if jobs? $("table.jobs tbody").html("") jobs.each (job) -> j = new Job(job) $("table.jobs tbody").append(j.render()) @refreshJobList() registerWorkersSocket: -> workersSocket = new WebSocket(@_socketUrl("subscribe/workers.status")) workersSocket.onopen = @_onOpen workersSocket.onerror = @_onError workersSocket.onmessage = @_onStatus workersSocket.onclose = @_onClose registerWorkflowsSocket: -> workflowsSocket = new WebSocket(@_socketUrl("subscribe/workflows.status")) workflowsSocket.onopen = @_onOpen workflowsSocket.onerror = @_onError workflowsSocket.onmessage = @_onWorkflowStatusChange workflowsSocket.onclose = @_onClose registerMachinesSocket: -> machinesSocket = new WebSocket(@_socketUrl("workers")) machinesSocket.onopen = @_onOpen machinesSocket.onerror = @_onError machinesSocket.onmessage = @_onMachineStatusMessage machinesSocket.onclose = @_onClose registerLogsSocket: (workflow, job) => logsSocket = new WebSocket(@_socketUrl("/logs/#{workflow}.#{job}")) @_registerScrollHook(logsSocket) logsSocket.onopen = @_onOpen logsSocket.onerror = @_onError logsSocket.onmessage = @_onLogsSocketMessage logsSocket.onclose = @_onClose startWorkflow: (workflow, el) -> $.ajax url: "/start/" + workflow, type: "POST", error: (response) -> console.log(response) if el el.removeClass("success") .addClass("alert") .data("action", "stop") .contents().filter -> this.nodeType == 3 .replaceWith("Stop workflow") startJob: (workflow, job, el) -> $.ajax url: "/start/#{workflow}/#{job}", type: "POST", error: (response) -> console.log(response) success: () -> window.location.href = "/show/#{workflow}" stopWorkflow: (workflow, el) -> $.ajax url: "/stop/" + workflow, type: "POST", error: (response) -> console.log(response) if el el.addClass("success") .removeClass("alert") .data("action", "start") .contents().filter -> this.nodeType == 3 .replaceWith("Start workflow") retryWorkflow: (workflow_id) -> $.ajax url: "/show/#{workflow_id}.json", type: "GET", success: (response) => response.jobs.each (job) => if job.failed @startJob(workflow_id, job.name, null) createWorkflow: (workflow) -> $.ajax url: "/create/" + workflow, type: "POST", error: (response) -> console.log(response) success: (response) => window.location.href = "/show/#{response.id}" destroyWorkflow: (workflow) -> $.ajax url: "/destroy/" + workflow, type: "POST", error: (response) -> console.log(response) success: (response) => window.location.href = "/" removeCompleted: -> $.ajax url: "/purge", type: "POST", error: (response) -> console.log(response) success: (response) => window.location.href = "/" removeLogs: (workflow_id, job_name) -> $.ajax url: "/purge_logs/#{workflow_id}.#{job_name}", type: "POST", error: (response) -> console.log(response) success: (response) => window.location.href = "/jobs/#{workflow_id}.#{job_name}" _onOpen: -> $("#modalBox").foundation("reveal", "close"); _onError: (error) -> $("#modalBox .data").html("<h2>Lost connection with server.</h2> <h3>Reconnecting…</h3>"); $("#modalBox").foundation("reveal", "open"); _onClose: -> console.log("Connection closed"); _onStatus: (message) => message = JSON.parse(message.data) console.log message switch message.status when "started" @_onJobStart(message) when "finished" @_onJobSuccess(message) when "heartbeat" @_onJobHeartbeat(message) when "failed" @_onJobFail(message) else console.error("Unkown job status:", message.status, "data: ", message) _onWorkflowStatusChange: (message) => message = JSON.parse(message.data) workflow = @workflows[message.workflow_id] if workflow workflow.changeStatus(message.status) workflow.updateDates(message) $("table.workflows").find("##{message.workflow_id}").replaceWith(workflow.render()) _onMachineStatusMessage: (message) => message = JSON.parse(message.data) message.each (machine) => machine = @machines[message.id] ||= new Machine(machine, $("table.machines tbody")) machine.markAsAlive() machine.render() _onJobStart: (message) => @_updateGraphStatus(message.workflow_id) _onJobSuccess: (message) => @_updateGraphStatus(message.workflow_id) workflow = @workflows[message.workflow_id] if workflow workflow.updateProgress() $("table.workflows").find("##{message.workflow_id}").replaceWith(workflow.render()) _onJobHeartbeat: (message) => _onJobFail: (message) => @_updateGraphStatus(message.workflow_id) workflow = @workflows[message.workflow_id] if workflow workflow.markAsFailed() $("table.workflows").find("##{message.workflow_id}").replaceWith(workflow.render()) _addWorkflow: (data) => workflow = new Workflow(data) @workflows[data.id] = workflow $("table.workflows").append(workflow.render()) _updateGraphStatus: (workflow_id) -> $.ajax url: "/show/#{workflow_id}.json", type: "GET", error: (response) -> console.log(response) success: (response) => graph = new Graph("canvas-#{workflow_id}") @displayJobsOverview(response.jobs) response.jobs.each (job) -> klasses = switch when job.failed then "status-finished status-failed" when job.finished then "status-finished" when job.enqueued then "status-enqueued" graph.markNode(job.name, klasses) _socketUrl: (path) -> "ws://#{window.location.host}/#{path}" _scrollToBottom: (container) -> container.scrollTop(container.prop('scrollHeight')) _preservePosition: (container, originalHeight) -> container.scrollTop(container.prop('scrollHeight') - originalHeight) _onLogsSocketMessage: (message) => container = $('ul.logs') originalHeight = container.prop('scrollHeight') logs = JSON.parse(message.data) logs.lines.forEach (log) => container[logs.method]("<li>#{log}</li>") if logs.method is "append" @_scrollToBottom(container) else @_preservePosition(container, originalHeight) _registerScrollHook: (logsSocket) -> container = $('ul.logs') container.scroll (e) -> if container.scrollTop() < 30 logsSocket.send("prepend")