mirror of
https://github.com/ansible/awx.git
synced 2026-03-07 11:41:08 -03:30
Added manual controls for zooming/panning the workflow graph
This commit is contained in:
@@ -14,6 +14,7 @@ import workflowEdit from './workflows/edit-workflow/main';
|
|||||||
import labels from './labels/main';
|
import labels from './labels/main';
|
||||||
import workflowChart from './workflows/workflow-chart/main';
|
import workflowChart from './workflows/workflow-chart/main';
|
||||||
import workflowMaker from './workflows/workflow-maker/main';
|
import workflowMaker from './workflows/workflow-maker/main';
|
||||||
|
import workflowControls from './workflows/workflow-controls/main';
|
||||||
import templatesListRoute from './list/templates-list.route';
|
import templatesListRoute from './list/templates-list.route';
|
||||||
import workflowService from './workflows/workflow.service';
|
import workflowService from './workflows/workflow.service';
|
||||||
import templateCopyService from './copy-template/template-copy.service';
|
import templateCopyService from './copy-template/template-copy.service';
|
||||||
@@ -21,7 +22,7 @@ import templateCopyService from './copy-template/template-copy.service';
|
|||||||
export default
|
export default
|
||||||
angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesAdd.name,
|
angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesAdd.name,
|
||||||
jobTemplatesEdit.name, labels.name, workflowAdd.name, workflowEdit.name,
|
jobTemplatesEdit.name, labels.name, workflowAdd.name, workflowEdit.name,
|
||||||
workflowChart.name, workflowMaker.name
|
workflowChart.name, workflowMaker.name, workflowControls.name
|
||||||
])
|
])
|
||||||
.service('TemplatesService', templatesService)
|
.service('TemplatesService', templatesService)
|
||||||
.service('WorkflowService', workflowService)
|
.service('WorkflowService', workflowService)
|
||||||
|
|||||||
@@ -14,16 +14,12 @@ export default [ '$state',
|
|||||||
addNode: '&',
|
addNode: '&',
|
||||||
editNode: '&',
|
editNode: '&',
|
||||||
deleteNode: '&',
|
deleteNode: '&',
|
||||||
|
workflowZoomed: '&',
|
||||||
mode: '@'
|
mode: '@'
|
||||||
},
|
},
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
link: function(scope, element) {
|
link: function(scope, element) {
|
||||||
|
|
||||||
scope.$watch('canAddWorkflowJobTemplate', function() {
|
|
||||||
// Redraw the graph if permissions change
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
|
|
||||||
let margin = {top: 20, right: 20, bottom: 20, left: 20},
|
let margin = {top: 20, right: 20, bottom: 20, left: 20},
|
||||||
width = 950,
|
width = 950,
|
||||||
height = 590 - margin.top - margin.bottom,
|
height = 590 - margin.top - margin.bottom,
|
||||||
@@ -31,8 +27,7 @@ export default [ '$state',
|
|||||||
rectW = 120,
|
rectW = 120,
|
||||||
rectH = 60,
|
rectH = 60,
|
||||||
rootW = 60,
|
rootW = 60,
|
||||||
rootH = 40,
|
rootH = 40;
|
||||||
m = [40, 240, 40, 240];
|
|
||||||
|
|
||||||
let tree = d3.layout.tree()
|
let tree = d3.layout.tree()
|
||||||
.size([height, width]);
|
.size([height, width]);
|
||||||
@@ -41,6 +36,19 @@ export default [ '$state',
|
|||||||
.x(function(d){return d.x;})
|
.x(function(d){return d.x;})
|
||||||
.y(function(d){return d.y;});
|
.y(function(d){return d.y;});
|
||||||
|
|
||||||
|
let zoomObj = d3.behavior.zoom().scaleExtent([0.5, 2]);
|
||||||
|
|
||||||
|
let baseSvg = d3.select(element[0]).append("svg")
|
||||||
|
.attr("width", width)
|
||||||
|
.attr("height", height)
|
||||||
|
.attr("class", "WorkflowChart-svg")
|
||||||
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
||||||
|
.call(zoomObj
|
||||||
|
.on("zoom", naturalZoom)
|
||||||
|
);
|
||||||
|
|
||||||
|
let svgGroup = baseSvg.append("g");
|
||||||
|
|
||||||
function lineData(d){
|
function lineData(d){
|
||||||
|
|
||||||
let sourceX = d.source.isStartNode ? d.source.y + rootW : d.source.y + rectW;
|
let sourceX = d.source.isStartNode ? d.source.y + rootW : d.source.y + rectW;
|
||||||
@@ -76,33 +84,55 @@ export default [ '$state',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let baseSvg = d3.select(element[0]).append("svg")
|
// This is the zoom function called by using the mousewheel/click and drag
|
||||||
.attr("width", width)
|
function naturalZoom() {
|
||||||
.attr("height", height)
|
|
||||||
.attr("class", "WorkflowChart-svg")
|
|
||||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
|
||||||
.call(d3.behavior.zoom()
|
|
||||||
.scaleExtent([0.5, 5])
|
|
||||||
.on("zoom", zoom)
|
|
||||||
);
|
|
||||||
|
|
||||||
let svgGroup = baseSvg.append("g");
|
|
||||||
|
|
||||||
function zoom() {
|
|
||||||
let scale = d3.event.scale,
|
let scale = d3.event.scale,
|
||||||
translation = d3.event.translate,
|
translation = d3.event.translate;
|
||||||
tbound = -height * scale,
|
|
||||||
bbound = height * scale,
|
|
||||||
lbound = (-width + m[1]) * scale,
|
|
||||||
rbound = (width - m[3]) * scale;
|
|
||||||
// limit translation to thresholds
|
|
||||||
translation = [
|
|
||||||
Math.max(Math.min(translation[0], rbound), lbound),
|
|
||||||
Math.max(Math.min(translation[1], bbound), tbound)
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
svgGroup.attr("transform", "translate(" + translation + ")scale(" + scale + ")");
|
svgGroup.attr("transform", "translate(" + translation + ")scale(" + scale + ")");
|
||||||
|
|
||||||
|
scope.workflowZoomed({
|
||||||
|
zoom: scale
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the zoom that gets called when the user interacts with the manual zoom controls
|
||||||
|
function manualZoom(zoom) {
|
||||||
|
let scale = zoom / 100,
|
||||||
|
translation = zoomObj.translate(),
|
||||||
|
origZoom = zoomObj.scale(),
|
||||||
|
unscaledOffsetX = (translation[0] + ((width*origZoom) - width)/2)/origZoom,
|
||||||
|
unscaledOffsetY = (translation[1] + ((height*origZoom) - height)/2)/origZoom,
|
||||||
|
translateX = unscaledOffsetX*scale - ((scale*width)-width)/2,
|
||||||
|
translateY = unscaledOffsetY*scale - ((scale*height)-height)/2;
|
||||||
|
|
||||||
|
svgGroup.attr("transform", "translate(" + [translateX, translateY] + ")scale(" + scale + ")");
|
||||||
|
zoomObj.scale(scale);
|
||||||
|
zoomObj.translate([translateX, translateY]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function manualPan(direction) {
|
||||||
|
let scale = zoomObj.scale(),
|
||||||
|
distance = 150 * scale,
|
||||||
|
translateX,
|
||||||
|
translateY,
|
||||||
|
translateCoords = zoomObj.translate();
|
||||||
|
if (direction === 'left' || direction === 'right') {
|
||||||
|
translateX = direction === 'left' ? translateCoords[0] - distance : translateCoords[0] + distance;
|
||||||
|
translateY = translateCoords[1];
|
||||||
|
} else if (direction === 'up' || direction === 'down') {
|
||||||
|
translateX = translateCoords[0];
|
||||||
|
translateY = direction === 'up' ? translateCoords[1] - distance : translateCoords[1] + distance;
|
||||||
|
}
|
||||||
|
svgGroup.attr("transform", "translate(" + translateX + "," + translateY + ")scale(" + scale + ")");
|
||||||
|
zoomObj.translate([translateX, translateY]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetZoomAndPan() {
|
||||||
|
svgGroup.attr("transform", "translate(" + 0 + "," + 0 + ")scale(" + 1 + ")");
|
||||||
|
// Update the zoomObj
|
||||||
|
zoomObj.scale(1);
|
||||||
|
zoomObj.translate([0,0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
@@ -637,10 +667,27 @@ export default [ '$state',
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.$watch('canAddWorkflowJobTemplate', function() {
|
||||||
|
// Redraw the graph if permissions change
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
scope.$on('refreshWorkflowChart', function(){
|
scope.$on('refreshWorkflowChart', function(){
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scope.$on('panWorkflowChart', function(evt, params) {
|
||||||
|
manualPan(params.direction);
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.$on('resetWorkflowChart', function(){
|
||||||
|
resetZoomAndPan();
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.$on('zoomWorkflowChart', function(evt, params) {
|
||||||
|
manualZoom(params.zoom);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2016 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
import workflowControls from './workflow-controls.directive';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('workflowControls', [])
|
||||||
|
.directive('workflowControls', workflowControls);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
@import "./client/src/shared/branding/colors.default.less";
|
||||||
|
|
||||||
|
.WorkflowControls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.WorkflowControls-Zoom {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan {
|
||||||
|
flex: 0 0 85px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--button {
|
||||||
|
color: @default-icon;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--button:hover {
|
||||||
|
color: @default-link-hov;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--home {
|
||||||
|
position: relative;
|
||||||
|
top: 9px;
|
||||||
|
right: 38px;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--up {
|
||||||
|
position: relative;
|
||||||
|
top: -4px;
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--down {
|
||||||
|
position: relative;
|
||||||
|
top: 25px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--right {
|
||||||
|
position: relative;
|
||||||
|
top: 12px;
|
||||||
|
right: 7px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Pan--left {
|
||||||
|
position: relative;
|
||||||
|
top: 12px;
|
||||||
|
right: 31px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Zoom--button {
|
||||||
|
line-height: 60px;
|
||||||
|
color: @default-icon;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Zoom--button:hover {
|
||||||
|
color: @default-link-hov;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Zoom--minus {
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-Zoom--plus {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-zoomSlider {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
.WorkflowControls-zoomPercentage {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.7em;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2016 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
export default ['templateUrl',
|
||||||
|
function(templateUrl) {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
panChart: '&',
|
||||||
|
resetChart: '&',
|
||||||
|
zoomChart: '&'
|
||||||
|
},
|
||||||
|
templateUrl: templateUrl('templates/workflows/workflow-controls/workflow-controls'),
|
||||||
|
restrict: 'E',
|
||||||
|
link: function(scope) {
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
scope.zoom = 100;
|
||||||
|
$( "#slider" ).slider({
|
||||||
|
value:100,
|
||||||
|
min: 50,
|
||||||
|
max: 200,
|
||||||
|
step: 10,
|
||||||
|
slide: function( event, ui ) {
|
||||||
|
scope.zoom = ui.value;
|
||||||
|
scope.zoomChart({
|
||||||
|
zoom: scope.zoom
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.pan = function(direction) {
|
||||||
|
scope.panChart({
|
||||||
|
direction: direction
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.reset = function() {
|
||||||
|
scope.zoom = 100;
|
||||||
|
$("#slider").slider('value',scope.zoom);
|
||||||
|
scope.resetChart();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.zoomIn = function() {
|
||||||
|
scope.zoom = Math.ceil((scope.zoom + 10) / 10) * 10 < 200 ? Math.ceil((scope.zoom + 10) / 10) * 10 : 200;
|
||||||
|
$("#slider").slider('value',scope.zoom);
|
||||||
|
scope.zoomChart({
|
||||||
|
zoom: scope.zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.zoomOut = function() {
|
||||||
|
scope.zoom = Math.floor((scope.zoom - 10) / 10) * 10 > 50 ? Math.floor((scope.zoom - 10) / 10) * 10 : 50;
|
||||||
|
$("#slider").slider('value',scope.zoom);
|
||||||
|
scope.zoomChart({
|
||||||
|
zoom: scope.zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.$on('workflowZoomed', function(evt, params) {
|
||||||
|
scope.zoom = Math.round(params.zoom * 10) * 10;
|
||||||
|
$("#slider").slider('value',scope.zoom);
|
||||||
|
});
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="WorkflowControls-Zoom">
|
||||||
|
<div class="WorkflowControls-Zoom--button WorkflowControls-Zoom--minus" ng-click="zoomOut()">
|
||||||
|
<i class="fa fa-minus" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowControls-zoomSlider">
|
||||||
|
<div class="WorkflowControls-zoomPercentage">{{zoom}}%</div>
|
||||||
|
<div id="slider"></div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowControls-Zoom--button WorkflowControls-Zoom--plus" ng-click="zoomIn()">
|
||||||
|
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowControls-Pan">
|
||||||
|
<i class="fa fa-caret-up WorkflowControls-Pan--button WorkflowControls-Pan--up" ng-click="pan('up')"></i>
|
||||||
|
<i class="fa fa-caret-down WorkflowControls-Pan--button WorkflowControls-Pan--down" ng-click="pan('down')"></i>
|
||||||
|
<i class="fa fa-caret-left WorkflowControls-Pan--button WorkflowControls-Pan--left" ng-click="pan('left')"></i>
|
||||||
|
<i class="fa fa-caret-right WorkflowControls-Pan--button WorkflowControls-Pan--right" ng-click="pan('right')"></i>
|
||||||
|
<i class="fa fa-home WorkflowControls-Pan--button WorkflowControls-Pan--home" ng-click="reset()"></i>
|
||||||
|
</div>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
}
|
}
|
||||||
.WorkflowMaker-contentHolder {
|
.WorkflowMaker-contentHolder {
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px solid #EBEBEB;
|
border: 1px solid @default-list-header-bg;
|
||||||
height: ~"calc(100% - 85px)";
|
height: ~"calc(100% - 85px)";
|
||||||
}
|
}
|
||||||
.WorkflowMaker-contentLeft {
|
.WorkflowMaker-contentLeft {
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
}
|
}
|
||||||
.WorkflowMaker-contentRight {
|
.WorkflowMaker-contentRight {
|
||||||
flex: 0 0 400px;
|
flex: 0 0 400px;
|
||||||
border-left: 1px solid #EBEBEB;
|
border-left: 1px solid @default-list-header-bg;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@@ -120,14 +120,14 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.WorkflowMaker-formHelp {
|
.WorkflowMaker-formHelp {
|
||||||
color: #707070;
|
color: @default-interface-txt;
|
||||||
}
|
}
|
||||||
.WorkflowMaker-formLists {
|
.WorkflowMaker-formLists {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.WorkflowMaker-formTitle {
|
.WorkflowMaker-formTitle {
|
||||||
display: flex;
|
display: flex;
|
||||||
color: #707070;
|
color: @default-interface-txt;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
.WorkflowMaker-formLabel {
|
.WorkflowMaker-formLabel {
|
||||||
@@ -140,13 +140,13 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.WorkflowMaker-totalJobs {
|
.WorkflowMaker-totalJobs {
|
||||||
margin-right: 10px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-maker {
|
.WorkflowLegend-maker {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
color: #707070;
|
color: @default-interface-txt;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-maker--left {
|
.WorkflowLegend-maker--left {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
flex: 0 0 170px;
|
flex: 0 0 170px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-onSuccessLegend {
|
.WorkflowLegend-onSuccessLegend {
|
||||||
height: 4px;
|
height: 4px;
|
||||||
@@ -167,21 +168,21 @@
|
|||||||
.WorkflowLegend-onFailLegend {
|
.WorkflowLegend-onFailLegend {
|
||||||
height: 4px;
|
height: 4px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
background-color: #d9534f;
|
background-color: @default-err;
|
||||||
margin: 18px 5px 18px 0px;
|
margin: 18px 5px 18px 0px;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-alwaysLegend {
|
.WorkflowLegend-alwaysLegend {
|
||||||
height: 4px;
|
height: 4px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
background-color: #337ab7;
|
background-color: @default-link;
|
||||||
margin: 18px 5px 18px 0px;
|
margin: 18px 5px 18px 0px;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-letterCircle{
|
.WorkflowLegend-letterCircle{
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background: #848992;
|
background: @default-icon;
|
||||||
color: #FFF;
|
color: @default-bg;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 10px 5px 10px 0px;
|
margin: 10px 5px 10px 0px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
@@ -191,7 +192,7 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
border: 1px solid #F6F6F6;
|
border: 1px solid @default-no-items-bord;
|
||||||
margin-top:10px;
|
margin-top:10px;
|
||||||
}
|
}
|
||||||
.WorkflowLegend-legendItem {
|
.WorkflowLegend-legendItem {
|
||||||
@@ -200,3 +201,45 @@
|
|||||||
.WorkflowLegend-legendItem:not(:last-child) {
|
.WorkflowLegend-legendItem:not(:last-child) {
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
}
|
}
|
||||||
|
.WorkflowLegend-details--left {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
.WorkflowLegend-details--right {
|
||||||
|
flex: 0 0 44px;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 20px;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
.WorkflowMaker-manualControlsIcon {
|
||||||
|
color: @default-icon;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.WorkflowMaker-manualControlsIcon:hover {
|
||||||
|
color: @default-link-hov;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.WorkflowMaker-manualControlsIcon--active {
|
||||||
|
color: @default-link-hov;
|
||||||
|
}
|
||||||
|
.WorkflowMaker-manualControls {
|
||||||
|
position: absolute;
|
||||||
|
left: -122px;
|
||||||
|
height: 60px;
|
||||||
|
width: 293px;
|
||||||
|
background-color: @default-bg;
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid @default-list-header-bg;
|
||||||
|
}
|
||||||
|
.WorkflowLegend-manualControls {
|
||||||
|
position: absolute;
|
||||||
|
left: -245px;
|
||||||
|
top: 38px;
|
||||||
|
height: 60px;
|
||||||
|
width: 290px;
|
||||||
|
background-color: @default-bg;
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid @default-list-header-bg;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$scope.treeDataMaster = angular.copy($scope.treeData.data);
|
$scope.treeDataMaster = angular.copy($scope.treeData.data);
|
||||||
|
$scope.showManualControls = false;
|
||||||
$scope.$broadcast("refreshWorkflowChart");
|
$scope.$broadcast("refreshWorkflowChart");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +575,32 @@ export default ['$scope', 'WorkflowService', 'generateList', 'TemplateList', 'Pr
|
|||||||
edgeFlags: $scope.edgeFlags
|
edgeFlags: $scope.edgeFlags
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.toggleManualControls = function() {
|
||||||
|
$scope.showManualControls = !$scope.showManualControls;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.panChart = function(direction) {
|
||||||
|
$scope.$broadcast('panWorkflowChart', {
|
||||||
|
direction: direction
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.zoomChart = function(zoom) {
|
||||||
|
$scope.$broadcast('zoomWorkflowChart', {
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.resetChart = function() {
|
||||||
|
$scope.$broadcast('resetWorkflowChart');
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.workflowZoomed = function(zoom) {
|
||||||
|
$scope.$broadcast('workflowZoomed', {
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,13 @@
|
|||||||
<div class="WorkflowLegend-maker--right">
|
<div class="WorkflowLegend-maker--right">
|
||||||
<span class="WorkflowMaker-totalJobs">TOTAL JOBS</span>
|
<span class="WorkflowMaker-totalJobs">TOTAL JOBS</span>
|
||||||
<span class="badge List-titleBadge" ng-bind="treeData.data.totalNodes"></span>
|
<span class="badge List-titleBadge" ng-bind="treeData.data.totalNodes"></span>
|
||||||
|
<i ng-class="{'WorkflowMaker-manualControlsIcon--active': showManualControls}" class="fa fa-cog WorkflowMaker-manualControlsIcon" aria-hidden="true" alt="Controls" ng-click="toggleManualControls()"></i>
|
||||||
|
<div ng-show="showManualControls" class="WorkflowMaker-manualControls noselect">
|
||||||
|
<workflow-controls class="WorkflowControls" pan-chart="panChart(direction)" zoom-chart="zoomChart(zoom)" reset-chart="resetChart()"></workflow-controls>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<workflow-chart tree-data="treeData.data" add-node="startAddNode(parent, betweenTwoNodes)" edit-node="startEditNode(nodeToEdit)" delete-node="startDeleteNode(nodeToDelete)" can-add-workflow-job-template="canAddWorkflowJobTemplate" mode="edit" class="WorkflowMaker-chart"></workflow-chart>
|
<workflow-chart tree-data="treeData.data" add-node="startAddNode(parent, betweenTwoNodes)" edit-node="startEditNode(nodeToEdit)" delete-node="startDeleteNode(nodeToDelete)" workflow-zoomed="workflowZoomed(zoom)" can-add-workflow-job-template="canAddWorkflowJobTemplate" mode="edit" class="WorkflowMaker-chart"></workflow-chart>
|
||||||
</div>
|
</div>
|
||||||
<div class="WorkflowMaker-contentRight">
|
<div class="WorkflowMaker-contentRight">
|
||||||
<div class="WorkflowMaker-formTitle">{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited) ? ((nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "EDIT TEMPLATE") : "ADD A TEMPLATE"}}</div>
|
<div class="WorkflowMaker-formTitle">{{(workflowMakerFormConfig.nodeMode === 'edit' && nodeBeingEdited) ? ((nodeBeingEdited.unifiedJobTemplate && nodeBeingEdited.unifiedJobTemplate.name) ? nodeBeingEdited.unifiedJobTemplate.name : "EDIT TEMPLATE") : "ADD A TEMPLATE"}}</div>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export default ['workflowData',
|
|||||||
$scope.workflow_nodes = workflowNodes;
|
$scope.workflow_nodes = workflowNodes;
|
||||||
$scope.workflowOptions = workflowDataOptions.actions.GET;
|
$scope.workflowOptions = workflowDataOptions.actions.GET;
|
||||||
$scope.labels = jobLabels;
|
$scope.labels = jobLabels;
|
||||||
|
$scope.showManualControls = false;
|
||||||
|
|
||||||
// turn related api browser routes into tower routes
|
// turn related api browser routes into tower routes
|
||||||
getTowerLinks();
|
getTowerLinks();
|
||||||
@@ -111,6 +112,32 @@ export default ['workflowData',
|
|||||||
workflowResultsService.relaunchJob($scope);
|
workflowResultsService.relaunchJob($scope);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.toggleManualControls = function() {
|
||||||
|
$scope.showManualControls = !$scope.showManualControls;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.panChart = function(direction) {
|
||||||
|
$scope.$broadcast('panWorkflowChart', {
|
||||||
|
direction: direction
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.zoomChart = function(zoom) {
|
||||||
|
$scope.$broadcast('zoomWorkflowChart', {
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.resetChart = function() {
|
||||||
|
$scope.$broadcast('resetWorkflowChart');
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.workflowZoomed = function(zoom) {
|
||||||
|
$scope.$broadcast('workflowZoomed', {
|
||||||
|
zoom: zoom
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
$scope.$on(`ws-workflow_events-${$scope.workflow.id}`, function(e, data) {
|
$scope.$on(`ws-workflow_events-${$scope.workflow.id}`, function(e, data) {
|
||||||
|
|||||||
@@ -217,26 +217,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<workflow-status-bar></workflow-status-bar>
|
<workflow-status-bar></workflow-status-bar>
|
||||||
<div class="WorkflowLegend-details">
|
<div class="WorkflowLegend-details">
|
||||||
<div class="WorkflowLegend-legendItem">KEY:</div>
|
<div class="WorkflowLegend-details--left">
|
||||||
<div class="WorkflowLegend-legendItem">
|
<div class="WorkflowLegend-legendItem">KEY:</div>
|
||||||
<div class="WorkflowLegend-onSuccessLegend"></div>
|
<div class="WorkflowLegend-legendItem">
|
||||||
<div>On Success</div>
|
<div class="WorkflowLegend-onSuccessLegend"></div>
|
||||||
|
<div>On Success</div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowLegend-legendItem">
|
||||||
|
<div class="WorkflowLegend-onFailLegend"></div>
|
||||||
|
<div>On Fail</div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowLegend-legendItem">
|
||||||
|
<div class="WorkflowLegend-alwaysLegend"></div>
|
||||||
|
<div>Always</div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowLegend-legendItem">
|
||||||
|
<div class="WorkflowLegend-letterCircle">P</div>
|
||||||
|
<div>Project Sync</div>
|
||||||
|
</div>
|
||||||
|
<div class="WorkflowLegend-legendItem">
|
||||||
|
<div class="WorkflowLegend-letterCircle">I</div>
|
||||||
|
<div>Inventory Sync</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="WorkflowLegend-legendItem">
|
<div class="WorkflowLegend-details--right">
|
||||||
<div class="WorkflowLegend-onFailLegend"></div>
|
<i ng-class="{'WorkflowMaker-manualControlsIcon--active': showManualControls}" class="fa fa-cog WorkflowMaker-manualControlsIcon" aria-hidden="true" alt="Controls" ng-click="toggleManualControls()"></i>
|
||||||
<div>On Fail</div>
|
<div ng-show="showManualControls" class="WorkflowLegend-manualControls noselect">
|
||||||
</div>
|
<workflow-controls class="WorkflowControls" pan-chart="panChart(direction)" zoom-chart="zoomChart(zoom)" reset-chart="resetChart()"></workflow-controls>
|
||||||
<div class="WorkflowLegend-legendItem">
|
</div>
|
||||||
<div class="WorkflowLegend-alwaysLegend"></div>
|
|
||||||
<div>Always</div>
|
|
||||||
</div>
|
|
||||||
<div class="WorkflowLegend-legendItem">
|
|
||||||
<div class="WorkflowLegend-letterCircle">P</div>
|
|
||||||
<div>Project Sync</div>
|
|
||||||
</div>
|
|
||||||
<div class="WorkflowLegend-legendItem">
|
|
||||||
<div class="WorkflowLegend-letterCircle">I</div>
|
|
||||||
<div>Inventory Sync</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<workflow-chart tree-data="treeData.data" can-add-workflow-job-template="canAddWorkflowJobTemplate" mode="details" class="WorkflowMaker-chart"></workflow-chart>
|
<workflow-chart tree-data="treeData.data" can-add-workflow-job-template="canAddWorkflowJobTemplate" mode="details" class="WorkflowMaker-chart"></workflow-chart>
|
||||||
|
|||||||
Reference in New Issue
Block a user