diff --git a/awx/ui/client/assets/i_severity_critical.svg b/awx/ui/client/assets/i_severity_critical.svg
new file mode 100644
index 0000000000..996df323a1
--- /dev/null
+++ b/awx/ui/client/assets/i_severity_critical.svg
@@ -0,0 +1,61 @@
+
+
+
+image/svg+xml
diff --git a/awx/ui/client/assets/i_severity_high.svg b/awx/ui/client/assets/i_severity_high.svg
new file mode 100644
index 0000000000..7bd2ba55c8
--- /dev/null
+++ b/awx/ui/client/assets/i_severity_high.svg
@@ -0,0 +1,61 @@
+
+
+
+image/svg+xml
diff --git a/awx/ui/client/assets/i_severity_low.svg b/awx/ui/client/assets/i_severity_low.svg
new file mode 100644
index 0000000000..539664987d
--- /dev/null
+++ b/awx/ui/client/assets/i_severity_low.svg
@@ -0,0 +1,62 @@
+
+
+
+image/svg+xml
diff --git a/awx/ui/client/assets/i_severity_med.svg b/awx/ui/client/assets/i_severity_med.svg
new file mode 100644
index 0000000000..33e3c19c30
--- /dev/null
+++ b/awx/ui/client/assets/i_severity_med.svg
@@ -0,0 +1,62 @@
+
+
+
+image/svg+xml
diff --git a/awx/ui/client/src/inventories/hosts/host.form.js b/awx/ui/client/src/inventories/hosts/host.form.js
index 6f45b7b338..9cfec370d2 100644
--- a/awx/ui/client/src/inventories/hosts/host.form.js
+++ b/awx/ui/client/src/inventories/hosts/host.form.js
@@ -125,7 +125,8 @@ function(i18n) {
awToolTip: i18n._('Please save before viewing Insights'),
dataPlacement: 'top',
title: i18n._('Insights'),
- skipGenerator: true
+ skipGenerator: true,
+ ngIf: 'host.insights_system_id!==null'
}
}
};
diff --git a/awx/ui/client/src/inventories/hosts/hosts.partial.html b/awx/ui/client/src/inventories/hosts/hosts.partial.html
index bdc9a030c8..1f11db98bb 100644
--- a/awx/ui/client/src/inventories/hosts/hosts.partial.html
+++ b/awx/ui/client/src/inventories/hosts/hosts.partial.html
@@ -74,6 +74,9 @@
+
+
+
diff --git a/awx/ui/client/src/inventories/hosts/list/host-list.controller.js b/awx/ui/client/src/inventories/hosts/list/host-list.controller.js
index e906052a79..d88bfadeb3 100644
--- a/awx/ui/client/src/inventories/hosts/list/host-list.controller.js
+++ b/awx/ui/client/src/inventories/hosts/list/host-list.controller.js
@@ -65,6 +65,9 @@ function HostsList($scope, HostsList, $rootScope, GetBasePath,
$scope.editHost = function(id){
$state.go('hosts.edit', {host_id: id});
};
+ $scope.goToInsights = function(id){
+ $state.go('hosts.edit.insights', {host_id:id});
+ };
$scope.deleteHost = function(id, name){
var body = '
Are you sure you want to permanently delete the host below from the inventory?
' + $filter('sanitize')(name) + '
';
var action = function(){
diff --git a/awx/ui/client/src/inventories/insights/insights.block.less b/awx/ui/client/src/inventories/insights/insights.block.less
index 38df774da8..a353bd76f4 100644
--- a/awx/ui/client/src/inventories/insights/insights.block.less
+++ b/awx/ui/client/src/inventories/insights/insights.block.less
@@ -1,5 +1,12 @@
@import "../../shared/branding/colors.default.less";
+.InsightsLastCheck{
+ display: flex;
+ justify-content: flex-end;
+ padding-bottom: 20px;
+ align-items: baseline;
+}
+
.InsightsNav{
width: 100%;
display: flex;
@@ -8,7 +15,6 @@
flex-wrap: wrap;
font-size: 14px;
font-weight: bold;
-
}
.InsightsNav-rightSide{
@@ -16,7 +22,8 @@
display: flex;
flex: 1 0 auto;
flex-wrap: wrap;
- padding: 10px 0px 10px 0px
+ max-width: 100%;
+ padding-left: 10px;
}
.InsightsNav-leftSide{
@@ -26,6 +33,45 @@
justify-content: flex-end;
flex-wrap: wrap;
max-width: 100%;
+ padding-right: 10px;
+}
+
+.InsightsNav-badgeTitle{
+ color: #707070;
+ font-size: 14px;
+ margin-right: 10px;
+ font-weight: normal;
+ text-transform: uppercase;
+ margin-left: 10px;
+}
+
+.InsightsIcon{
+ height: 30px;
+ width:30px;
+}
+
+.InsightsIcon-warning{
+ color:@default-warning;
+ padding-right: 7px;
+}
+
+.InsightsNav-anchor{
+ display:flex;
+ align-items: center;
+ cursor:pointer;
+ height: 40px;
+ padding-right:10px;
+}
+
+.InsightsNav-anchor.is-currentFilter{
+ padding-top: 5px;
+ border-bottom: 5px solid @menu-link-btm-hov;
+}
+
+.InsightsNav-anchor:hover{
+ background-color: @menu-link-bg-hov;
+ padding-top: 5px;
+ border-bottom: 5px solid @menu-link-btm-hov;
}
.InsightsNav-totalIssues{
@@ -42,7 +88,7 @@
}
.InsightsNav-mediumIssues{
- background-color: @default-succ;
+ background-color: @insights-yellow;
}
.InsightsNav-lowIssues{
@@ -52,6 +98,29 @@
.InsightsNav-solvableBadge{
background-color: @b7grey;
}
-.InsightsNav-solvableBadge:last-of-type{
- margin-right: 20px;
+
+.InsightsRow{
+ margin-top:10px;
+}
+.InsightsRow-title{
+ display: flex;
+ align-items: center;
+}
+
+.InsightsRow-description{
+ font-size:14px;
+ font-weight: bold;
+ padding-left: 5px;
+}
+
+.InsightsRow-category{
+ margin-left: 10px;
+}
+
+.InsightsRow-body{
+ padding-left: 35px;
+}
+
+.InsightsRow-plan{
+ padding-left: 35px;
}
diff --git a/awx/ui/client/src/inventories/insights/insights.controller.js b/awx/ui/client/src/inventories/insights/insights.controller.js
index e892b62387..786df445a1 100644
--- a/awx/ui/client/src/inventories/insights/insights.controller.js
+++ b/awx/ui/client/src/inventories/insights/insights.controller.js
@@ -4,13 +4,71 @@
* All Rights Reserved
*************************************************/
-export default [
-function () {
+export default [ 'InsightsData', '$scope', 'moment', '$state', 'resourceData',
+function (data, $scope, moment, $state, resourceData) {
function init() {
- // $scope.insights
+
+ $scope.reports = data.reports;
+ $scope.reports_dataset = data;
+ $scope.currentFilter = "total";
+ $scope.solvable_count = _.filter($scope.reports_dataset.reports, (report) => {return report.maintenance_actions.length > 0;}).length;
+ $scope.not_solvable_count = _.filter($scope.reports_dataset.reports, (report) => {return report.maintenance_actions.length === 0; }).length;
+ $scope.critical_count = 0 || _.filter($scope.reports_dataset.reports, (report) => {return report.rule.severity === "CRITICAL"; }).length;
+ $scope.high_count = _.filter($scope.reports_dataset.reports, (report) => {return report.rule.severity === "ERROR"; }).length;
+ $scope.med_count = _.filter($scope.reports_dataset.reports, (report) => {return report.rule.severity === "WARN"; }).length;
+ $scope.low_count = _.filter($scope.reports_dataset.reports, (report) => {return report.rule.severity === "INFO"; }).length;
+ let a = moment(), b = moment($scope.reports_dataset.last_check_in);
+ $scope.last_check_in = a.diff(b, 'hours');
+ $scope.inventory = resourceData.data;
+ $scope.insights_credential = resourceData.data.summary_fields.insights_credential.id;
}
init();
+ $scope.filter = function(filter){
+ $scope.currentFilter = filter;
+ if(filter === "total"){
+ $scope.reports = $scope.reports_dataset.reports;
+ }
+ if(filter === "solvable"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.maintenance_actions.length > 0);
+ });
+ }
+ if(filter === "not_solvable"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.maintenance_actions.length === 0);
+ });
+ }
+ if(filter === "critical"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.rule.severity === 'CRITICAL');
+ });
+ }
+ if(filter === "high"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.rule.severity === 'ERROR');
+ });
+ }
+ if(filter === "medium"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.rule.severity === 'WARN');
+ });
+ }
+ if(filter === "low"){
+ $scope.reports = _.filter($scope.reports_dataset.reports, function(report){
+ return (report.rule.severity === 'INFO');
+ });
+ }
+ };
+ $scope.viewDataInInsights = function(){
+ window.open(`https://access.redhat.com/insights/inventory?machine=${$scope.$parent.host.insights_system_id}`, '_blank');
+ };
+ $scope.remediateInventory = function(inv_id, inv_name, insights_credential){
+ $state.go('templates.addJobTemplate', {inventory_id: inv_id, inventory_name:inv_name, credential_id: insights_credential});
+ };
+ $scope.formCancel = function(){
+ $state.go('inventories', null, {reload: true});
+ };
}];
diff --git a/awx/ui/client/src/inventories/insights/insights.partial.html b/awx/ui/client/src/inventories/insights/insights.partial.html
index 30268578bc..d0c98ae65e 100644
--- a/awx/ui/client/src/inventories/insights/insights.partial.html
+++ b/awx/ui/client/src/inventories/insights/insights.partial.html
@@ -1,20 +1,81 @@
+
+
+ This machine has not checked in with Insights in {{last_check_in}} hours
+
-
Total Issues
-
4
-
Critical
-
1
-
High
-
1
-
Medium
-
1
-
Low
-
1
+
+
Total Issues
+
{{reports_dataset.reports.length}}
+
+
+
+
Critical
+
{{critical_count}}
+
+
+
High
+
{{high_count}}
+
+
+
Medium
+
{{med_count}}
+
+
-
Solvable With Playbook
-
4
-
Not Solvable With Playbook
-
1
+
+
+
Solvable With Playbook
+
{{solvable_count}}
+
+
+
Not Solvable With Playbook
+
{{not_solvable_count}}
+
+
+
+
+
+
+
+
+
+
ISSUE: {{report.rule.description}}
+
{{report.rule.category}}
+
+
{{report.rule.summary}}
+
+
+
+
+
+ VIEW DATA IN INSIGHTS
+ REMEDIATE INVENTORY
+ Close
+
diff --git a/awx/ui/client/src/inventories/insights/insights.route.js b/awx/ui/client/src/inventories/insights/insights.route.js
index 1bba477d18..3d7cf2c664 100644
--- a/awx/ui/client/src/inventories/insights/insights.route.js
+++ b/awx/ui/client/src/inventories/insights/insights.route.js
@@ -13,15 +13,21 @@ export default {
}
},
resolve: {
- Facts: ['$stateParams', 'GetBasePath', 'Rest',
- function($stateParams, GetBasePath, Rest) {
- let ansibleFactsUrl = GetBasePath('hosts') + $stateParams.host_id + '/ansible_facts';
- Rest.setUrl(ansibleFactsUrl);
+ InsightsData: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors',
+ (Rest, $stateParams, GetBasePath, ProcessErrors) => {
+ var path = `${GetBasePath('hosts')}${$stateParams.host_id}/insights`;
+ Rest.setUrl(path);
return Rest.get()
- .success(function(data) {
- return data;
+ .then(function(data) {
+ return (data.data.insights_content);
+ }).catch(function(response) {
+ ProcessErrors(null, response.data, response.status, null, {
+ hdr: 'Error!',
+ msg: 'Failed to get insights info. GET returned status: ' +
+ response.status
+ });
});
}
- ]
+ ],
}
};
diff --git a/awx/ui/client/src/inventories/insights/main.js b/awx/ui/client/src/inventories/insights/main.js
index 75e05fd1eb..44573e6c9a 100644
--- a/awx/ui/client/src/inventories/insights/main.js
+++ b/awx/ui/client/src/inventories/insights/main.js
@@ -5,7 +5,9 @@
*************************************************/
import controller from './insights.controller';
+import planFilter from './plan-filter';
export default
angular.module('insightsDashboard', [])
+ .filter('planFilter', planFilter)
.controller('InsightsController', controller);
diff --git a/awx/ui/client/src/inventories/insights/plan-filter.js b/awx/ui/client/src/inventories/insights/plan-filter.js
new file mode 100644
index 0000000000..40916cd5ec
--- /dev/null
+++ b/awx/ui/client/src/inventories/insights/plan-filter.js
@@ -0,0 +1,16 @@
+/*************************************************
+ * Copyright (c) 2017 Ansible, Inc.
+ *
+ * All Rights Reserved
+ *************************************************/
+
+ export default function(){
+ return function(plan) {
+ if(plan === null || plan === undefined){
+ return "PLAN: Not Available
CREATE A NEW PLAN IN INSIGHTS ";
+ } else {
+ let name = (plan.maintenance_plan.name === null) ? "Unnamed Plan" : plan.maintenance_plan.name;
+ return `
${name} (${plan.maintenance_plan.maintenance_id}) `;
+ }
+ };
+ }
diff --git a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
index b02c9cbf43..3af8c0c6eb 100644
--- a/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
+++ b/awx/ui/client/src/inventories/related-hosts/list/host-list.controller.js
@@ -86,6 +86,9 @@ export default ['$scope', 'ListDefinition', '$rootScope', 'GetBasePath',
$scope.editHost = function(id){
$state.go('inventories.edit.hosts.edit', {host_id: id});
};
+ $scope.goToInsights = function(id){
+ $state.go('inventories.edit.hosts.edit.insights', {host_id:id});
+ };
$scope.deleteHost = function(id, name){
var body = '
Are you sure you want to permanently delete the host below from the inventory?
' + $filter('sanitize')(name) + '
';
var action = function(){
diff --git a/awx/ui/client/src/inventories/related-hosts/related-host.form.js b/awx/ui/client/src/inventories/related-hosts/related-host.form.js
index 941f98d995..0ad88d8835 100644
--- a/awx/ui/client/src/inventories/related-hosts/related-host.form.js
+++ b/awx/ui/client/src/inventories/related-hosts/related-host.form.js
@@ -125,7 +125,8 @@ function(i18n) {
awToolTip: i18n._('Please save before viewing Insights'),
dataPlacement: 'top',
title: i18n._('Insights'),
- skipGenerator: true
+ skipGenerator: true,
+ ngIf: 'host.insights_system_id!==null'
}
}
};
diff --git a/awx/ui/client/src/inventories/related-hosts/related-host.list.js b/awx/ui/client/src/inventories/related-hosts/related-host.list.js
index c806fbaa58..7e1e114bad 100644
--- a/awx/ui/client/src/inventories/related-hosts/related-host.list.js
+++ b/awx/ui/client/src/inventories/related-hosts/related-host.list.js
@@ -50,6 +50,13 @@ export default {
fieldActions: {
columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right',
+ insights: {
+ ngClick: "goToInsights(host.id)",
+ icon: 'fa-info',
+ awToolTip: 'View Insights Data',
+ dataPlacement: 'top',
+ ngShow: 'host.insights_system_id'
+ },
copy: {
mode: 'all',
ngClick: "copyMoveHost(host.id)",
diff --git a/awx/ui/client/src/inventories/standard/edit/inventory-edit.controller.js b/awx/ui/client/src/inventories/standard/edit/inventory-edit.controller.js
index 205b483779..70500bac10 100644
--- a/awx/ui/client/src/inventories/standard/edit/inventory-edit.controller.js
+++ b/awx/ui/client/src/inventories/standard/edit/inventory-edit.controller.js
@@ -29,6 +29,7 @@ function InventoriesEdit($scope, $location,
$scope = angular.extend($scope, inventoryData);
+ $scope.credential_name = (inventoryData.summary_fields.insights_credential && inventoryData.summary_fields.insights_credential.name) ? inventoryData.summary_fields.insights_credential.name : null;
$scope.organization_name = inventoryData.summary_fields.organization.name;
$scope.inventory_variables = inventoryData.variables === null || inventoryData.variables === '' ? '---' : ParseVariableString(inventoryData.variables);
$scope.parseType = 'yaml';
@@ -90,6 +91,10 @@ function InventoriesEdit($scope, $location,
$state.go('inventories');
};
+ $scope.remediateInventory = function(inv_id, inv_name, insights_credential){
+ $state.go('templates.addJobTemplate', {inventory_id: inv_id, inventory_name:inv_name, credential_id: insights_credential});
+ };
+
}
export default ['$scope', '$location',
diff --git a/awx/ui/client/src/inventories/standard/inventory.form.js b/awx/ui/client/src/inventories/standard/inventory.form.js
index 08e3d8df48..468ab1112f 100644
--- a/awx/ui/client/src/inventories/standard/inventory.form.js
+++ b/awx/ui/client/src/inventories/standard/inventory.form.js
@@ -68,6 +68,17 @@ function(i18n, InventoryCompletedJobsList) {
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd) || !canEditOrg',
awLookupWhen: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd) && canEditOrg'
},
+ insights_credential: {
+ label: i18n._('Insights Credential'),
+ type: 'lookup',
+ list: 'CredentialList',
+ basePath: 'credentials',
+ sourceModel: 'credential',
+ sourceField: 'name',
+ search: {
+ credential_type: 13 //insights
+ }
+ },
inventory_variables: {
realName: 'variables',
label: i18n._('Variables'),
@@ -177,6 +188,14 @@ function(i18n, InventoryCompletedJobsList) {
skipGenerator: true
},
completed_jobs: completed_jobs_object
+ },
+ relatedButtons: {
+ remediate_inventory: {
+ ngClick: 'remediateInventory(id, name, insights_credential)',
+ ngShow: 'insights_credential!==null',
+ label: i18n._('Remediate Inventory'),
+ class: 'Form-primaryButton'
+ }
}
};}];
diff --git a/awx/ui/client/src/projects/add/projects-add.controller.js b/awx/ui/client/src/projects/add/projects-add.controller.js
index 2c90d6448e..a458e1c51e 100644
--- a/awx/ui/client/src/projects/add/projects-add.controller.js
+++ b/awx/ui/client/src/projects/add/projects-add.controller.js
@@ -7,9 +7,10 @@
export default ['$scope', '$location', '$stateParams', 'GenerateForm',
'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath',
'GetProjectPath', 'GetChoices', 'Wait', '$state', 'CreateSelect2', 'i18n',
+ 'CredentialTypes',
function($scope, $location, $stateParams, GenerateForm, ProjectsForm, Rest,
Alert, ProcessErrors, GetBasePath, GetProjectPath, GetChoices, Wait, $state,
- CreateSelect2, i18n) {
+ CreateSelect2, i18n, CredentialTypes) {
var form = ProjectsForm(),
base = $location.path().replace(/^\//, '').split('/')[0],
@@ -121,6 +122,7 @@ export default ['$scope', '$location', '$stateParams', 'GenerateForm',
if ($scope.scm_type.value) {
switch ($scope.scm_type.value) {
case 'git':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '
' +
i18n._('Example URLs for GIT SCM include:') +
'
https://github.com/ansible/ansible.git ' +
@@ -130,11 +132,13 @@ export default ['$scope', '$location', '$stateParams', 'GenerateForm',
'SSH. GIT read only protocol (git://) does not use username or password information.'), '', ' ');
break;
case 'svn':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '' + i18n._('Example URLs for Subversion SCM include:') + '
' +
'https://github.com/ansible/ansible svn://servername.example.com/path ' +
'svn+ssh://servername.example.com/path ';
break;
case 'hg':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '' + i18n._('Example URLs for Mercurial SCM include:') + '
' +
'https://bitbucket.org/username/project ssh://hg@bitbucket.org/username/project ' +
'ssh://server.example.com/path ' +
@@ -142,8 +146,15 @@ export default ['$scope', '$location', '$stateParams', 'GenerateForm',
'Do not put the username and key in the URL. ' +
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '', ' ');
break;
+ case 'insights':
+ $scope.pathRequired = false;
+ $scope.scmRequired = false;
+ $scope.credRequired = true;
+ $scope.credentialLabel = "Credential";
+ break;
default:
- $scope.urlPopover = ' ' + i18n._('URL popover text');
+ $scope.credentialLabel = "SCM Credential";
+ $scope.urlPopover = '
' + i18n._('URL popover text') + '
';
}
}
@@ -151,5 +162,20 @@ export default ['$scope', '$location', '$stateParams', 'GenerateForm',
$scope.formCancel = function() {
$state.go('projects');
};
+ $scope.lookupCredential = function(){
+ // Perform a lookup on the credential_type. Git, Mercurial, and Subversion
+ // all use SCM as their credential type.
+ let credType = _.filter(CredentialTypes, function(credType){
+ return ($scope.scm_type.value !== "insights" && credType.kind === "scm" ||
+ $scope.scm_type.value === "insights" && credType.kind === "insights");
+ });
+ $state.go('.credential', {
+ credential_search: {
+ credential_type: credType[0].id,
+ page_size: '5',
+ page: '1'
+ }
+ });
+ };
}
];
diff --git a/awx/ui/client/src/projects/edit/projects-edit.controller.js b/awx/ui/client/src/projects/edit/projects-edit.controller.js
index 4cb088a638..be0890de12 100644
--- a/awx/ui/client/src/projects/edit/projects-edit.controller.js
+++ b/awx/ui/client/src/projects/edit/projects-edit.controller.js
@@ -8,11 +8,11 @@ export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest',
'Alert', 'ProcessErrors', 'GenerateForm', 'Prompt', 'ClearScope',
'GetBasePath', 'GetProjectPath', 'Authorization', 'GetChoices', 'Empty',
'Wait', 'ProjectUpdate', '$state', 'CreateSelect2', 'ToggleNotification',
- 'i18n',
+ 'i18n', 'CredentialTypes',
function($scope, $rootScope, $stateParams, ProjectsForm, Rest, Alert,
ProcessErrors, GenerateForm, Prompt, ClearScope, GetBasePath,
GetProjectPath, Authorization, GetChoices, Empty, Wait, ProjectUpdate,
- $state, CreateSelect2, ToggleNotification, i18n) {
+ $state, CreateSelect2, ToggleNotification, i18n, CredentialTypes) {
ClearScope('htmlTemplate');
@@ -254,6 +254,7 @@ export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest',
if ($scope.scm_type.value) {
switch ($scope.scm_type.value) {
case 'git':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '' + i18n._('Example URLs for GIT SCM include:') + '
https://github.com/ansible/ansible.git ' +
'git@github.com:ansible/ansible.git git://servername.example.com/ansible.git ' +
'' + i18n.sprintf(i18n._('%sNote:%s When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
@@ -261,11 +262,13 @@ export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest',
'SSH. GIT read only protocol (git://) does not use username or password information.'), '', ' ');
break;
case 'svn':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '
' + i18n._('Example URLs for Subversion SCM include:') + '
' +
'https://github.com/ansible/ansible svn://servername.example.com/path ' +
'svn+ssh://servername.example.com/path ';
break;
case 'hg':
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = '' + i18n._('Example URLs for Mercurial SCM include:') + '
' +
'https://bitbucket.org/username/project ssh://hg@bitbucket.org/username/project ' +
'ssh://server.example.com/path ' +
@@ -273,12 +276,35 @@ export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest',
'Do not put the username and key in the URL. ' +
'If using Bitbucket and SSH, do not supply your Bitbucket username.'), '', ' ');
break;
+ case 'insights':
+ $scope.pathRequired = false;
+ $scope.scmRequired = false;
+ $scope.credRequired = true;
+ $scope.credentialLabel = "Credential";
+ break;
default:
+ $scope.credentialLabel = "SCM Credential";
$scope.urlPopover = ' ' + i18n._('URL popover text');
}
}
};
+ $scope.lookupCredential = function(){
+ // Perform a lookup on the credential_type. Git, Mercurial, and Subversion
+ // all use SCM as their credential type.
+ let credType = _.filter(CredentialTypes, function(credType){
+ return ($scope.scm_type.value !== "insights" && credType.kind === "scm" ||
+ $scope.scm_type.value === "insights" && credType.kind === "insights");
+ });
+ $state.go('.credential', {
+ credential_search: {
+ credential_type: credType[0].id,
+ page_size: '5',
+ page: '1'
+ }
+ });
+ };
+
$scope.SCMUpdate = function() {
if ($scope.project_obj.scm_type === "Manual" || Empty($scope.project_obj.scm_type)) {
// ignore
diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js
index 1b76213cd3..52fa7270b6 100644
--- a/awx/ui/client/src/projects/main.js
+++ b/awx/ui/client/src/projects/main.js
@@ -28,7 +28,24 @@ angular.module('Projects', [revisions.name])
.config(['$stateProvider', 'stateDefinitionsProvider',
function($stateProvider, stateDefinitionsProvider) {
let stateDefinitions = stateDefinitionsProvider.$get();
-
+ var projectResolve = {
+ CredentialTypes: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors',
+ (Rest, $stateParams, GetBasePath, ProcessErrors) => {
+ var path = GetBasePath('credential_types');
+ Rest.setUrl(path);
+ return Rest.get()
+ .then(function(data) {
+ return (data.data.results);
+ }).catch(function(response) {
+ ProcessErrors(null, response.data, response.status, null, {
+ hdr: 'Error!',
+ msg: 'Failed to get credential tpyes. GET returned status: ' +
+ response.status
+ });
+ });
+ }
+ ]
+ };
// lazily generate a tree of substates which will replace this node in ui-router's stateRegistry
// see: stateDefinition.factory for usage documentation
$stateProvider.state({
@@ -55,6 +72,10 @@ angular.module('Projects', [revisions.name])
},
ncyBreadcrumb: {
label: N_('PROJECTS')
+ },
+ resolve: {
+ add: projectResolve,
+ edit: projectResolve
}
})
});
diff --git a/awx/ui/client/src/projects/projects.form.js b/awx/ui/client/src/projects/projects.form.js
index 8297213be7..7399546d68 100644
--- a/awx/ui/client/src/projects/projects.form.js
+++ b/awx/ui/client/src/projects/projects.form.js
@@ -131,9 +131,10 @@ export default ['i18n', 'NotificationsList', function(i18n, NotificationsList) {
basePath: 'credentials',
list: 'CredentialList',
// apply a default search filter to show only scm credentials
- search: {
- kind: 'scm'
- },
+ // search: {
+ // kind: 'scm'
+ // },
+ ngClick: 'lookupCredential()',
autopopulateLookup: false,
awRequiredWhen: {
reqExpression: "credRequired",
diff --git a/awx/ui/client/src/shared/branding/colors.default.less b/awx/ui/client/src/shared/branding/colors.default.less
index b6216f524e..1f7ca0b2d0 100644
--- a/awx/ui/client/src/shared/branding/colors.default.less
+++ b/awx/ui/client/src/shared/branding/colors.default.less
@@ -23,6 +23,7 @@
@egrey: #EEEEEE;
@cgrey: #CCCCCC;
@f7grey: #F7F7F7;
+@insights-yellow: #dedc4f;
@default-warning: #F0AD4E;
diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js
index 96f0457fae..cf6b300ba5 100644
--- a/awx/ui/client/src/shared/form-generator.js
+++ b/awx/ui/client/src/shared/form-generator.js
@@ -1507,6 +1507,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
collection = this.form.related[itm];
html += `