mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 12:20:45 -03:30
Add initial support for workflow pause approve
This commit is contained in:
parent
82e0b2121b
commit
0720857022
@ -117,7 +117,7 @@ function TemplatesStrings (BaseString) {
|
||||
TOTAL_NODES: t.s('TOTAL NODES'),
|
||||
ADD_A_NODE: t.s('ADD A NODE'),
|
||||
EDIT_TEMPLATE: t.s('EDIT TEMPLATE'),
|
||||
JOBS: t.s('JOBS'),
|
||||
JOBS: t.s('Jobs'),
|
||||
PLEASE_CLICK_THE_START_BUTTON: t.s('Please click the start button to build your workflow.'),
|
||||
PLEASE_HOVER_OVER_A_TEMPLATE: t.s('Please hover over a template for additional options.'),
|
||||
EDIT_LINK_TOOLTIP: t.s('Click to edit link'),
|
||||
@ -144,7 +144,8 @@ function TemplatesStrings (BaseString) {
|
||||
UNSAVED_CHANGES_PROMPT_TEXT: t.s('Are you sure you want to exit the Workflow Creator without saving your changes?'),
|
||||
EXIT: t.s('EXIT'),
|
||||
CANCEL: t.s('CANCEL'),
|
||||
SAVE_AND_EXIT: t.s('SAVE & EXIT')
|
||||
SAVE_AND_EXIT: t.s('SAVE & EXIT'),
|
||||
PAUSE_NODE: t.s('Pause Node')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1981,11 +1981,6 @@ tr td button i {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.select2-container {
|
||||
margin-left: 2px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.form-control + .select2-container--disabled .select2-selection {
|
||||
background-color: @ebgrey !important;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@import 'action/_index';
|
||||
@import 'approvalsDrawer/_index';
|
||||
@import 'dialog/_index';
|
||||
@import 'input/_index';
|
||||
@import 'launchTemplateButton/_index';
|
||||
|
||||
56
awx/ui/client/lib/components/approvalsDrawer/_index.less
Normal file
56
awx/ui/client/lib/components/approvalsDrawer/_index.less
Normal file
@ -0,0 +1,56 @@
|
||||
.at-ApprovalsDrawer {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 540px;
|
||||
background-color: white;
|
||||
z-index: 1000000;
|
||||
animation-duration: 0.5s;
|
||||
// TODO: fix animation?
|
||||
// animation-name: slidein;
|
||||
padding: 20px;
|
||||
box-shadow: -3px 0px 8px -2px #aaaaaa;
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
flex: 1 0 auto;
|
||||
color: #606060;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
width: calc(82%);
|
||||
}
|
||||
|
||||
&-exit {
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
|
||||
button {
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
color: #D7D7D7;
|
||||
line-height: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
button:hover{
|
||||
color: @default-icon;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slidein {
|
||||
from {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
to {
|
||||
width: 540px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
const templateUrl = require('~components/approvalsDrawer/approvalsDrawer.partial.html');
|
||||
|
||||
function AtApprovalsDrawerController (strings, Rest, GetBasePath, $rootScope) {
|
||||
const vm = this || {};
|
||||
|
||||
const toolbarSortDefault = {
|
||||
label: `${strings.get('sort.CREATED_ASCENDING')}`,
|
||||
value: 'created'
|
||||
};
|
||||
|
||||
vm.toolbarSortValue = toolbarSortDefault;
|
||||
|
||||
// This will probably need to be expanded
|
||||
vm.toolbarSortOptions = [
|
||||
toolbarSortDefault,
|
||||
{ label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }
|
||||
];
|
||||
|
||||
vm.queryset = {
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
vm.emptyListReason = strings.get('approvals.NONE');
|
||||
|
||||
const loadTheList = () => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}?page_size=5&order_by=created&status=pending`);
|
||||
Rest.get()
|
||||
.then(({ data }) => {
|
||||
vm.dataset = data;
|
||||
vm.approvals = data.results;
|
||||
vm.count = data.count;
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
vm.listLoaded = true;
|
||||
});
|
||||
};
|
||||
|
||||
loadTheList();
|
||||
|
||||
vm.onToolbarSort = (sort) => {
|
||||
vm.toolbarSortValue = sort;
|
||||
|
||||
// TODO: this...
|
||||
// const queryParams = Object.assign(
|
||||
// {},
|
||||
// $state.params.user_search,
|
||||
// paginateQuerySet,
|
||||
// { order_by: sort.value }
|
||||
// );
|
||||
|
||||
// // Update URL with params
|
||||
// $state.go('.', {
|
||||
// user_search: queryParams
|
||||
// }, { notify: false, location: 'replace' });
|
||||
|
||||
// rather than ^^ we want to just re-load the data based on new params
|
||||
};
|
||||
|
||||
vm.approve = (approval) => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}${approval.id}/approve`);
|
||||
Rest.post()
|
||||
.then(() => loadTheList());
|
||||
};
|
||||
|
||||
vm.deny = (approval) => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}${approval.id}/deny`);
|
||||
Rest.post()
|
||||
.then(() => loadTheList());
|
||||
};
|
||||
}
|
||||
|
||||
AtApprovalsDrawerController.$inject = ['ComponentsStrings', 'Rest', 'GetBasePath', '$rootScope'];
|
||||
|
||||
function atApprovalsDrawer () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
templateUrl,
|
||||
controller: AtApprovalsDrawerController,
|
||||
controllerAs: 'vm',
|
||||
scope: {
|
||||
closeApprovals: '&'
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default atApprovalsDrawer;
|
||||
@ -0,0 +1,79 @@
|
||||
<div style="width: 100%;height: 100%;position: fixed;top: 0;right: 0;opacity: 0.5;background-color: black;z-index: 10000;"></div>
|
||||
<div class="at-ApprovalsDrawer" ng-if="vm.listLoaded">
|
||||
<div class="at-ApprovalsDrawer-header">
|
||||
<div class="at-ApprovalsDrawer-title">
|
||||
<span>
|
||||
NOTIFICATIONS
|
||||
</span>
|
||||
<span class="at-Panel-headingTitleBadge">
|
||||
{{vm.count}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="at-ApprovalsDrawer-exit">
|
||||
<button class="close" ng-click="closeApprovals()">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<at-list-toolbar
|
||||
ng-if="vm.approvals.length > 0"
|
||||
sort-only="true"
|
||||
sort-value="vm.toolbarSortValue"
|
||||
sort-options="vm.toolbarSortOptions"
|
||||
on-sort="vm.onToolbarSort">
|
||||
</at-list-toolbar>
|
||||
<at-list results="vm.approvals" id="approvals_list" empty-list-reason="{{ vm.emptyListReason }}">
|
||||
<at-row ng-repeat="approval in vm.approvals"
|
||||
id="approval-row-{{ approval.id }}">
|
||||
<div class="at-Row-items">
|
||||
<div class="at-Row-container">
|
||||
<div class="at-Row-container">
|
||||
<!-- TODO: translate header tag -->
|
||||
<at-row-item
|
||||
header-value="{{ approval.summary_fields.source_workflow_job.name }}"
|
||||
header-state="workflowResults({id: {{approval.summary_fields.source_workflow_job.id}}})"
|
||||
header-tag="Workflow Template">
|
||||
</at-row-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<at-row-item
|
||||
value-bind-html="{{ approval.created | longDate }}">
|
||||
</at-row-item>
|
||||
<at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires: Never">
|
||||
</at-row-item>
|
||||
<!-- <at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires {{ approval.created | longDate }}">
|
||||
</at-row-item> -->
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<div style="display: flex; justify-content: flex-end; width: 100%; margin-top: 10px;">
|
||||
<div>Continue workflow job?</div>
|
||||
<button class="btn at-Button--success"
|
||||
style="margin-left: 15px;"
|
||||
ng-click="vm.approve(approval)"
|
||||
type="button">
|
||||
APPROVE
|
||||
</button>
|
||||
<button class="btn at-Button--error"
|
||||
style="margin-left: 15px;"
|
||||
ng-click="vm.deny(approval)"
|
||||
type="button">
|
||||
DENY
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</at-row>
|
||||
</at-list>
|
||||
<paginate
|
||||
collection="vm.approvals"
|
||||
dataset="vm.dataset"
|
||||
iterator="template"
|
||||
base-path="unified_job_templates"
|
||||
query-set="vm.queryset">
|
||||
</paginate>
|
||||
</div>
|
||||
@ -119,6 +119,10 @@ function ComponentsStrings (BaseString) {
|
||||
EXPANDED: t.s('Expanded'),
|
||||
SORT_BY: t.s('SORT BY')
|
||||
};
|
||||
|
||||
ns.approvals = {
|
||||
NONE: t.s('There are no jobs awaiting approval')
|
||||
};
|
||||
}
|
||||
|
||||
ComponentsStrings.$inject = ['BaseStringService'];
|
||||
|
||||
@ -2,6 +2,7 @@ import atLibServices from '~services';
|
||||
|
||||
import actionGroup from '~components/action/action-group.directive';
|
||||
import actionButton from '~components/action/action-button.directive';
|
||||
import approvalsDrawer from '~components/approvalsDrawer/approvalsDrawer.directive';
|
||||
import dialog from '~components/dialog/dialog.component';
|
||||
import divider from '~components/utility/divider.directive';
|
||||
import dynamicSelect from '~components/input/dynamic-select.directive';
|
||||
@ -60,6 +61,7 @@ angular
|
||||
])
|
||||
.directive('atActionGroup', actionGroup)
|
||||
.directive('atActionButton', actionButton)
|
||||
.directive('atApprovalsDrawer', approvalsDrawer)
|
||||
.component('atDialog', dialog)
|
||||
.directive('atDivider', divider)
|
||||
.directive('atDynamicSelect', dynamicSelect)
|
||||
|
||||
@ -81,6 +81,23 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.at-Layout-topNavApprovals {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
div {
|
||||
margin-left: 10px;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
background-color: red;
|
||||
color: white;
|
||||
height: 15px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-sideContainer {
|
||||
|
||||
@ -25,6 +25,10 @@ function AtLayoutController ($scope, $http, strings, ProcessErrors, $transitions
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('$root.pendingApprovalCount', () => {
|
||||
vm.approvalsCount = _.get($scope, '$root.pendingApprovalCount') || 0;
|
||||
});
|
||||
|
||||
$scope.$watch('$root.socketStatus', (newStatus) => {
|
||||
vm.socketState = newStatus;
|
||||
vm.socketIconClass = `icon-socket-${vm.socketState}`;
|
||||
@ -42,6 +46,14 @@ function AtLayoutController ($scope, $http, strings, ProcessErrors, $transitions
|
||||
}
|
||||
};
|
||||
|
||||
vm.openApprovals = () => {
|
||||
vm.showApprovals = true;
|
||||
};
|
||||
|
||||
vm.closeApprovals = () => {
|
||||
vm.showApprovals = false;
|
||||
};
|
||||
|
||||
function checkOrgAdmin () {
|
||||
const usersPath = `/api/v2/users/${vm.currentUserId}/admin_of_organizations/`;
|
||||
$http.get(usersPath)
|
||||
|
||||
@ -14,6 +14,12 @@
|
||||
<span>{{ $parent.layoutVm.currentUsername }}</span>
|
||||
</a>
|
||||
</at-top-nav-item>
|
||||
<at-top-nav-item ng-click="vm.openApprovals()">
|
||||
<div class="at-Layout-topNavApprovals">
|
||||
<i class="fa fa-bell" alt="{{ vm.getString('NOTIFICATIONS') }}"></i>
|
||||
<div>{{vm.approvalsCount}}</div>
|
||||
</div>
|
||||
</at-top-nav-item>
|
||||
<at-top-nav-item>
|
||||
<a ui-sref="about">
|
||||
<i class="fa fa-info-circle" alt="{{ vm.getString('ABOUT') }}"></i>
|
||||
@ -104,4 +110,5 @@
|
||||
<ng-transclude></ng-transclude>
|
||||
</div>
|
||||
</div>
|
||||
<at-approvals-drawer ng-if="vm.showApprovals" close-approvals="vm.closeApprovals()"></at-approvals-drawer>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import atLibServices from '~services';
|
||||
|
||||
import Application from '~models/Application';
|
||||
import AdHocCommand from '~models/AdHocCommand';
|
||||
import Application from '~models/Application';
|
||||
import Base from '~models/Base';
|
||||
import Config from '~models/Config';
|
||||
import Credential from '~models/Credential';
|
||||
@ -19,16 +19,16 @@ import Me from '~models/Me';
|
||||
import NotificationTemplate from '~models/NotificationTemplate';
|
||||
import Organization from '~models/Organization';
|
||||
import Project from '~models/Project';
|
||||
import Schedule from '~models/Schedule';
|
||||
import ProjectUpdate from '~models/ProjectUpdate';
|
||||
import Schedule from '~models/Schedule';
|
||||
import SystemJob from '~models/SystemJob';
|
||||
import Token from '~models/Token';
|
||||
import UnifiedJob from '~models/UnifiedJob';
|
||||
import UnifiedJobTemplate from '~models/UnifiedJobTemplate';
|
||||
import User from '~models/User';
|
||||
import WorkflowJob from '~models/WorkflowJob';
|
||||
import WorkflowJobTemplate from '~models/WorkflowJobTemplate';
|
||||
import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode';
|
||||
import UnifiedJob from '~models/UnifiedJob';
|
||||
import User from '~models/User';
|
||||
|
||||
import ModelsStrings from '~models/models.strings';
|
||||
|
||||
@ -38,8 +38,8 @@ angular
|
||||
.module(MODULE_NAME, [
|
||||
atLibServices
|
||||
])
|
||||
.service('ApplicationModel', Application)
|
||||
.service('AdHocCommandModel', AdHocCommand)
|
||||
.service('ApplicationModel', Application)
|
||||
.service('BaseModel', Base)
|
||||
.service('ConfigModel', Config)
|
||||
.service('CredentialModel', Credential)
|
||||
@ -54,19 +54,19 @@ angular
|
||||
.service('JobModel', Job)
|
||||
.service('JobTemplateModel', JobTemplate)
|
||||
.service('MeModel', Me)
|
||||
.service('ModelsStrings', ModelsStrings)
|
||||
.service('NotificationTemplate', NotificationTemplate)
|
||||
.service('OrganizationModel', Organization)
|
||||
.service('ProjectModel', Project)
|
||||
.service('ScheduleModel', Schedule)
|
||||
.service('UnifiedJobModel', UnifiedJob)
|
||||
.service('ProjectUpdateModel', ProjectUpdate)
|
||||
.service('ScheduleModel', Schedule)
|
||||
.service('SystemJobModel', SystemJob)
|
||||
.service('TokenModel', Token)
|
||||
.service('UnifiedJobModel', UnifiedJob)
|
||||
.service('UnifiedJobTemplateModel', UnifiedJobTemplate)
|
||||
.service('UserModel', User)
|
||||
.service('WorkflowJobModel', WorkflowJob)
|
||||
.service('WorkflowJobTemplateModel', WorkflowJobTemplate)
|
||||
.service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode)
|
||||
.service('UserModel', User)
|
||||
.service('ModelsStrings', ModelsStrings);
|
||||
.service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode);
|
||||
|
||||
export default MODULE_NAME;
|
||||
|
||||
@ -161,16 +161,16 @@ angular
|
||||
// })
|
||||
}
|
||||
])
|
||||
.run(['$stateExtender', '$q', '$compile', '$cookies', '$rootScope', '$log', '$stateParams',
|
||||
.run(['$q', '$cookies', '$rootScope', '$log', '$stateParams',
|
||||
'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
|
||||
'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
|
||||
'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
|
||||
'$filter', 'SocketService', 'AppStrings', '$transitions',
|
||||
function($stateExtender, $q, $compile, $cookies, $rootScope, $log, $stateParams,
|
||||
'LoadConfig', 'Store', 'pendoService', 'Rest',
|
||||
'$state', 'GetBasePath', 'ConfigService',
|
||||
'SocketService', 'AppStrings', '$transitions',
|
||||
function($q, $cookies, $rootScope, $log, $stateParams,
|
||||
CheckLicense, $location, Authorization, LoadBasePaths, Timer,
|
||||
LoadConfig, Store, pendoService, Prompt, Rest, Wait,
|
||||
ProcessErrors, $state, GetBasePath, ConfigService,
|
||||
$filter, SocketService, AppStrings, $transitions) {
|
||||
LoadConfig, Store, pendoService, Rest,
|
||||
$state, GetBasePath, ConfigService,
|
||||
SocketService, AppStrings, $transitions) {
|
||||
|
||||
$rootScope.$state = $state;
|
||||
$rootScope.$state.matches = function(stateName) {
|
||||
@ -387,6 +387,15 @@ angular
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}?status=pending&page_size=1`);
|
||||
Rest.get()
|
||||
.then(({data}) => {
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle this
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -39,14 +39,14 @@
|
||||
* This is usage information.
|
||||
*/
|
||||
|
||||
export default ['$log', '$cookies', '$compile', '$rootScope',
|
||||
export default ['$log', '$cookies', '$rootScope',
|
||||
'$location', 'Authorization', 'Alert', 'Wait', 'Timer',
|
||||
'Empty', '$scope', 'pendoService', 'ConfigService',
|
||||
'CheckLicense', 'SocketService',
|
||||
function ($log, $cookies, $compile, $rootScope, $location,
|
||||
Authorization, Alert, Wait, Timer, Empty,
|
||||
scope, pendoService, ConfigService, CheckLicense,
|
||||
SocketService) {
|
||||
'CheckLicense', 'SocketService', 'Rest', 'GetBasePath',
|
||||
function ($log, $cookies, $rootScope,
|
||||
$location, Authorization, Alert, Wait, Timer,
|
||||
Empty, scope, pendoService, ConfigService,
|
||||
CheckLicense, SocketService, Rest, GetBasePath) {
|
||||
var lastPath, lastUser, sessionExpired, loginAgain, preAuthUrl;
|
||||
|
||||
loginAgain = function() {
|
||||
@ -139,6 +139,15 @@ export default ['$log', '$cookies', '$compile', '$rootScope',
|
||||
Alert('Error', 'Failed to access user information. GET returned status: ' + status, 'alert-danger', loginAgain);
|
||||
});
|
||||
});
|
||||
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}?status=pending&page_size=1`);
|
||||
Rest.get()
|
||||
.then(({data}) => {
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle this
|
||||
});
|
||||
});
|
||||
|
||||
// Call the API to get an auth token
|
||||
|
||||
@ -75,221 +75,230 @@ export default ['Rest', 'GetBasePath', '$q', 'NextPage', function(Rest, GetBaseP
|
||||
}).catch(function(response){
|
||||
return $q.reject( response );
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
getAllWorkflowJobTemplateLabels: function(id) {
|
||||
Rest.setUrl(GetBasePath('workflow_job_templates') + id + "/labels?page_size=200");
|
||||
return Rest.get()
|
||||
.then(function(res) {
|
||||
if (res.data.next) {
|
||||
return NextPage({
|
||||
url: res.data.next,
|
||||
arrayOfValues: res.data.results
|
||||
}).then(function(labels) {
|
||||
return labels;
|
||||
}).catch(function(response){
|
||||
return $q.reject( response );
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.resolve( res.data.results );
|
||||
}
|
||||
}).catch(function(response){
|
||||
return $q.reject( response );
|
||||
});
|
||||
},
|
||||
getJobTemplate: function(id) {
|
||||
var url = GetBasePath('job_templates');
|
||||
getAllWorkflowJobTemplateLabels: function(id) {
|
||||
Rest.setUrl(GetBasePath('workflow_job_templates') + id + "/labels?page_size=200");
|
||||
return Rest.get()
|
||||
.then(function(res) {
|
||||
if (res.data.next) {
|
||||
return NextPage({
|
||||
url: res.data.next,
|
||||
arrayOfValues: res.data.results
|
||||
}).then(function(labels) {
|
||||
return labels;
|
||||
}).catch(function(response){
|
||||
return $q.reject( response );
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.resolve( res.data.results );
|
||||
}
|
||||
}).catch(function(response){
|
||||
return $q.reject( response );
|
||||
});
|
||||
},
|
||||
getJobTemplate: function(id) {
|
||||
var url = GetBasePath('job_templates');
|
||||
|
||||
url = url + id;
|
||||
url = url + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
addWorkflowNode: function(params) {
|
||||
// params.url
|
||||
// params.data
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
addWorkflowNode: function(params) {
|
||||
// params.url
|
||||
// params.data
|
||||
|
||||
Rest.setUrl(params.url);
|
||||
return Rest.post(params.data);
|
||||
},
|
||||
editWorkflowNode: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
Rest.setUrl(params.url);
|
||||
return Rest.post(params.data);
|
||||
},
|
||||
editWorkflowNode: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.id;
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.put(params.data);
|
||||
},
|
||||
getJobTemplateLaunchInfo: function(id) {
|
||||
var url = GetBasePath('job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.put(params.data);
|
||||
},
|
||||
getJobTemplateLaunchInfo: function(id) {
|
||||
var url = GetBasePath('job_templates');
|
||||
|
||||
url = url + id + '/launch';
|
||||
url = url + id + '/launch';
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getWorkflowJobTemplateNodes: function(id, page) {
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getWorkflowJobTemplateNodes: function(id, page) {
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
|
||||
url = url + id + '/workflow_nodes?page_size=200';
|
||||
url = url + id + '/workflow_nodes?page_size=200';
|
||||
|
||||
if(page) {
|
||||
url += '&page=' + page;
|
||||
}
|
||||
if(page) {
|
||||
url += '&page=' + page;
|
||||
}
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
updateWorkflowJobTemplate: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
updateWorkflowJobTemplate: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
|
||||
url = url + params.id;
|
||||
url = url + params.id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.patch(params.data);
|
||||
},
|
||||
getWorkflowJobTemplate: function(id) {
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.patch(params.data);
|
||||
},
|
||||
getWorkflowJobTemplate: function(id) {
|
||||
var url = GetBasePath('workflow_job_templates');
|
||||
|
||||
url = url + id;
|
||||
url = url + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
deleteWorkflowJobTemplateNode: function(id) {
|
||||
var url = GetBasePath('workflow_job_template_nodes') + id;
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
deleteWorkflowJobTemplateNode: function(id) {
|
||||
var url = GetBasePath('workflow_job_template_nodes') + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.destroy();
|
||||
},
|
||||
disassociateWorkflowNode: function(params) {
|
||||
//params.parentId
|
||||
//params.nodeId
|
||||
//params.edge
|
||||
Rest.setUrl(url);
|
||||
return Rest.destroy();
|
||||
},
|
||||
disassociateWorkflowNode: function(params) {
|
||||
//params.parentId
|
||||
//params.nodeId
|
||||
//params.edge
|
||||
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.parentId;
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.parentId;
|
||||
|
||||
if(params.edge === 'success') {
|
||||
url = url + '/success_nodes';
|
||||
}
|
||||
else if(params.edge === 'failure') {
|
||||
url = url + '/failure_nodes';
|
||||
}
|
||||
else if(params.edge === 'always') {
|
||||
url = url + '/always_nodes';
|
||||
}
|
||||
if(params.edge === 'success') {
|
||||
url = url + '/success_nodes';
|
||||
}
|
||||
else if(params.edge === 'failure') {
|
||||
url = url + '/failure_nodes';
|
||||
}
|
||||
else if(params.edge === 'always') {
|
||||
url = url + '/always_nodes';
|
||||
}
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.post({
|
||||
"id": params.nodeId,
|
||||
"disassociate": true
|
||||
});
|
||||
},
|
||||
associateWorkflowNode: function(params) {
|
||||
//params.parentId
|
||||
//params.nodeId
|
||||
//params.edge
|
||||
Rest.setUrl(url);
|
||||
return Rest.post({
|
||||
"id": params.nodeId,
|
||||
"disassociate": true
|
||||
});
|
||||
},
|
||||
associateWorkflowNode: function(params) {
|
||||
//params.parentId
|
||||
//params.nodeId
|
||||
//params.edge
|
||||
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.parentId;
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.parentId;
|
||||
|
||||
if(params.edge === 'success') {
|
||||
url = url + '/success_nodes';
|
||||
}
|
||||
else if(params.edge === 'failure') {
|
||||
url = url + '/failure_nodes';
|
||||
}
|
||||
else if(params.edge === 'always') {
|
||||
url = url + '/always_nodes';
|
||||
}
|
||||
if(params.edge === 'success') {
|
||||
url = url + '/success_nodes';
|
||||
}
|
||||
else if(params.edge === 'failure') {
|
||||
url = url + '/failure_nodes';
|
||||
}
|
||||
else if(params.edge === 'always') {
|
||||
url = url + '/always_nodes';
|
||||
}
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.post({
|
||||
id: params.nodeId
|
||||
});
|
||||
},
|
||||
getUnifiedJobTemplate: function(id) {
|
||||
var url = GetBasePath('unified_job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.post({
|
||||
id: params.nodeId
|
||||
});
|
||||
},
|
||||
getUnifiedJobTemplate: function(id) {
|
||||
var url = GetBasePath('unified_job_templates');
|
||||
|
||||
url = url + "?id=" + id;
|
||||
url = url + "?id=" + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getCredential: function(id) {
|
||||
var url = GetBasePath('credentials');
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getCredential: function(id) {
|
||||
var url = GetBasePath('credentials');
|
||||
|
||||
url = url + id;
|
||||
url = url + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getInventory: function(id) {
|
||||
var url = GetBasePath('inventory');
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getInventory: function(id) {
|
||||
var url = GetBasePath('inventory');
|
||||
|
||||
url = url + id;
|
||||
url = url + id;
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getWorkflowCopy: function(id) {
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
getWorkflowCopy: function(id) {
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
|
||||
url = url + id + '/copy';
|
||||
url = url + id + '/copy';
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
copyWorkflow: function(id) {
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
Rest.setUrl(url);
|
||||
return Rest.get();
|
||||
},
|
||||
copyWorkflow: function(id) {
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
|
||||
url = url + id + '/copy';
|
||||
url = url + id + '/copy';
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.post();
|
||||
},
|
||||
getWorkflowJobTemplateOptions: function() {
|
||||
var deferred = $q.defer();
|
||||
Rest.setUrl(url);
|
||||
return Rest.post();
|
||||
},
|
||||
getWorkflowJobTemplateOptions: function() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
let url = GetBasePath('workflow_job_templates');
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.then(({data}) => {
|
||||
deferred.resolve(data);
|
||||
}).catch(({msg, code}) => {
|
||||
deferred.reject(msg, code);
|
||||
});
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.then(({data}) => {
|
||||
deferred.resolve(data);
|
||||
}).catch(({msg, code}) => {
|
||||
deferred.reject(msg, code);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
getJobTemplateOptions: function() {
|
||||
var deferred = $q.defer();
|
||||
return deferred.promise;
|
||||
},
|
||||
getJobTemplateOptions: function() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
let url = GetBasePath('job_templates');
|
||||
let url = GetBasePath('job_templates');
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.then(({data}) => {
|
||||
deferred.resolve(data);
|
||||
}).catch(({msg, code}) => {
|
||||
deferred.reject(msg, code);
|
||||
});
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.then(({data}) => {
|
||||
deferred.resolve(data);
|
||||
}).catch(({msg, code}) => {
|
||||
deferred.reject(msg, code);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
postWorkflowNodeCredential: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
return deferred.promise;
|
||||
},
|
||||
postWorkflowNodeCredential: function(params) {
|
||||
// params.id
|
||||
// params.data
|
||||
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.id + '/credentials';
|
||||
var url = GetBasePath('workflow_job_template_nodes') + params.id + '/credentials';
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.post(params.data);
|
||||
}
|
||||
Rest.setUrl(url);
|
||||
return Rest.post(params.data);
|
||||
},
|
||||
createApprovalTemplate: (params) => {
|
||||
params = params || {};
|
||||
Rest.setUrl(GetBasePath('workflow_approval_templates'));
|
||||
return Rest.post(params);
|
||||
},
|
||||
patchApprovalTemplate: ({id, data}) => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval_templates')}/${id}`);
|
||||
return Rest.patch(data);
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@ -142,8 +142,10 @@
|
||||
}
|
||||
|
||||
.WorkflowChart-deletedText {
|
||||
width: 90px;
|
||||
width: 180px;
|
||||
height: 14px;
|
||||
color: @default-interface-txt;
|
||||
text-align: center;
|
||||
}
|
||||
.WorkflowChart-activeNode {
|
||||
fill: @default-link;
|
||||
@ -159,7 +161,11 @@
|
||||
}
|
||||
|
||||
.WorkflowChart-nameText {
|
||||
width: 180px;
|
||||
height: 20px;
|
||||
line-height: 18px;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.WorkflowChart-tooltip {
|
||||
|
||||
@ -770,12 +770,23 @@ export default ['moment', '$timeout', '$window', '$filter', 'TemplatesStrings',
|
||||
});
|
||||
|
||||
baseSvg.selectAll(".WorkflowChart-nameText")
|
||||
.attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 20 : nodeW / 2; })
|
||||
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 10 : nodeH / 2; })
|
||||
.attr("x", 0)
|
||||
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 10 : (nodeH / 2) - 10; })
|
||||
.attr("text-anchor", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? "inherit" : "middle"; })
|
||||
.text(function (d) {
|
||||
.html(function (d) {
|
||||
const name = _.get(d, 'unifiedJobTemplate.name');
|
||||
return name ? wrap(name) : "";
|
||||
const wrappedName = name ? wrap(name) : "";
|
||||
// TODO: clean this up
|
||||
if (d.unifiedJobTemplate && d.unifiedJobTemplate.unified_job_type === 'workflow_approval') {
|
||||
return `<span>
|
||||
<div style="background-color: #EBEBEB;height: 20px;width: 20px;border-radius: 50%;display: inline-block;margin-right:5px;">
|
||||
<span style="color:#707070" class="fa fa-pause"></span>
|
||||
</div>
|
||||
<span>${wrappedName}</span>
|
||||
</span>`;
|
||||
} else {
|
||||
return `<span>${wrappedName}</span>`;
|
||||
}
|
||||
});
|
||||
|
||||
baseSvg.selectAll(".WorkflowChart-detailsLink")
|
||||
@ -884,19 +895,31 @@ export default ['moment', '$timeout', '$window', '$filter', 'TemplatesStrings',
|
||||
.attr("class", "WorkflowChart-activeNode")
|
||||
.style("display", function(d) { return d.id === scope.graphState.nodeBeingEdited ? null : "none"; });
|
||||
|
||||
thisNode.append("text")
|
||||
.attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 20 : nodeW / 2; })
|
||||
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 10 : nodeH / 2; })
|
||||
thisNode.append("foreignObject")
|
||||
// .attr("x", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 20 : nodeW / 2; })
|
||||
.attr("x", 0)
|
||||
.attr("y", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? 10 : (nodeH / 2) - 10; })
|
||||
.attr("dy", ".35em")
|
||||
.attr("text-anchor", function(d){ return (scope.mode === 'details' && d.job && d.job.status) ? "inherit" : "middle"; })
|
||||
.attr("class", "WorkflowChart-defaultText WorkflowChart-nameText")
|
||||
.text(function (d) {
|
||||
.html(function (d) {
|
||||
const name = _.get(d, 'unifiedJobTemplate.name');
|
||||
return name ? wrap(name) : "";
|
||||
const wrappedName = name ? wrap(name) : "";
|
||||
// TODO: clean this up
|
||||
if (d.unifiedJobTemplate && d.unifiedJobTemplate.unified_job_type === 'workflow_approval') {
|
||||
return `<span>
|
||||
<div style="background-color: #EBEBEB;height: 20px;width: 20px;border-radius: 50%;display: inline-block;margin-right:5px;">
|
||||
<span style="color:#707070" class="fa fa-pause"></span>
|
||||
</div>
|
||||
<span>${wrappedName}</span>
|
||||
</span>`;
|
||||
} else {
|
||||
return `<span>${wrappedName}</span>`;
|
||||
}
|
||||
});
|
||||
|
||||
thisNode.append("foreignObject")
|
||||
.attr("x", 62)
|
||||
.attr("x", 0)
|
||||
.attr("y", 22)
|
||||
.attr("dy", ".35em")
|
||||
.attr("text-anchor", "middle")
|
||||
|
||||
@ -32,6 +32,7 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
|
||||
|
||||
$scope.strings = TemplatesStrings;
|
||||
$scope.editNodeHelpMessage = null;
|
||||
$scope.pauseNode = {};
|
||||
|
||||
let templateList = _.cloneDeep(TemplateList);
|
||||
delete templateList.actions;
|
||||
@ -463,6 +464,7 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
|
||||
}
|
||||
|
||||
$scope.promptData = null;
|
||||
$scope.pauseNode = {};
|
||||
$scope.editNodeHelpMessage = getEditNodeHelpMessage(selectedTemplate, $scope.workflowJobTemplateObj);
|
||||
|
||||
if (selectedTemplate.type === "job_template" || selectedTemplate.type === "workflow_job_template") {
|
||||
@ -616,26 +618,48 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
|
||||
})
|
||||
);
|
||||
|
||||
CreateSelect2({
|
||||
element: '#workflow-node-types',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$q.all(listPromises)
|
||||
.then(() => {
|
||||
if ($scope.nodeConfig.mode === "edit") {
|
||||
// Make sure that we have the full unified job template object
|
||||
if (!$scope.nodeConfig.node.fullUnifiedJobTemplateObject) {
|
||||
// This is a node that we got back from the api with an incomplete
|
||||
// unified job template so we're going to pull down the whole object
|
||||
TemplatesService.getUnifiedJobTemplate($scope.nodeConfig.node.originalNodeObject.summary_fields.unified_job_template.id)
|
||||
.then(({data}) => {
|
||||
$scope.nodeConfig.node.fullUnifiedJobTemplateObject = data.results[0];
|
||||
finishConfiguringEdit();
|
||||
}, (error) => {
|
||||
ProcessErrors($scope, error.data, error.status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get unified job template. GET returned ' +
|
||||
'status: ' + error.status
|
||||
});
|
||||
});
|
||||
if ($scope.nodeConfig.node.unifiedJobTemplate && $scope.nodeConfig.node.unifiedJobTemplate.unified_job_type === "workflow_approval") {
|
||||
$scope.selectedTemplate = null;
|
||||
$scope.activeTab = "pause";
|
||||
CreateSelect2({
|
||||
element: '#workflow_node_edge',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
$scope.pauseNode = {
|
||||
isPauseNode: true,
|
||||
name: $scope.nodeConfig.node.unifiedJobTemplate.name,
|
||||
description: $scope.nodeConfig.node.unifiedJobTemplate.description,
|
||||
};
|
||||
|
||||
$scope.nodeFormDataLoaded = true;
|
||||
} else {
|
||||
finishConfiguringEdit();
|
||||
// Make sure that we have the full unified job template object
|
||||
if (!$scope.nodeConfig.node.fullUnifiedJobTemplateObject) {
|
||||
// This is a node that we got back from the api with an incomplete
|
||||
// unified job template so we're going to pull down the whole object
|
||||
TemplatesService.getUnifiedJobTemplate($scope.nodeConfig.node.originalNodeObject.summary_fields.unified_job_template.id)
|
||||
.then(({data}) => {
|
||||
$scope.nodeConfig.node.fullUnifiedJobTemplateObject = data.results[0];
|
||||
finishConfiguringEdit();
|
||||
}, (error) => {
|
||||
ProcessErrors($scope, error.data, error.status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get unified job template. GET returned ' +
|
||||
'status: ' + error.status
|
||||
});
|
||||
});
|
||||
} else {
|
||||
finishConfiguringEdit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finishConfiguringAdd();
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
<div ng-show="nodeFormDataLoaded">
|
||||
<div class="WorkflowMaker-formTitle">{{nodeConfig.mode === 'edit' ? nodeConfig.node.fullUnifiedJobTemplateObject.name || nodeConfig.node.unifiedJobTemplate.name : strings.get('workflow_maker.ADD_A_NODE')}}</div>
|
||||
<div class="Form-tabHolder" ng-show="!readOnly">
|
||||
<div class="Form-tab WorkflowMaker-formTab" ng-class="{'is-selected': activeTab === 'jobs'}" ng-click="activeTab = 'jobs'">{{strings.get('workflow_maker.JOBS')}}</div>
|
||||
<div class="Form-tab WorkflowMaker-formTab" ng-class="{'is-selected': activeTab === 'project_syncs'}" ng-click="activeTab = 'project_syncs'">{{strings.get('workflow_maker.PROJECT_SYNC')}}</div>
|
||||
<div class="Form-tab WorkflowMaker-formTab" ng-class="{'is-selected': activeTab === 'inventory_syncs'}" ng-click="activeTab = 'inventory_syncs'">{{strings.get('workflow_maker.INVENTORY_SYNC')}}</div>
|
||||
<div class="WorkflowMaker-formTypeDropdown" ng-show="!readOnly">
|
||||
<select
|
||||
id="workflow-node-types"
|
||||
ng-model="activeTab"
|
||||
class="form-control Form-dropDown"
|
||||
name="activeTab"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<option value="jobs" selected="selected">{{strings.get('workflow_maker.JOBS')}}</option>
|
||||
<option value="project_syncs" selected="selected">{{strings.get('workflow_maker.PROJECT_SYNC')}}</option>
|
||||
<option value="inventory_syncs" selected="selected">{{strings.get('workflow_maker.INVENTORY_SYNC')}}</option>
|
||||
<option value="pause" selected="selected">{{strings.get('workflow_maker.PAUSE_NODE')}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="WorkflowMaker-formLists" ng-show="!readOnly">
|
||||
<div id="workflow-jobs-list" ng-show="activeTab === 'jobs'">
|
||||
@ -103,6 +112,36 @@
|
||||
</div>
|
||||
<paginate base-path="inventory_sources" collection="wf_maker_inventory_sources" dataset="wf_maker_inventory_source_dataset" iterator="wf_maker_inventory_source" query-set="wf_maker_inventory_source_queryset" hide-view-per-page="true" max-visible-pages="5"></paginate>
|
||||
</div>
|
||||
<div id="workflow-pause" ng-show="activeTab === 'pause'">
|
||||
<label class="WorkflowMaker-pauseCheckbox">
|
||||
<input type="checkbox" ng-model="pauseNode.isPauseNode" />
|
||||
<!-- translate -->
|
||||
<span class="Form-inputLabel">Make this a pause node</span>
|
||||
</label>
|
||||
<div ng-hide="!pauseNode.isPauseNode">
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn">
|
||||
<label for="pauseName" class="Form-inputLabelContainer">
|
||||
<span class="Form-requiredAsterisk">*</span>
|
||||
<!-- translate -->
|
||||
<span class="Form-inputLabel">Name</span>
|
||||
</label>
|
||||
<div>
|
||||
<input type="text" ng-model="pauseNode.name" name="pauseName" id="workflow_job_template_pauseName" class="form-control Form-textInput" />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group Form-formGroup Form-formGroup--singleColumn"></div>
|
||||
<label for="pauseDesc" class="Form-inputLabelContainer">
|
||||
<!-- translate -->
|
||||
<span class="Form-inputLabel">Description</span>
|
||||
</label>
|
||||
<div>
|
||||
<input type="text" ng-model="pauseNode.description" name="pauseDesc" id="workflow_job_template_pauseDesc" class="form-control Form-textInput" />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="selectedTemplate && selectedTemplateInvalid">
|
||||
<div class="WorkflowMaker-invalidJobTemplateWarning">
|
||||
@ -238,7 +277,8 @@
|
||||
<button type="button" class="btn btn-sm Form-primaryButton Form-primaryButton--noMargin" id="workflow_maker_prompt_btn" ng-show="showPromptButton && activeTab == 'jobs' " ng-click="openPromptModal()"> {{:: strings.get('prompt.PROMPT') }}</button>
|
||||
<button type="button" class="btn btn-sm Form-cancelButton" id="workflow_maker_cancel_node_btn" ng-show="!readOnly" ng-click="cancel()"> {{:: strings.get('CANCEL') }}</button>
|
||||
<button type="button" class="btn btn-sm Form-cancelButton" id="workflow_maker_close_node_btn" ng-show="readOnly" ng-click="cancel()"> {{:: strings.get('CLOSE') }}</button>
|
||||
<button type="button" class="btn btn-sm Form-saveButton" id="workflow_maker_select_node_btn" ng-show="!readOnly" ng-click="select({selectedTemplate, promptData, edgeType})" ng-disabled="!selectedTemplate || promptModalMissingReqFields || credentialRequiresPassword || selectedTemplateInvalid"> {{:: strings.get('workflow_maker.SELECT') }}</button>
|
||||
<!-- need to figure out how to disable this button when pause node is incomplete -->
|
||||
<button type="button" class="btn btn-sm Form-saveButton" id="workflow_maker_select_node_btn" ng-show="!readOnly" ng-click="select({selectedTemplate, promptData, edgeType, pauseNode})" ng-disabled="!(selectedTemplate || pauseNode.isPauseNode) || promptModalMissingReqFields || credentialRequiresPassword || selectedTemplateInvalid || (pauseNode.isPauseNode && !pauseNode.name)"> {{:: strings.get('workflow_maker.SELECT') }}</button>
|
||||
</div>
|
||||
<prompt prompt-data="promptData" action-text="{{:: strings.get('prompt.CONFIRM')}}" prevent-creds-with-passwords="preventCredsWithPasswords" read-only-prompts="readOnly"></prompt>
|
||||
</div>
|
||||
|
||||
@ -296,8 +296,8 @@
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.WorkflowMaker-formTab {
|
||||
margin-right: 10px;
|
||||
.WorkflowMaker-formTypeDropdown {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.WorkflowMaker-preventBodyScrolling {
|
||||
@ -314,6 +314,13 @@
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.WorkflowMaker-pauseCheckbox {
|
||||
input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.Key-list {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
|
||||
@ -140,59 +140,126 @@ export default ['$scope', 'TemplatesService',
|
||||
};
|
||||
|
||||
if ($scope.graphState.arrayOfNodesForChart.length > 1) {
|
||||
let approvalTemplatePromises = [];
|
||||
let addPromises = [];
|
||||
let editPromises = [];
|
||||
let credentialRequests = [];
|
||||
|
||||
Object.keys(nodeRef).map((workflowMakerNodeId) => {
|
||||
if (nodeRef[workflowMakerNodeId].isNew) {
|
||||
addPromises.push(TemplatesService.addWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: buildSendableNodeData(nodeRef[workflowMakerNodeId])
|
||||
}).then(({data}) => {
|
||||
nodeRef[workflowMakerNodeId].originalNodeObject = data;
|
||||
nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId);
|
||||
if (_.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.ask_credential_on_launch')) {
|
||||
// This finds the credentials that were selected in the prompt but don't occur
|
||||
// in the template defaults
|
||||
let credentialIdsToPost = nodeRef[workflowMakerNodeId].promptData.prompts.credentials.value.filter((credFromPrompt) => {
|
||||
let defaultCreds = _.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.defaults.credentials', []);
|
||||
return !defaultCreds.some((defaultCred) => {
|
||||
return credFromPrompt.id === defaultCred.id;
|
||||
const node = nodeRef[workflowMakerNodeId];
|
||||
if (node.isNew) {
|
||||
if (node.unifiedJobTemplate && node.unifiedJobTemplate.unified_job_type === "workflow_approval") {
|
||||
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
|
||||
name: node.unifiedJobTemplate.name
|
||||
}).then(({data: approvalTemplateData}) => {
|
||||
addPromises.push(TemplatesService.addWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: {
|
||||
unified_job_template: approvalTemplateData.id
|
||||
}
|
||||
}).then(({data: nodeData}) => {
|
||||
node.originalNodeObject = nodeData;
|
||||
nodeIdToChartNodeIdMapping[nodeData.id] = parseInt(workflowMakerNodeId);
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
}));
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
|
||||
credentialIdsToPost.forEach((credentialToPost) => {
|
||||
credentialRequests.push({
|
||||
id: data.id,
|
||||
}));
|
||||
} else {
|
||||
addPromises.push(TemplatesService.addWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: buildSendableNodeData(node)
|
||||
}).then(({data}) => {
|
||||
node.originalNodeObject = data;
|
||||
nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId);
|
||||
if (_.get(node, 'promptData.launchConf.ask_credential_on_launch')) {
|
||||
// This finds the credentials that were selected in the prompt but don't occur
|
||||
// in the template defaults
|
||||
let credentialIdsToPost = node.promptData.prompts.credentials.value.filter((credFromPrompt) => {
|
||||
let defaultCreds = _.get(node, 'promptData.launchConf.defaults.credentials', []);
|
||||
return !defaultCreds.some((defaultCred) => {
|
||||
return credFromPrompt.id === defaultCred.id;
|
||||
});
|
||||
});
|
||||
|
||||
credentialIdsToPost.forEach((credentialToPost) => {
|
||||
credentialRequests.push({
|
||||
id: data.id,
|
||||
data: {
|
||||
id: credentialToPost.id
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
}));
|
||||
}
|
||||
} else if (node.isEdited) {
|
||||
if (node.unifiedJobTemplate && node.unifiedJobTemplate.unified_job_type === "workflow_approval") {
|
||||
if (node.originalNodeObject.summary_fields.unified_job_template.unified_job_type === "workflow_approval") {
|
||||
approvalTemplatePromises.push(TemplatesService.patchApprovalTemplate({
|
||||
id: node.originalNodeObject.summary_fields.unified_job_template.id,
|
||||
data: {
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description
|
||||
}
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
|
||||
name: node.unifiedJobTemplate.name
|
||||
}).then(({data: approvalTemplateData}) => {
|
||||
// Make sure that this isn't overwriting everything on the node...
|
||||
editPromises.push(TemplatesService.editWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: {
|
||||
id: credentialToPost.id
|
||||
unified_job_template: approvalTemplateData.id
|
||||
}
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
}));
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
}));
|
||||
} else if (nodeRef[workflowMakerNodeId].isEdited) {
|
||||
editPromises.push(TemplatesService.editWorkflowNode({
|
||||
id: nodeRef[workflowMakerNodeId].originalNodeObject.id,
|
||||
data: buildSendableNodeData(nodeRef[workflowMakerNodeId])
|
||||
}));
|
||||
} else {
|
||||
editPromises.push(TemplatesService.editWorkflowNode({
|
||||
id: node.originalNodeObject.id,
|
||||
data: buildSendableNodeData(node)
|
||||
}));
|
||||
}
|
||||
|
||||
if (_.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.ask_credential_on_launch')) {
|
||||
let credentialsNotInPriorCredentials = nodeRef[workflowMakerNodeId].promptData.prompts.credentials.value.filter((credFromPrompt) => {
|
||||
let defaultCreds = _.get(nodeRef[workflowMakerNodeId], 'promptData.launchConf.defaults.credentials', []);
|
||||
if (_.get(node, 'promptData.launchConf.ask_credential_on_launch')) {
|
||||
let credentialsNotInPriorCredentials = node.promptData.prompts.credentials.value.filter((credFromPrompt) => {
|
||||
let defaultCreds = _.get(node, 'promptData.launchConf.defaults.credentials', []);
|
||||
return !defaultCreds.some((defaultCred) => {
|
||||
return credFromPrompt.id === defaultCred.id;
|
||||
});
|
||||
});
|
||||
|
||||
let credentialsToAdd = credentialsNotInPriorCredentials.filter((credNotInPrior) => {
|
||||
let previousOverrides = _.get(nodeRef[workflowMakerNodeId], 'promptData.prompts.credentials.previousOverrides', []);
|
||||
let previousOverrides = _.get(node, 'promptData.prompts.credentials.previousOverrides', []);
|
||||
return !previousOverrides.some((priorCred) => {
|
||||
return credNotInPrior.id === priorCred.id;
|
||||
});
|
||||
@ -200,8 +267,8 @@ export default ['$scope', 'TemplatesService',
|
||||
|
||||
let credentialsToRemove = [];
|
||||
|
||||
if (_.has(nodeRef[workflowMakerNodeId], 'promptData.prompts.credentials.previousOverrides')) {
|
||||
credentialsToRemove = nodeRef[workflowMakerNodeId].promptData.prompts.credentials.previousOverrides.filter((priorCred) => {
|
||||
if (_.has(node, 'promptData.prompts.credentials.previousOverrides')) {
|
||||
credentialsToRemove = node.promptData.prompts.credentials.previousOverrides.filter((priorCred) => {
|
||||
return !credentialsNotInPriorCredentials.some((credNotInPrior) => {
|
||||
return priorCred.id === credNotInPrior.id;
|
||||
});
|
||||
@ -210,7 +277,7 @@ export default ['$scope', 'TemplatesService',
|
||||
|
||||
credentialsToAdd.forEach((credentialToAdd) => {
|
||||
credentialRequests.push({
|
||||
id: nodeRef[workflowMakerNodeId].originalNodeObject.id,
|
||||
id: node.originalNodeObject.id,
|
||||
data: {
|
||||
id: credentialToAdd.id
|
||||
}
|
||||
@ -219,7 +286,7 @@ export default ['$scope', 'TemplatesService',
|
||||
|
||||
credentialsToRemove.forEach((credentialToRemove) => {
|
||||
credentialRequests.push({
|
||||
id: nodeRef[workflowMakerNodeId].originalNodeObject.id,
|
||||
id: node.originalNodeObject.id,
|
||||
data: {
|
||||
id: credentialToRemove.id,
|
||||
disassociate: true
|
||||
@ -235,172 +302,177 @@ export default ['$scope', 'TemplatesService',
|
||||
return TemplatesService.deleteWorkflowJobTemplateNode(nodeId);
|
||||
});
|
||||
|
||||
$q.all(addPromises.concat(editPromises, deletePromises))
|
||||
$q.all(approvalTemplatePromises)
|
||||
.then(() => {
|
||||
let disassociatePromises = [];
|
||||
let associatePromises = [];
|
||||
let linkMap = {};
|
||||
|
||||
// Build a link map for easy access
|
||||
$scope.graphState.arrayOfLinksForChart.forEach(link => {
|
||||
// link.source.id of 1 is our artificial start node
|
||||
if (link.source.id !== 1) {
|
||||
const sourceNodeId = nodeRef[link.source.id].originalNodeObject.id;
|
||||
const targetNodeId = nodeRef[link.target.id].originalNodeObject.id;
|
||||
if (!linkMap[sourceNodeId]) {
|
||||
linkMap[sourceNodeId] = {};
|
||||
$q.all(addPromises.concat(editPromises, deletePromises))
|
||||
.then(() => {
|
||||
let disassociatePromises = [];
|
||||
let associatePromises = [];
|
||||
let linkMap = {};
|
||||
|
||||
// Build a link map for easy access
|
||||
$scope.graphState.arrayOfLinksForChart.forEach(link => {
|
||||
// link.source.id of 1 is our artificial start node
|
||||
if (link.source.id !== 1) {
|
||||
const sourceNodeId = nodeRef[link.source.id].originalNodeObject.id;
|
||||
const targetNodeId = nodeRef[link.target.id].originalNodeObject.id;
|
||||
if (!linkMap[sourceNodeId]) {
|
||||
linkMap[sourceNodeId] = {};
|
||||
}
|
||||
|
||||
linkMap[sourceNodeId][targetNodeId] = link.edgeType;
|
||||
}
|
||||
|
||||
linkMap[sourceNodeId][targetNodeId] = link.edgeType;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(nodeRef).map((workflowNodeId) => {
|
||||
let nodeId = nodeRef[workflowNodeId].originalNodeObject.id;
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.success_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.success_nodes.forEach((successNodeId) => {
|
||||
if (
|
||||
!deletedNodeIds.includes(successNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][successNodeId] ||
|
||||
linkMap[nodeId][successNodeId] !== "success")
|
||||
) {
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: successNodeId,
|
||||
edge: "success"
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.failure_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.failure_nodes.forEach((failureNodeId) => {
|
||||
if (
|
||||
!deletedNodeIds.includes(failureNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][failureNodeId] ||
|
||||
linkMap[nodeId][failureNodeId] !== "failure")
|
||||
) {
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: failureNodeId,
|
||||
edge: "failure"
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.always_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.always_nodes.forEach((alwaysNodeId) => {
|
||||
if (
|
||||
!deletedNodeIds.includes(alwaysNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][alwaysNodeId] ||
|
||||
linkMap[nodeId][alwaysNodeId] !== "always")
|
||||
) {
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: alwaysNodeId,
|
||||
edge: "always"
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(linkMap).map((sourceNodeId) => {
|
||||
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
|
||||
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
|
||||
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
|
||||
switch(linkMap[sourceNodeId][targetNodeId]) {
|
||||
case "success":
|
||||
});
|
||||
|
||||
Object.keys(nodeRef).map((workflowNodeId) => {
|
||||
let nodeId = nodeRef[workflowNodeId].originalNodeObject.id;
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.success_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.success_nodes.forEach((successNodeId) => {
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
!deletedNodeIds.includes(successNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][successNodeId] ||
|
||||
linkMap[nodeId][successNodeId] !== "success")
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: successNodeId,
|
||||
edge: "success"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "failure":
|
||||
});
|
||||
}
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.failure_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.failure_nodes.forEach((failureNodeId) => {
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
!deletedNodeIds.includes(failureNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][failureNodeId] ||
|
||||
linkMap[nodeId][failureNodeId] !== "failure")
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: failureNodeId,
|
||||
edge: "failure"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "always":
|
||||
});
|
||||
}
|
||||
if (nodeRef[workflowNodeId].originalNodeObject.always_nodes) {
|
||||
nodeRef[workflowNodeId].originalNodeObject.always_nodes.forEach((alwaysNodeId) => {
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
!deletedNodeIds.includes(alwaysNodeId) &&
|
||||
(!linkMap[nodeId] ||
|
||||
!linkMap[nodeId][alwaysNodeId] ||
|
||||
linkMap[nodeId][alwaysNodeId] !== "always")
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
disassociatePromises.push(
|
||||
TemplatesService.disassociateWorkflowNode({
|
||||
parentId: nodeId,
|
||||
nodeId: alwaysNodeId,
|
||||
edge: "always"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$q.all(disassociatePromises)
|
||||
.then(() => {
|
||||
let credentialPromises = credentialRequests.map((request) => {
|
||||
return TemplatesService.postWorkflowNodeCredential({
|
||||
id: request.id,
|
||||
data: request.data
|
||||
});
|
||||
});
|
||||
|
||||
return $q.all(associatePromises.concat(credentialPromises))
|
||||
.then(() => {
|
||||
Wait('stop');
|
||||
$scope.workflowChangesUnsaved = false;
|
||||
$scope.workflowChangesStarted = false;
|
||||
$scope.closeDialog();
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
});
|
||||
}).catch(({
|
||||
data,
|
||||
status
|
||||
}) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
|
||||
Object.keys(linkMap).map((sourceNodeId) => {
|
||||
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
|
||||
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
|
||||
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
|
||||
switch(linkMap[sourceNodeId][targetNodeId]) {
|
||||
case "success":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "success"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "failure":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "failure"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "always":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "always"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
|
||||
$q.all(disassociatePromises)
|
||||
.then(() => {
|
||||
let credentialPromises = credentialRequests.map((request) => {
|
||||
return TemplatesService.postWorkflowNodeCredential({
|
||||
id: request.id,
|
||||
data: request.data
|
||||
});
|
||||
});
|
||||
|
||||
return $q.all(associatePromises.concat(credentialPromises))
|
||||
.then(() => {
|
||||
Wait('stop');
|
||||
$scope.workflowChangesUnsaved = false;
|
||||
$scope.workflowChangesStarted = false;
|
||||
$scope.closeDialog();
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
});
|
||||
}).catch(({
|
||||
data,
|
||||
status
|
||||
}) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
});
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: $scope.strings.get('error.HEADER')
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
let deletePromises = deletedNodeIds.map((nodeId) => {
|
||||
@ -511,17 +583,27 @@ export default ['$scope', 'TemplatesService',
|
||||
$scope.formState.showNodeForm = true;
|
||||
};
|
||||
|
||||
$scope.confirmNodeForm = (selectedTemplate, promptData, edgeType) => {
|
||||
$scope.confirmNodeForm = (selectedTemplate, promptData, edgeType, pauseNode) => {
|
||||
$scope.workflowChangesUnsaved = true;
|
||||
const nodeId = $scope.nodeConfig.nodeId;
|
||||
if ($scope.nodeConfig.mode === "add") {
|
||||
if (selectedTemplate && edgeType && edgeType.value) {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
fullUnifiedJobTemplateObject: selectedTemplate,
|
||||
promptData,
|
||||
isNew: true
|
||||
};
|
||||
|
||||
if (edgeType && edgeType.value) {
|
||||
if (selectedTemplate) {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
fullUnifiedJobTemplateObject: selectedTemplate,
|
||||
promptData,
|
||||
isNew: true
|
||||
};
|
||||
} else if (pauseNode && pauseNode.isPauseNode) {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
unifiedJobTemplate: {
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description,
|
||||
unified_job_type: "workflow_approval"
|
||||
},
|
||||
isNew: true
|
||||
};
|
||||
}
|
||||
$scope.graphState.nodeBeingAdded = null;
|
||||
|
||||
$scope.graphState.arrayOfLinksForChart.map( (link) => {
|
||||
@ -534,6 +616,7 @@ export default ['$scope', 'TemplatesService',
|
||||
} else if ($scope.nodeConfig.mode === "edit") {
|
||||
if (selectedTemplate) {
|
||||
nodeRef[$scope.nodeConfig.nodeId].fullUnifiedJobTemplateObject = selectedTemplate;
|
||||
nodeRef[$scope.nodeConfig.nodeId].unifiedJobTemplate = selectedTemplate;
|
||||
nodeRef[$scope.nodeConfig.nodeId].promptData = _.cloneDeep(promptData);
|
||||
nodeRef[$scope.nodeConfig.nodeId].isEdited = true;
|
||||
$scope.graphState.nodeBeingEdited = null;
|
||||
@ -546,12 +629,30 @@ export default ['$scope', 'TemplatesService',
|
||||
link.source.unifiedJobTemplate = selectedTemplate;
|
||||
}
|
||||
});
|
||||
} else if (pauseNode && pauseNode.isPauseNode) {
|
||||
// If it's a _new_ pause node then we'll want to create the new ujt
|
||||
// If it's an existing pause node then we'll want to update the ujt
|
||||
nodeRef[$scope.nodeConfig.nodeId].unifiedJobTemplate = {
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description,
|
||||
unified_job_type: "workflow_approval"
|
||||
},
|
||||
nodeRef[$scope.nodeConfig.nodeId].isEdited = true;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.graphState.arrayOfNodesForChart.map( (node) => {
|
||||
if (node.id === nodeId) {
|
||||
node.unifiedJobTemplate = selectedTemplate;
|
||||
if (pauseNode && pauseNode.isPauseNode) {
|
||||
node.unifiedJobTemplate = {
|
||||
unified_job_type: 'workflow_approval',
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description
|
||||
};
|
||||
} else {
|
||||
node.unifiedJobTemplate = selectedTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@
|
||||
</div>
|
||||
<div class="WorkflowMaker-contentRight">
|
||||
<span ng-if="formState.showNodeForm">
|
||||
<workflow-node-form node-config="nodeConfig" workflow-job-template-obj="workflowJobTemplateObj" select="confirmNodeForm(selectedTemplate, promptData, edgeType)" cancel="cancelNodeForm()" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit"/>
|
||||
<workflow-node-form node-config="nodeConfig" workflow-job-template-obj="workflowJobTemplateObj" select="confirmNodeForm(selectedTemplate, promptData, edgeType, pauseNode)" cancel="cancelNodeForm()" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit"/>
|
||||
</span>
|
||||
<span ng-if="formState.showLinkForm">
|
||||
<workflow-link-form link-config="linkConfig" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit" select="confirmLinkForm(edgeType)" cancel="cancelLinkForm()" unlink="unlink()"/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user