mirror of
https://github.com/ansible/awx.git
synced 2026-03-19 18:07:33 -02:30
Merge pull request #6836 from mabashian/6656-multiselect-preview
Added multi-select preview to group/host associate and instance groups modals
This commit is contained in:
@@ -13,7 +13,7 @@ export default {
|
|||||||
controller: function($scope, $q, GroupsService, $state){
|
controller: function($scope, $q, GroupsService, $state){
|
||||||
$scope.associateGroups = function(selectedItems){
|
$scope.associateGroups = function(selectedItems){
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) )
|
return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) )
|
||||||
.then( () =>{
|
.then( () =>{
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
controller: function($scope, $q, GroupsService, $state){
|
controller: function($scope, $q, GroupsService, $state){
|
||||||
$scope.associateGroups = function(selectedItems){
|
$scope.associateGroups = function(selectedItems){
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
return $q.all( _.map(selectedItems, (id) => GroupsService.associateGroup({id: id}, $state.params.group_id)) )
|
return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateGroup({id: selectedItem.id}, $state.params.group_id)) )
|
||||||
.then( () =>{
|
.then( () =>{
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
controller: function($scope, $q, GroupsService, $state){
|
controller: function($scope, $q, GroupsService, $state){
|
||||||
$scope.associateHosts = function(selectedItems){
|
$scope.associateHosts = function(selectedItems){
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: id}, $state.params.group_id)) )
|
return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: selectedItem.id}, $state.params.group_id)) )
|
||||||
.then( () =>{
|
.then( () =>{
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
controller: function($scope, $q, GroupsService, $state){
|
controller: function($scope, $q, GroupsService, $state){
|
||||||
$scope.associateGroups = function(selectedItems){
|
$scope.associateGroups = function(selectedItems){
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
return $q.all( _.map(selectedItems, (id) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, id)) )
|
return $q.all( _.map(selectedItems, (selectedItem) => GroupsService.associateHost({id: parseInt($state.params.host_id)}, selectedItem.id)) )
|
||||||
.then( () =>{
|
.then( () =>{
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
|
|||||||
@@ -35,6 +35,10 @@
|
|||||||
list.multiSelect = true;
|
list.multiSelect = true;
|
||||||
list.fields.name.ngClick = 'linkoutGroup(associate_group.id)';
|
list.fields.name.ngClick = 'linkoutGroup(associate_group.id)';
|
||||||
list.trackBy = 'associate_group.id';
|
list.trackBy = 'associate_group.id';
|
||||||
|
list.multiSelectPreview = {
|
||||||
|
selectedRows: 'selectedItems',
|
||||||
|
availableRows: 'associate_groups'
|
||||||
|
};
|
||||||
delete list.actions;
|
delete list.actions;
|
||||||
delete list.fieldActions;
|
delete list.fieldActions;
|
||||||
delete list.fields.failed_hosts;
|
delete list.fields.failed_hosts;
|
||||||
@@ -58,9 +62,11 @@
|
|||||||
$scope.$watchCollection('associate_groups', function () {
|
$scope.$watchCollection('associate_groups', function () {
|
||||||
if($scope.selectedItems) {
|
if($scope.selectedItems) {
|
||||||
$scope.associate_groups.forEach(function(row, i) {
|
$scope.associate_groups.forEach(function(row, i) {
|
||||||
if (_.includes($scope.selectedItems, row.id)) {
|
$scope.selectedItems.forEach(function(selectedItem) {
|
||||||
$scope.associate_groups[i].isSelected = true;
|
if(selectedItem.id === row.id) {
|
||||||
}
|
$scope.associate_groups[i].isSelected = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -72,14 +78,14 @@
|
|||||||
let item = value.value;
|
let item = value.value;
|
||||||
|
|
||||||
if (value.isSelected) {
|
if (value.isSelected) {
|
||||||
$scope.selectedItems.push(item.id);
|
$scope.selectedItems.push(item);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// _.remove() Returns the new array of removed elements.
|
// _.remove() Returns the new array of removed elements.
|
||||||
// This will pull all the values out of the array that don't
|
// This will pull all the values out of the array that don't
|
||||||
// match the deselected item effectively removing it
|
// match the deselected item effectively removing it
|
||||||
$scope.selectedItems = _.remove($scope.selectedItems, function(selectedItem) {
|
$scope.selectedItems = _.remove($scope.selectedItems, function(selectedItem) {
|
||||||
return selectedItem !== item.id;
|
return selectedItem.id !== item.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header Form-header">
|
<div class="modal-header Form-header">
|
||||||
<div class="Form-title Form-title--uppercase">SELECT GROUP</div>
|
<div class="Form-title Form-title--uppercase">SELECT GROUPS</div>
|
||||||
<div class="Form-header--fields"></div>
|
<div class="Form-header--fields"></div>
|
||||||
<div class="Form-exitHolder">
|
<div class="Form-exitHolder">
|
||||||
<button type="button" class="Form-exit" ng-click="closeModal()">
|
<button type="button" class="Form-exit" ng-click="closeModal()">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header Form-header">
|
<div class="modal-header Form-header">
|
||||||
<div class="Form-title Form-title--uppercase">SELECT HOST</div>
|
<div class="Form-title Form-title--uppercase">SELECT HOSTS</div>
|
||||||
<div class="Form-header--fields"></div>
|
<div class="Form-header--fields"></div>
|
||||||
<div class="Form-exitHolder">
|
<div class="Form-exitHolder">
|
||||||
<button type="button" class="Form-exit" ng-click="closeModal()">
|
<button type="button" class="Form-exit" ng-click="closeModal()">
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ export default ['templateUrl', function(templateUrl) {
|
|||||||
instanceGroupList.listTitle = false;
|
instanceGroupList.listTitle = false;
|
||||||
instanceGroupList.well = false;
|
instanceGroupList.well = false;
|
||||||
instanceGroupList.multiSelect = true;
|
instanceGroupList.multiSelect = true;
|
||||||
instanceGroupList.multiSelectExtended = true;
|
instanceGroupList.multiSelectPreview = {
|
||||||
|
selectedRows: 'igTags',
|
||||||
|
availableRows: 'instance_groups'
|
||||||
|
};
|
||||||
delete instanceGroupList.fields.percent_capacity_remaining;
|
delete instanceGroupList.fields.percent_capacity_remaining;
|
||||||
delete instanceGroupList.fields.jobs_running;
|
delete instanceGroupList.fields.jobs_running;
|
||||||
|
|
||||||
@@ -104,4 +107,4 @@ export default ['templateUrl', function(templateUrl) {
|
|||||||
};
|
};
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ export default ['$compile', 'Attr', 'Icon',
|
|||||||
html += "</div>\n";
|
html += "</div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list.multiSelectPreview) {
|
||||||
|
html += "<multi-select-preview selected-rows='" + list.multiSelectPreview.selectedRows + "' available-rows='" + list.multiSelectPreview.availableRows + "'></multi-select-preview>";
|
||||||
|
}
|
||||||
|
|
||||||
if (options.instructions) {
|
if (options.instructions) {
|
||||||
html += "<div class=\"instructions alert alert-info\">" + options.instructions + "</div>\n";
|
html += "<div class=\"instructions alert alert-info\">" + options.instructions + "</div>\n";
|
||||||
} else if (list.instructions) {
|
} else if (list.instructions) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import directives from './directives';
|
|||||||
import features from './features/main';
|
import features from './features/main';
|
||||||
import orgAdminLookup from './org-admin-lookup/main';
|
import orgAdminLookup from './org-admin-lookup/main';
|
||||||
import limitPanels from './limit-panels/main';
|
import limitPanels from './limit-panels/main';
|
||||||
|
import multiSelectPreview from './multi-select-preview/main';
|
||||||
import 'angular-duration-format';
|
import 'angular-duration-format';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@@ -61,6 +62,7 @@ angular.module('shared', [listGenerator.name,
|
|||||||
features.name,
|
features.name,
|
||||||
orgAdminLookup.name,
|
orgAdminLookup.name,
|
||||||
limitPanels.name,
|
limitPanels.name,
|
||||||
|
multiSelectPreview.name,
|
||||||
require('angular-cookies'),
|
require('angular-cookies'),
|
||||||
'angular-duration-format'
|
'angular-duration-format'
|
||||||
])
|
])
|
||||||
|
|||||||
11
awx/ui/client/src/shared/multi-select-preview/main.js
Normal file
11
awx/ui/client/src/shared/multi-select-preview/main.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2017 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
import multiSelectPreview from './multi-select-preview.directive';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('multiSelectPreview', [])
|
||||||
|
.directive('multiSelectPreview', multiSelectPreview);
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
@import '../branding/colors.default.less';
|
||||||
|
|
||||||
|
.MultiSelectPreview {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-selectedItems {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 100%;
|
||||||
|
background-color: @default-no-items-bord;
|
||||||
|
border: 1px solid @default-border;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-selectedItemsLabel, .MultiSelectPreview-label {
|
||||||
|
color: @default-interface-txt;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-selectedItemsLabel {
|
||||||
|
flex: 0 0 80px;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTags--outer {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
max-width: ~"calc(100% - 140px)";
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTags--inner {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagContainer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagRevert {
|
||||||
|
flex: 0 0 60px;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-revertLink {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagContainerDelete {
|
||||||
|
background-color: @default-link;
|
||||||
|
border-top-left-radius: 5px;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
color: @default-bg;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 4px 0px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagContainerDelete:hover {
|
||||||
|
border-color: @default-err;
|
||||||
|
background-color: @default-err;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagContainerDelete:hover > .MultiSelectPreview-previewTagContainerTagDelete {
|
||||||
|
color: @default-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTag {
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
margin: 4px 0px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: @default-interface-txt;
|
||||||
|
background-color: @default-list-header-bg;
|
||||||
|
margin-right: 5px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTagLabel {
|
||||||
|
color: @default-list-header-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MultiSelectPreview-previewTag--deletable {
|
||||||
|
color: @default-bg;
|
||||||
|
background-color: @default-link;
|
||||||
|
margin-right: 0px;
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
border-right: 0;
|
||||||
|
max-width: ~"calc(100% - 23px)";
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2017 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
export default ['$scope',
|
||||||
|
function ($scope) {
|
||||||
|
$scope.unselectSelectedRow = function(index) {
|
||||||
|
|
||||||
|
angular.forEach($scope.availableRows, function(value) {
|
||||||
|
if(value.id === $scope.selectedRows[index].id) {
|
||||||
|
value.isSelected = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.selectedRows.splice(index, 1);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2017 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
import MultiSelectPreviewController from './multi-select-preview.controller';
|
||||||
|
|
||||||
|
export default ['templateUrl', function(templateUrl) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
replace: true,
|
||||||
|
scope: {
|
||||||
|
selectedRows: '=',
|
||||||
|
availableRows: '='
|
||||||
|
},
|
||||||
|
controller: MultiSelectPreviewController,
|
||||||
|
templateUrl: templateUrl('shared/multi-select-preview/multi-select-preview')
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="MultiSelectPreview" ng-show="selectedRows.length > 0">
|
||||||
|
<div class="MultiSelectPreview-selectedItems">
|
||||||
|
<div class="MultiSelectPreview-selectedItemsLabel">
|
||||||
|
<span>SELECTED:</span>
|
||||||
|
</div>
|
||||||
|
<div class="MultiSelectPreview-previewTags--outer">
|
||||||
|
<div class="MultiSelectPreview-previewTags--inner">
|
||||||
|
<div class="MultiSelectPreview-previewTagContainer" ng-repeat="selectedRow in selectedRows">
|
||||||
|
<div class="MultiSelectPreview-previewTagContainerDelete" ng-click="unselectSelectedRow($index)">
|
||||||
|
<i class="fa fa-times MultiSelectPreview-previewTagContainerTagDelete"></i>
|
||||||
|
</div>
|
||||||
|
<div class="MultiSelectPreview-previewTag MultiSelectPreview-previewTag--deletable">
|
||||||
|
<span>{{selectedRow.name}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user