From 5fe066124e42c18e06230e97b459f6e05ae28355 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Thu, 1 Dec 2016 11:45:32 -0500 Subject: [PATCH 1/2] Added details link to running/already finished running nodes --- .../workflow-chart/workflow-chart.block.less | 9 +- .../workflow-chart.directive.js | 144 ++++++++++++------ .../workflow-maker.partial.html | 2 +- .../templates/workflows/workflow.service.js | 10 +- .../workflow-results.controller.js | 3 +- .../workflow-results.partial.html | 2 +- 6 files changed, 116 insertions(+), 54 deletions(-) diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less index 1ee7d1b444..db51a1b8de 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less @@ -20,9 +20,12 @@ fill: @default-err-hov; } -.node .WorkflowChart-defaultText { +.node { font-size: 12px; font-family: 'Open Sans', sans-serif; +} + +.WorkflowChart-defaultText { fill: @default-interface-txt; } @@ -76,3 +79,7 @@ .workflowChart-nodeStatus--failed { fill: @default-err; } +.WorkflowChart-detailsLink { + fill: @default-link; + cursor: pointer; +} diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js index aad3fe4034..2b6a8037f7 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js @@ -4,8 +4,8 @@ * All Rights Reserved *************************************************/ -export default [ - function() { +export default [ '$state', + function($state) { return { scope: { @@ -13,7 +13,8 @@ export default [ canAddWorkflowJobTemplate: '=', addNode: '&', editNode: '&', - deleteNode: '&' + deleteNode: '&', + mode: '@' }, restrict: 'E', link: function(scope, element) { @@ -64,8 +65,11 @@ export default [ // TODO: this function is hacky and we need to come up with a better solution // see: http://stackoverflow.com/questions/15975440/add-ellipses-to-overflowing-text-in-svg#answer-27723752 function wrap(text) { - if(text && text.length > 15) { - return text.substring(0,15) + '...'; + + let maxLength = scope.mode === 'details' ? 14 : 15; + + if(text && text.length > maxLength) { + return text.substring(0,maxLength) + '...'; } else { return text; @@ -156,11 +160,12 @@ export default [ .attr("class", function(d) { return d.placeholder ? "rect placeholder" : "rect"; }); + thisNode.append("text") - .attr("x", rectW / 2) - .attr("y", rectH / 2) + .attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 20 : rectW / 2; }) + .attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 10 : rectH / 2; }) .attr("dy", ".35em") - .attr("text-anchor", "middle") + .attr("text-anchor", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? "inherit" : "middle"; }) .attr("class", "WorkflowChart-defaultText WorkflowChart-nameText") .text(function (d) { return (d.unifiedJobTemplate && d.unifiedJobTemplate.name) ? d.unifiedJobTemplate.name : ""; @@ -199,6 +204,16 @@ export default [ .classed("hovering", false); } }); + thisNode.append("text") + .attr("x", rectW - 50) + .attr("y", rectH - 10) + .attr("dy", ".35em") + .attr("class", "WorkflowChart-detailsLink") + .style("display", function(d){ return d.job && d.job.jobStatus && d.job.unified_job_id ? null : "none"; }) + .text(function () { + return "DETAILS"; + }) + .call(details); thisNode.append("circle") .attr("id", function(d){return "node-" + d.id + "-add";}) .attr("cx", rectW) @@ -288,27 +303,29 @@ export default [ let statusClass = "WorkflowChart-nodeStatus "; - switch(d.jobStatus) { - case "pending": - statusClass = "workflowChart-nodeStatus--running"; - break; - case "waiting": - statusClass = "workflowChart-nodeStatus--running"; - break; - case "running": - statusClass = "workflowChart-nodeStatus--running"; - break; - case "successful": - statusClass = "workflowChart-nodeStatus--success"; - break; - case "failed": - statusClass = "workflowChart-nodeStatus--failed"; - break; + if(d.job){ + switch(d.job.jobStatus) { + case "pending": + statusClass = "workflowChart-nodeStatus--running"; + break; + case "waiting": + statusClass = "workflowChart-nodeStatus--running"; + break; + case "running": + statusClass = "workflowChart-nodeStatus--running"; + break; + case "successful": + statusClass = "workflowChart-nodeStatus--success"; + break; + case "failed": + statusClass = "workflowChart-nodeStatus--failed"; + break; + } } return statusClass; }) - .style("display", function(d) { return d.jobStatus ? null : "none"; }) + .style("display", function(d) { return d.job && d.job.jobStatus ? null : "none"; }) .attr("cy", 10) .attr("cx", 10) .attr("r", 6); @@ -456,11 +473,6 @@ export default [ return d.placeholder ? "rect placeholder" : "rect"; }); - t.selectAll(".WorkflowChart-nameText") - .text(function (d) { - return (d.unifiedJobTemplate && d.unifiedJobTemplate.name) ? wrap(d.unifiedJobTemplate.name) : ""; - }); - t.selectAll(".node") .attr("transform", function(d) {d.px = d.x; d.py = d.y; return "translate(" + d.y + "," + d.x + ")"; }); @@ -478,32 +490,34 @@ export default [ let statusClass = "WorkflowChart-nodeStatus "; - switch(d.jobStatus) { - case "pending": - statusClass += "workflowChart-nodeStatus--running"; - break; - case "waiting": - statusClass += "workflowChart-nodeStatus--running"; - break; - case "running": - statusClass += "workflowChart-nodeStatus--running"; - break; - case "successful": - statusClass += "workflowChart-nodeStatus--success"; - break; - case "failed": - statusClass += "workflowChart-nodeStatus--failed"; - break; + if(d.job){ + switch(d.job.jobStatus) { + case "pending": + statusClass += "workflowChart-nodeStatus--running"; + break; + case "waiting": + statusClass += "workflowChart-nodeStatus--running"; + break; + case "running": + statusClass += "workflowChart-nodeStatus--running"; + break; + case "successful": + statusClass += "workflowChart-nodeStatus--success"; + break; + case "failed": + statusClass += "workflowChart-nodeStatus--failed"; + break; + } } return statusClass; }) - .style("display", function(d) { return d.jobStatus ? null : "none"; }) + .style("display", function(d) { return d.job && d.job.jobStatus ? null : "none"; }) .transition() .duration(0) .attr("r", 6) .each(function(d) { - if(d.jobStatus && (d.jobStatus === "pending" || d.jobStatus === "waiting" || d.jobStatus === "running")) { + if(d.job && d.job.jobStatus && (d.job.jobStatus === "pending" || d.job.jobStatus === "waiting" || d.job.jobStatus === "running")) { // Pulse the circle var circle = d3.select(this); (function repeat() { @@ -519,6 +533,18 @@ export default [ } }); + t.selectAll(".WorkflowChart-nameText") + .attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 20 : rectW / 2; }) + .attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? 10 : rectH / 2; }) + .attr("text-anchor", function(d){ return (scope.mode === 'details' && d.job && d.job.jobStatus) ? "inherit" : "middle"; }) + .text(function (d) { + return (d.unifiedJobTemplate && d.unifiedJobTemplate.name) ? wrap(d.unifiedJobTemplate.name) : ""; + }); + + t.selectAll(".WorkflowChart-detailsLink") + .style("display", function(d){ return d.job && d.job.jobStatus && d.job.unified_job_id ? null : "none"; }); + + } function add_node() { @@ -563,6 +589,28 @@ export default [ }); } + function details() { + this.on("mouseover", function() { + d3.select(this).style("text-decoration", "underline"); + }); + this.on("mouseout", function() { + d3.select(this).style("text-decoration", null); + }); + this.on("click", function(d) { + if(d.job.unified_job_id && d.unifiedJobTemplate) { + if(d.unifiedJobTemplate.unified_job_type === 'job') { + $state.go('jobDetail', {id: d.job.unified_job_id}); + } + else if(d.unifiedJobTemplate.unified_job_type === 'inventory_update') { + $state.go('inventorySyncStdout', {id: d.job.unified_job_id}); + } + else if(d.unifiedJobTemplate.unified_job_type === 'project_update') { + $state.go('scmUpdateStdout', {id: d.job.unified_job_id}); + } + } + }); + } + scope.$on('refreshWorkflowChart', function(){ update(); }); diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html index 77cdd18d9c..8674576710 100644 --- a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html +++ b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.partial.html @@ -60,7 +60,7 @@ - +
{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited && nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "ADD A TEMPLATE"}}
diff --git a/awx/ui/client/src/templates/workflows/workflow.service.js b/awx/ui/client/src/templates/workflows/workflow.service.js index 8150b52005..6dce55f179 100644 --- a/awx/ui/client/src/templates/workflows/workflow.service.js +++ b/awx/ui/client/src/templates/workflows/workflow.service.js @@ -221,7 +221,10 @@ export default [function(){ } if(params.nodesObj[params.nodeId].summary_fields.job) { - treeNode.jobStatus = params.nodesObj[params.nodeId].summary_fields.job.status; + treeNode.job = { + jobStatus: params.nodesObj[params.nodeId].summary_fields.job.status, + unified_job_id: params.nodesObj[params.nodeId].summary_fields.job.id + }; } // Loop across the success nodes and add them recursively @@ -271,7 +274,10 @@ export default [function(){ }); if(matchingNode) { - matchingNode.jobStatus = params.status; + matchingNode.job = { + jobStatus: params.status, + unified_job_id: params.unified_job_id + }; } } diff --git a/awx/ui/client/src/workflow-results/workflow-results.controller.js b/awx/ui/client/src/workflow-results/workflow-results.controller.js index 1c4aee2ade..d80385141c 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.controller.js +++ b/awx/ui/client/src/workflow-results/workflow-results.controller.js @@ -118,7 +118,8 @@ export default ['workflowData', WorkflowService.updateStatusOfNode({ treeData: $scope.treeData, nodeId: data.workflow_node_id, - status: data.status + status: data.status, + unified_job_id: data.unified_job_id }); $scope.$broadcast("refreshWorkflowChart"); diff --git a/awx/ui/client/src/workflow-results/workflow-results.partial.html b/awx/ui/client/src/workflow-results/workflow-results.partial.html index f8266f74f8..38b6eee6ca 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.partial.html +++ b/awx/ui/client/src/workflow-results/workflow-results.partial.html @@ -216,7 +216,7 @@
- + From b93ca08b8c8597b5d2ef68ee32d719e0c151cd8c Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Thu, 1 Dec 2016 12:01:41 -0500 Subject: [PATCH 2/2] Fix unit test failures --- awx/ui/tests/spec/job-results/job-results.controller-test.js | 2 +- awx/ui/tests/spec/smart-search/queryset.service-test.js | 2 +- awx/ui/tests/spec/workflows/workflow-add.controller-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/awx/ui/tests/spec/job-results/job-results.controller-test.js b/awx/ui/tests/spec/job-results/job-results.controller-test.js index 5114bf64c8..b334ea5ecc 100644 --- a/awx/ui/tests/spec/job-results/job-results.controller-test.js +++ b/awx/ui/tests/spec/job-results/job-results.controller-test.js @@ -67,7 +67,7 @@ describe('Controller: jobResultsController', () => { .respond(''); $httpBackend - .whenGET('/api/') + .whenGET('/api') .respond(200, ''); $scope = $rootScope.$new(); diff --git a/awx/ui/tests/spec/smart-search/queryset.service-test.js b/awx/ui/tests/spec/smart-search/queryset.service-test.js index 54f9794e41..b932925171 100644 --- a/awx/ui/tests/spec/smart-search/queryset.service-test.js +++ b/awx/ui/tests/spec/smart-search/queryset.service-test.js @@ -29,7 +29,7 @@ describe('Service: QuerySet', () => { // @todo: improve appsource // provide api version via package.json config block $httpBackend - .whenGET('/api/') + .whenGET('/api') .respond(200, ''); })); diff --git a/awx/ui/tests/spec/workflows/workflow-add.controller-test.js b/awx/ui/tests/spec/workflows/workflow-add.controller-test.js index 87eae5e019..e4ec2d6562 100644 --- a/awx/ui/tests/spec/workflows/workflow-add.controller-test.js +++ b/awx/ui/tests/spec/workflows/workflow-add.controller-test.js @@ -81,7 +81,7 @@ describe('Controller: WorkflowAdd', () => { ToJSON = _ToJSON_; httpBackend - .whenGET('/api/') + .whenGET('/api') .respond(200, ''); TemplatesService.getLabelOptions = jasmine.createSpy('getLabelOptions').and.returnValue(getLabelsDeferred.promise);