From 161c320f051f6c356e21edd81a46451c4ba111e5 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Mon, 7 Nov 2016 17:25:04 -0500 Subject: [PATCH] More integration work - getting to the point where you can add nodes to the workflow after integrating with smart search. --- .../edit-workflow/workflow-edit.controller.js | 2 +- awx/ui/client/src/job-templates/main.js | 148 ++++++++---- .../workflow-maker/workflow-help.service.js | 46 +--- .../workflow-maker.controller.js | 218 ++++-------------- awx/ui/client/src/shared/form-generator.js | 6 +- .../shared/lookup/lookup-modal.directive.js | 3 + .../shared/lookup/lookup-modal.partial.html | 4 +- .../src/shared/stateDefinitions.factory.js | 2 +- awx/ui/grunt-tasks/browserSync.js | 8 +- 9 files changed, 169 insertions(+), 268 deletions(-) diff --git a/awx/ui/client/src/job-templates/edit-workflow/workflow-edit.controller.js b/awx/ui/client/src/job-templates/edit-workflow/workflow-edit.controller.js index 18a07e5fe5..b79b10ce83 100644 --- a/awx/ui/client/src/job-templates/edit-workflow/workflow-edit.controller.js +++ b/awx/ui/client/src/job-templates/edit-workflow/workflow-edit.controller.js @@ -14,7 +14,7 @@ ClearScope, GetBasePath, $q, ParseTypeChange, Wait, Empty, ToJSON, SurveyControllerInit, $state, CreateSelect2, ParseVariableString, JobTemplateService, OrganizationList, Rest - ) { + ) {window.state = $state; ClearScope(); diff --git a/awx/ui/client/src/job-templates/main.js b/awx/ui/client/src/job-templates/main.js index 6b2ea34945..ba0fae8dd5 100644 --- a/awx/ui/client/src/job-templates/main.js +++ b/awx/ui/client/src/job-templates/main.js @@ -76,10 +76,17 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp workflowMaker = { name: 'templates.editWorkflowJobTemplate.workflowMaker', url: '/workflow-maker', + // ncyBreadcrumb: { + // label: 'WORKFLOW MAKER' + // }, + data: { + formChildState: true + }, params: { - template_search: { + job_template_search: { value: { - page_size: '5' + page_size: '5', + type: 'job_template' }, squash: true, dynamic: true @@ -104,26 +111,18 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp template: ` ` }, 'jobTemplateList@templates.editWorkflowJobTemplate.workflowMaker': { - templateProvider: function(JobTemplateList, generateList) { - let list = _.cloneDeep(JobTemplateList); - delete list.fields.type; - delete list.fields.description; - delete list.fields.smart_status; - delete list.fields.labels; - delete list.fieldActions; - list.fields.name.columnClass = "col-md-11"; + templateProvider: function(WorkflowMakerJobTemplateList, generateList) { + //debugger; let html = generateList.build({ - list: list, + list: WorkflowMakerJobTemplateList, input_type: 'radio', mode: 'lookup' }); return html; }, // $scope encapsulated in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy - controller: ['$scope', 'JobTemplateList', 'JobTemplateDataset', '$log', - function($scope, list, Dataset, $log) { - // name of this tab - let tab = 'jobs'; + controller: ['$scope', 'WorkflowMakerJobTemplateList', 'JobTemplateDataset', + function($scope, list, Dataset) { init(); @@ -133,14 +132,25 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp $scope[list.name] = $scope[`${list.iterator}_dataset`].results; } - // resets any selected list items, if this tab is not active - $scope.$on('resetWorkflowList', function(e, active) { - // e.targetScope is a reference to the outer scope if you need to manipulate it! + $scope.toggle_job_template = function(id) { - // a reference to the currently-selected radio is stored in $scope.selection[list.iterator] - // clear it out! - if (active !== tab) { - $scope.selection[list.iterator] = null; + $scope.job_templates.forEach(function(row, i) { + if (row.id === id) { + $scope.job_templates[i].checked = 1; + $scope.selection[list.iterator] = { + id: row.id, + name: row.name + }; + + $scope.$emit('templateSelected', row); + } + }); + + }; + + $scope.$on('clearOtherTemplateLists', function(e, tab) { + if(tab !== 'jobs') { + // Clear out any selected job } }); } @@ -160,7 +170,6 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp // encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy controller: ['$scope', 'InventorySourcesList', 'InventorySourcesDataset', function($scope, list, Dataset) { - let tab = 'inventory_sync'; init(); @@ -171,35 +180,42 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp } - // resets any selected list items, if this tab is not active - $scope.$on('resetWorkflowList', function(e, active) { - // e.targetScope is a reference to the outer scope if you need to manipulate it! + $scope.toggle_inventory_source = function(id) { + + $scope.inventory_sources.forEach(function(row, i) { + if (row.id === id) { + $scope.inventory_sources[i].checked = 1; + $scope.selection[list.iterator] = { + id: row.id, + name: row.name + }; + + $scope.$emit('templateSelected', row); + } + }); + + }; + + $scope.$on('clearOtherTemplateLists', function(e, tab) { + if(tab !== 'project_sync') { - if (active !== tab) { - $scope.selection[list.iterator] = null; } }); } ] }, 'projectSyncList@templates.editWorkflowJobTemplate.workflowMaker': { - templateProvider: function(ProjectList, generateList) { - let list = _.cloneDeep(ProjectList); - delete list.fields.status; - delete list.fields.scm_type; - delete list.fields.last_updated; - list.fields.name.columnClass = "col-md-11"; + templateProvider: function(WorkflowProjectList, generateList) { let html = generateList.build({ - list: list, + list: WorkflowProjectList, input_type: 'radio', mode: 'lookup' }); return html; }, // encapsulated $scope in this controller will be a initialized as child of 'modal' $scope, because of element hierarchy - controller: ['$scope', 'ProjectList', 'ProjectDataset', + controller: ['$scope', 'WorkflowProjectList', 'ProjectDataset', function($scope, list, Dataset) { - let tab = 'project_sync'; init(); @@ -209,12 +225,26 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp $scope[list.name] = $scope[`${list.iterator}_dataset`].results; } - // resets any selected list items, if this tab is not active - $scope.$on('resetWorkflowList', function(e, active) { - // e.targetScope is a reference to the outer scope if you need to manipulate it! - if (active !== tab) { - $scope.selection[list.iterator] = null; + $scope.toggle_project = function(id) { + + $scope.projects.forEach(function(row, i) { + if (row.id === id) { + $scope.projects[i].checked = 1; + $scope.selection[list.iterator] = { + id: row.id, + name: row.name + }; + + $scope.$emit('templateSelected', row); + } + }); + + }; + + $scope.$on('clearOtherTemplateLists', function(e, tab) { + if(tab !== 'inventory_sync') { + } }); } @@ -233,7 +263,7 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp } }, resolve: { - JobTemplateDataset: ['JobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath', + JobTemplateDataset: ['WorkflowMakerJobTemplateList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => { let path = GetBasePath(list.basePath); return qs.search(path, $stateParams[`${list.iterator}_search`]); @@ -250,6 +280,32 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp let path = GetBasePath(list.basePath); return qs.search(path, $stateParams[`${list.iterator}_search`]); } + ], + WorkflowMakerJobTemplateList: ['JobTemplateList', + (JobTemplateList) => { + let list = _.cloneDeep(JobTemplateList); + delete list.fields.type; + delete list.fields.description; + delete list.fields.smart_status; + delete list.fields.labels; + delete list.fieldActions; + list.fields.name.columnClass = "col-md-11"; + list.iterator = 'job_template'; + list.name = 'job_templates'; + + return list; + } + ], + WorkflowProjectList: ['ProjectList', + (ProjectList) => { + let list = _.cloneDeep(ProjectList); + delete list.fields.status; + delete list.fields.scm_type; + delete list.fields.last_updated; + list.fields.name.columnClass = "col-md-11"; + + return list; + } ] } }; @@ -259,7 +315,7 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp name: 'templates.editWorkflowJobTemplate.workflowMaker.inventory', url: '/inventory', data: { - lookup: true + formChildState: true }, params: { inventory_search: { @@ -309,7 +365,7 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp name: 'templates.editWorkflowJobTemplate.workflowMaker.credential', url: '/credential', data: { - lookup: true + formChildState: true }, params: { credential_search: { @@ -334,7 +390,7 @@ angular.module('jobTemplates', [surveyMaker.name, jobTemplatesList.name, jobTemp } }, resolve: { - ListDefinition: ['ListDefinition', function(list) { + ListDefinition: ['CredentialList', function(list) { // mutate the provided list definition here return list; }], diff --git a/awx/ui/client/src/job-templates/workflow-maker/workflow-help.service.js b/awx/ui/client/src/job-templates/workflow-maker/workflow-help.service.js index 24c7fd9679..25b889e4fd 100644 --- a/awx/ui/client/src/job-templates/workflow-maker/workflow-help.service.js +++ b/awx/ui/client/src/job-templates/workflow-maker/workflow-help.service.js @@ -1,49 +1,9 @@ -export default ['CreateDialog', 'Wait', '$q', function(CreateDialog, Wait, $q){ +export default ['CreateDialog', 'Wait', '$q', '$state', function(CreateDialog, Wait, $q, $state){ return { - openDialog: function(params){ - // params.scope - - // let deferred = $q.defer(); - - // if (params.scope.removeWorkflowDialogReady) { - // params.scope.removeWorkflowDialogReady(); - // } - // params.scope.removeWorkflowDialogReady = params.scope.$on('WorkflowDialogReady', function() { - // $('#workflow-modal-dialog').dialog('open'); - - // deferred.resolve(); - // }); - // Wait('start'); - // debugger; - // CreateDialog({ - // id: 'workflow-modal-dialog', - // scope: params.scope, - // width: 1400, - // height: 720, - // draggable: false, - // dialogClass: 'SurveyMaker-dialog', - // position: ['center',20], - // onClose: function() { - // $('#workflow-modal-dialog').empty(); - // }, - // onOpen: function() { - // Wait('stop'); - - // // Let the modal height be variable based on the content - // // and set a uniform padding - // $('#workflow-modal-dialog').css({'padding': '20px'}); - - // }, - // _allowInteraction: function(e) { - // return !!$(e.target).is('.select2-input') || this._super(e); - // }, - // callback: 'WorkflowDialogReady' - // }); - - // return deferred.promise; - }, closeDialog: function() { $('#workflow-modal-dialog').dialog('destroy'); + + $state.go('^'); }, searchTree: function(params) { // params.element diff --git a/awx/ui/client/src/job-templates/workflow-maker/workflow-maker.controller.js b/awx/ui/client/src/job-templates/workflow-maker/workflow-maker.controller.js index 498dd73965..c68a4fbf63 100644 --- a/awx/ui/client/src/job-templates/workflow-maker/workflow-maker.controller.js +++ b/awx/ui/client/src/job-templates/workflow-maker/workflow-maker.controller.js @@ -32,78 +32,10 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateLis value: "check" }]; - let job_template_url = GetBasePath('job_templates'); - // TODO: we won't be able to rely on this in the future for security purposes. Will need to come up - // with another way to get the list of job templates that have credentials that don't require passwords - // on launch - job_template_url += "?not__credential__vault_password=ASK¬__credential__password=ASK"; - //http://localhost:3000/api/v1/job_templates/?not__credential__vault_password=ASK¬__credential__password=ASK - - // Set up the lists for the add/edit node form - // let jobTemplatesList = _.cloneDeep(JobTemplateList); - // delete jobTemplatesList.fields.type; - // delete jobTemplatesList.fields.description; - // delete jobTemplatesList.fields.smart_status; - // delete jobTemplatesList.fields.labels; - // jobTemplatesList.fields.name.columnClass = "col-md-11"; - // jobTemplatesList.name = "workflow_job_templates"; - - // let project_url = GetBasePath('projects'); - - // let projectList = _.cloneDeep(ProjectList); - // delete projectList.fields.status; - // delete projectList.fields.scm_type; - // delete projectList.fields.last_updated; - // projectList.fields.name.columnClass = "col-md-11"; - // projectList.name = "workflow_projects"; - - //let inventory_sources_url = GetBasePath('inventory_sources'); - - //let inventorySourcesList = _.cloneDeep(InventorySourcesList); - function init() { $scope.treeDataMaster = angular.copy($scope.treeData.data); $scope.$broadcast("refreshWorkflowChart"); - $scope.$watchCollection('workflow_job_templates', function() { - if ($scope.selectedTemplate) { - // Loop across the inventories and see if one of them should be "checked" - $scope.workflow_job_templates.forEach(function(row, i) { - if (row.id === $scope.selectedTemplate.id) { - $scope.workflow_job_templates[i].checked = 1; - } else { - $scope.workflow_job_templates[i].checked = 0; - } - }); - } - }); - - $scope.$watchCollection('workflow_projects', function() { - if ($scope.selectedTemplate) { - // Loop across the inventories and see if one of them should be "checked" - $scope.workflow_projects.forEach(function(row, i) { - if (row.id === $scope.selectedTemplate.id) { - $scope.workflow_projects[i].checked = 1; - } else { - $scope.workflow_projects[i].checked = 0; - } - }); - } - }); - - $scope.$watchCollection('workflow_inventory_sources', function() { - if ($scope.selectedTemplate) { - // Loop across the inventories and see if one of them should be "checked" - $scope.workflow_inventory_sources.forEach(function(row, i) { - if (row.id === $scope.selectedTemplate.id) { - $scope.workflow_inventory_sources[i].checked = 1; - } else { - $scope.workflow_inventory_sources[i].checked = 0; - } - }); - } - }); - $scope.$watchGroup(['selectedTemplate', 'edgeType'], function() { if ($scope.selectedTemplate && $scope.edgeType) { $scope.workflowMakerFormConfig.formIsValid = true; @@ -143,7 +75,11 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateLis } $scope.lookUpInventory = function(){ - $state.go('.inventory') + $state.go('.inventory'); + }; + + $scope.lookUpCredential = function(){ + $state.go('.credential'); }; $scope.closeWorkflowMaker = function() { @@ -540,123 +476,63 @@ export default ['$scope', 'WorkflowHelpService', 'generateList', 'JobTemplateLis }; $scope.toggleFormTab = function(tab) { - // a dictionary of settings required by each encapsulated tab - $scope.$broadcast('resetWorkflowList', tab); if ($scope.workflowMakerFormConfig.activeTab !== tab) { $scope.workflowMakerFormConfig.activeTab = tab; } }; - $scope.toggle_job_template = function(id) { - - // $scope.workflow_projects.forEach(function(row, i) { - // $scope.workflow_projects[i].checked = 0; - // }); - - // $scope.workflow_inventory_sources.forEach(function(row, i) { - // $scope.workflow_inventory_sources[i].checked = 0; - // }); - - $scope.workflow_job_templates.forEach(function(row, i) { - if (row.id === id) { - $scope.selectedTemplate = angular.copy(row); - if ($scope.selectedTemplate.ask_credential_on_launch) { - if ($scope.selectedTemplate.summary_fields.credential) { - $scope.credential_name = $scope.selectedTemplate.summary_fields.credential.name ? $scope.selectedTemplate.summary_fields.credential.name : null; - $scope.credential = $scope.selectedTemplate.summary_fields.credential.id ? $scope.selectedTemplate.summary_fields.credential.id : null; - } else { - $scope.credential_name = null; - $scope.credential = null; - } - } - - if ($scope.selectedTemplate.ask_inventory_on_launch) { - if ($scope.selectedTemplate.summary_fields.inventory) { - $scope.inventory_name = $scope.selectedTemplate.summary_fields.inventory.name ? $scope.selectedTemplate.summary_fields.inventory.name : null; - $scope.inventory = $scope.selectedTemplate.summary_fields.inventory.id ? $scope.selectedTemplate.summary_fields.inventory.id : null; - } else { - $scope.inventory_name = null; - $scope.inventory = null; - } - } - - if ($scope.selectedTemplate.ask_job_type_on_launch) { - $scope.job_type = { - value: $scope.selectedTemplate.job_type ? $scope.selectedTemplate.job_type : null - }; - - // The default needs to be in place before we can select2-ify the dropdown - CreateSelect2({ - element: '#workflow_maker_job_type', - multiple: false - }); - } - - if ($scope.selectedTemplate.ask_limit_on_launch) { - $scope.limit = $scope.selectedTemplate.limit ? $scope.selectedTemplate.limit : null; - } - - if ($scope.selectedTemplate.ask_skip_tags_on_launch) { - $scope.skip_tags = $scope.selectedTemplate.skip_tags ? $scope.selectedTemplate.skip_tags : null; - } - - if ($scope.selectedTemplate.ask_tags_on_launch) { - $scope.job_tags = $scope.selectedTemplate.job_tags ? $scope.selectedTemplate.job_tags : null; - } - - $scope.workflow_job_templates[i].checked = 1; - } else { - $scope.workflow_job_templates[i].checked = 0; - } - }); - - }; - - $scope.toggle_project = function(id) { + $scope.$on('templateSelected', function(e, selectedTemplate) { resetPromptFields(); - // $scope.workflow_job_templates.forEach(function(row, i) { - // $scope.workflow_job_templates[i].checked = 0; - // }); + $scope.selectedTemplate = angular.copy(selectedTemplate); - // $scope.workflow_inventory_sources.forEach(function(row, i) { - // $scope.workflow_inventory_sources[i].checked = 0; - // }); - - $scope.workflow_projects.forEach(function(row, i) { - if (row.id === id) { - $scope.selectedTemplate = angular.copy(row); - $scope.workflow_projects[i].checked = 1; + if ($scope.selectedTemplate.ask_credential_on_launch) { + if ($scope.selectedTemplate.summary_fields.credential) { + $scope.credential_name = $scope.selectedTemplate.summary_fields.credential.name ? $scope.selectedTemplate.summary_fields.credential.name : null; + $scope.credential = $scope.selectedTemplate.summary_fields.credential.id ? $scope.selectedTemplate.summary_fields.credential.id : null; } else { - $scope.workflow_projects[i].checked = 0; + $scope.credential_name = null; + $scope.credential = null; } - }); + } - }; - - $scope.toggle_inventory_source = function(id) { - - resetPromptFields(); - - // $scope.workflow_job_templates.forEach(function(row, i) { - // $scope.workflow_job_templates[i].checked = 0; - // }); - - // $scope.workflow_projects.forEach(function(row, i) { - // $scope.workflow_projects[i].checked = 0; - // }); - - $scope.workflow_inventory_sources.forEach(function(row, i) { - if (row.id === id) { - $scope.selectedTemplate = angular.copy(row); - $scope.workflow_inventory_sources[i].checked = 1; + if ($scope.selectedTemplate.ask_inventory_on_launch) { + if ($scope.selectedTemplate.summary_fields.inventory) { + $scope.inventory_name = $scope.selectedTemplate.summary_fields.inventory.name ? $scope.selectedTemplate.summary_fields.inventory.name : null; + $scope.inventory = $scope.selectedTemplate.summary_fields.inventory.id ? $scope.selectedTemplate.summary_fields.inventory.id : null; } else { - $scope.workflow_inventory_sources[i].checked = 0; + $scope.inventory_name = null; + $scope.inventory = null; } - }); + } - }; + if ($scope.selectedTemplate.ask_job_type_on_launch) { + $scope.job_type = { + value: $scope.selectedTemplate.job_type ? $scope.selectedTemplate.job_type : null + }; + + // The default needs to be in place before we can select2-ify the dropdown + CreateSelect2({ + element: '#workflow_maker_job_type', + multiple: false + }); + } + + if ($scope.selectedTemplate.ask_limit_on_launch) { + $scope.limit = $scope.selectedTemplate.limit ? $scope.selectedTemplate.limit : null; + } + + if ($scope.selectedTemplate.ask_skip_tags_on_launch) { + $scope.skip_tags = $scope.selectedTemplate.skip_tags ? $scope.selectedTemplate.skip_tags : null; + } + + if ($scope.selectedTemplate.ask_tags_on_launch) { + $scope.job_tags = $scope.selectedTemplate.job_tags ? $scope.selectedTemplate.job_tags : null; + } + + $scope.$broadcast('clearOtherTemplateLists', $scope.workflowMakerFormConfig.activeTab); + }); init(); diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 955a5d1e7e..d0cfb46a92 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1274,7 +1274,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat if(this.mode === "edit"){ html += `
` + + `ng-class="{'is-selected': $state.is('${this.form.activeEditState}') || $state.is('${this.form.stateTree}.edit') || $state.$current.data.formChildState }">` + `${details}
`; for (itm in this.form.related) { @@ -1372,8 +1372,8 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += "";//tabHolder } - if(!_.isEmpty(this.form.related) && this.mode === "edit"){ - html += `
`; + if(!_.isEmpty(this.form.related) && this.mode === "edit"){// TODO: either include $state.is('templates.editWorkflowJobTemplate') or figure out something else to do here + html += `
`; } html += "
-
@@ -16,7 +16,7 @@
diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index 79170ac8bb..d3c5806698 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -372,7 +372,7 @@ export default ['$injector', '$stateExtender', '$log', function($injector, $stat // a lookup field's basePath takes precedence over generic list definition's basePath, if supplied data: { basePath: field.basePath || null, - lookup: true + formChildState: true }, params: { [field.sourceModel + '_search']: { diff --git a/awx/ui/grunt-tasks/browserSync.js b/awx/ui/grunt-tasks/browserSync.js index 107444ae0f..b4c9e179c6 100644 --- a/awx/ui/grunt-tasks/browserSync.js +++ b/awx/ui/grunt-tasks/browserSync.js @@ -17,7 +17,13 @@ module.exports = { ws: true }, keepalive: false, - watchTask: true + watchTask: true, + // The browser-sync-client lib will write your current scroll position to window.name + // https://github.com/BrowserSync/browser-sync-client/blob/a2718faa91e11553feca7a3962313bf1ec6ba3e5/dist/index.js#L500 + // This strategy is enabled in the core browser-sync lib, and not externally documented as an option. Yay! + // https://github.com/BrowserSync/browser-sync/blob/a522aaf12b6167d5591ed285eb3086f43a4d9ac2/lib/default-config.js#L312 + scrollRestoreTechnique: null, + injectChanges: true } } };