mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 02:50:02 -03:30
Modified search widget heper to no longer include 'row' element in the returned html. Callers will now controll the row definition. Moved breadcrumb generation from list-generator to generator-helpers so that it can be called from anywhere, including the inventory edit controller. Breadcrumbs now appear on inventory edit page. Changed search to check if searchPlaceholer field property is a scope variable. If it is, use the scope variable's value. Now clicking on a group name highlights it, searches for hosts and changes the search filed placeholder value to include the group name.
This commit is contained in:
parent
156652d60b
commit
a4098a6df7
@ -311,12 +311,13 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
|
||||
InventoriesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait'];
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait'
|
||||
];
|
||||
|
||||
|
||||
|
||||
function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait,
|
||||
UpdateStatusMsg, InjectHosts, HostsReload, GroupsAdd, GroupsEdit)
|
||||
function InventoriesEdit ($scope, $location, $routeParams, $compile, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait,
|
||||
UpdateStatusMsg, InjectHosts, HostsReload, GroupsAdd, GroupsEdit, Breadcrumbs, LoadBreadCrumbs)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -327,20 +328,35 @@ function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearSc
|
||||
|
||||
$scope.inventory_id = $routeParams.inventory_id;
|
||||
|
||||
LoadBreadCrumbs();
|
||||
|
||||
if ($scope.removeSearchTreeReady) {
|
||||
$scope.removeSearchTreeReady();
|
||||
}
|
||||
$scope.removeSearchTreeReady = $scope.$on('searchTreeReady', function(e, inventory_name, groups) {
|
||||
// After the tree data loads, generate the groups list
|
||||
generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5' });
|
||||
var e = angular.element(document.getElementById('breadcrumbs'));
|
||||
e.html(Breadcrumbs({ list: list, mode: 'edit' }));
|
||||
$compile(e)($scope);
|
||||
generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5 col-md-5 col-sm-5' });
|
||||
$scope.groups = groups;
|
||||
$scope.inventory_name = inventory_name;
|
||||
InjectHosts({ scope: $scope, inventory_id: $scope.inventory_id });
|
||||
Wait('stop');
|
||||
});
|
||||
|
||||
$scope.showHosts = function(group_id) {
|
||||
|
||||
$scope.showHosts = function(tree_id, group_id) {
|
||||
// Clicked on group
|
||||
//$scope.groups[tree_id].selected_class = 'selected';
|
||||
$scope.selected_tree_id = tree_id;
|
||||
$scope.selected_group_id = group_id;
|
||||
for (var i=0; i < $scope.groups.length; i++) {
|
||||
$scope.groups[i].selected_class = ($scope.groups[i].id == tree_id) ? 'selected' : '';
|
||||
if ($scope.groups[i].id == tree_id) {
|
||||
$scope.selected_group_name = $scope.groups[i].name;
|
||||
}
|
||||
}
|
||||
$scope.search_place_holder='Search ' + $scope.selected_group_name;
|
||||
HostsReload({ scope: $scope, group_id: group_id, inventory_id: $scope.inventory_id });
|
||||
}
|
||||
|
||||
@ -355,7 +371,8 @@ function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearSc
|
||||
BuildTree({ scope: $scope, inventory_id: $scope.inventory_id });
|
||||
}
|
||||
|
||||
InventoriesEdit.$inject = [ '$scope','$location', '$routeParams', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts', 'BuildTree',
|
||||
'Wait', 'UpdateStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsAdd', 'GroupsEdit'
|
||||
InventoriesEdit.$inject = [ '$scope', '$location', '$routeParams', '$compile', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts',
|
||||
'BuildTree', 'Wait', 'UpdateStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsAdd', 'GroupsEdit', 'Breadcrumbs',
|
||||
'LoadBreadCrumbs'
|
||||
];
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
var inventory_id = params.inventory_id;
|
||||
|
||||
var generator = GenerateList;
|
||||
generator.inject(InventoryHosts, { mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-5' });
|
||||
generator.inject(InventoryHosts, { mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-6 col-md-6 col-sm-6' });
|
||||
HostsReload({ scope: scope, group_id: null, inventory_id: inventory_id });
|
||||
}
|
||||
}])
|
||||
|
||||
@ -83,10 +83,21 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = false;
|
||||
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) ?
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder : 'Search';
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder];
|
||||
}
|
||||
else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
|
||||
scope[iterator + 'InputDisable' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
@ -128,9 +139,24 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputHide' + modifier] = false;
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = (list.fields[fld].searchPlaceholder) ? list.fields[fld].searchPlaceholder : 'Search';
|
||||
scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject == 'all') ? true : false;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder];
|
||||
}
|
||||
else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
|
||||
if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') {
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
|
||||
@ -24,8 +24,8 @@ angular.module('InventoryGroupsDefinition', [])
|
||||
name: {
|
||||
label: 'Group',
|
||||
key: true,
|
||||
ngClick: "\{\{ 'showHosts(' + group.id + ')' \}\}",
|
||||
//ngClass: "\{\{ 'level' + group.level \}\}",
|
||||
ngClick: "\{\{ 'showHosts(' + group.id + ',' + group.group_id + ')' \}\}",
|
||||
ngClass: "group.selected_class",
|
||||
hasChildren: true
|
||||
},
|
||||
status: {
|
||||
|
||||
@ -24,7 +24,8 @@ angular.module('InventoryHostsDefinition', [])
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
|
||||
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')",
|
||||
searchPlaceholder: "search_place_holder"
|
||||
},
|
||||
active_failures: {
|
||||
label: 'Job Status',
|
||||
@ -55,7 +56,8 @@ angular.module('InventoryHostsDefinition', [])
|
||||
searchable: true,
|
||||
sourceModel: 'groups',
|
||||
sourceField: 'name',
|
||||
nosort: true
|
||||
nosort: true,
|
||||
searchPlaceholder: "search_place_holder"
|
||||
},
|
||||
enabled: {
|
||||
label: 'Disabled?',
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
@red-hover: #AE3F3A;
|
||||
@green: #5bb75b;
|
||||
@blue: #1778c3; /* logo blue */
|
||||
@blue-link: #0088cc;
|
||||
@blue-link: #1778c3;
|
||||
@blue-dark: #2a6496; /* link hover */
|
||||
@grey: #A9A9A9;
|
||||
@well: #f5f5f5; /* well background color */
|
||||
@green: #5bb75b;
|
||||
@ -35,6 +36,7 @@ body {
|
||||
color: @black;
|
||||
}
|
||||
|
||||
|
||||
/* Helper Classes */
|
||||
.pad-right-sm { padding-right: 10px; }
|
||||
.pad-left-md { padding-left: 30px; }
|
||||
@ -47,6 +49,17 @@ body {
|
||||
.text-center { text-align: center !important; }
|
||||
|
||||
|
||||
a {
|
||||
color: @blue;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: @blue-dark;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Old style TB default button with grey background */
|
||||
.btn-grey {
|
||||
color: #333;
|
||||
@ -66,6 +79,15 @@ body {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Bring primary (blue) buttons in line with link colors */
|
||||
.btn-primary {
|
||||
background-color: @blue;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: @blue-dark;
|
||||
}
|
||||
|
||||
/* List Actions column */
|
||||
.actions {
|
||||
a {
|
||||
@ -320,10 +342,6 @@ dd {
|
||||
max-width: 260px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.help-link,
|
||||
.help-link:active,
|
||||
.help-link:visited {
|
||||
@ -517,10 +535,7 @@ select.page-size {
|
||||
}
|
||||
|
||||
/* Search Widget */
|
||||
.search-widget {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
.search-widget label {
|
||||
display: inline-block;
|
||||
padding-right: 15px;
|
||||
@ -658,7 +673,7 @@ input[type="checkbox"].checkbox-no-label {
|
||||
/* Display list actions next to search widget */
|
||||
.list-actions {
|
||||
text-align: right;
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 25px;
|
||||
|
||||
button {
|
||||
margin-left: 4px;
|
||||
@ -897,9 +912,9 @@ input[type="checkbox"].checkbox-no-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-items .search-widget {
|
||||
/*.form-items .search-widget {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}*/
|
||||
|
||||
.form-items .item-count {
|
||||
display: inline-block;
|
||||
@ -955,237 +970,19 @@ input[type="checkbox"].checkbox-no-label {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Inventory Edit */
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
color: @blue-dark;
|
||||
}
|
||||
|
||||
.inventory-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Inventory-> Groups */
|
||||
|
||||
.inventory-passwd-msg {
|
||||
font-size: 14px;
|
||||
margin-bottom: 25px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.groups-issue {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.inventory-content {
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/*
|
||||
.tree-view-container {
|
||||
padding: 0 0 10px 0;
|
||||
|
||||
.col-lg-4 {
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#tree-view {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e3e3e3;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
|
||||
/*border: 1px solid #e3e3e3;
|
||||
border-radius: 6px;
|
||||
background-color: #e3e3e3;
|
||||
*/
|
||||
padding-top: 10px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 10px;
|
||||
min-height: 100px;
|
||||
|
||||
.title {
|
||||
color: #888;
|
||||
padding-bottom: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
#tree-form {
|
||||
display: none;
|
||||
/*padding: 15px 10px 10px 10px;
|
||||
margin-top: 5px;
|
||||
border: 1px solid #e3e3e3;
|
||||
background-color: #e3e3e3;
|
||||
border-radius: 6px;*/
|
||||
|
||||
.form-title {
|
||||
color: #888;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: #ccc;
|
||||
height: 1px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Inventory-> Hosts */
|
||||
|
||||
.hosts-well {
|
||||
padding-top: 5px;
|
||||
|
||||
.search-widget {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.list-actions {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.hosts-title p {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hosts-title h4 {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.host-groups {
|
||||
margin-top: 15px;
|
||||
|
||||
select {
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.host-group-buttons {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
padding-top: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow tree node title to float above surrounding elements on hover */
|
||||
#search-tree-target {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.search-tree {
|
||||
|
||||
padding: 10px 3px 10px 10px;
|
||||
|
||||
.title {
|
||||
color: @grey;
|
||||
font-weight: normal;
|
||||
margin-bottom: 5px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.icon-sitemap {
|
||||
color: @grey;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.tree-root {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.activate {
|
||||
display: block;
|
||||
padding: 2px 3px 1px 3px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
.activate:hover {
|
||||
display: inline-block;
|
||||
overflow: visible;
|
||||
background-color: #ddd;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
box-shadow: 3px 3px 3px 0 @grey;
|
||||
border-bottom: 1px solid @grey;
|
||||
border-right: 1px solid @grey;
|
||||
background-color: #fff;
|
||||
|
||||
.activate:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.expand-container,
|
||||
.badge-container,
|
||||
.title-container {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-bottom: 2px solid @well;
|
||||
}
|
||||
|
||||
.expand-container {
|
||||
width: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.badge-container {
|
||||
vertical-align: none;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
#root-badge-container {
|
||||
margin-right: -2px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.expand {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.title-container {
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.expand-container:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.field-badge {
|
||||
font-size: 10px;
|
||||
line-height: normal;
|
||||
/*vertical-align: baseline;*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.host-failure-filter {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: @grey;
|
||||
}
|
||||
|
||||
@ -177,15 +177,16 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper'])
|
||||
|
||||
var inventory_id = params.inventory_id;
|
||||
var scope = params.scope;
|
||||
//var selected_id = params.
|
||||
|
||||
var groups = [];
|
||||
var id = 1;
|
||||
var id = 0;
|
||||
|
||||
function buildGroups(tree_data, parent, level) {
|
||||
var sorted = SortNodes(tree_data);
|
||||
for (var i=0; i < sorted.length; i++) {
|
||||
var currentId= id;
|
||||
var stat = UpdateStatusMsg({ status: sorted[i].status });
|
||||
var currentId = id;
|
||||
var stat = UpdateStatusMsg({ status: sorted[i].summary_fields.inventory_source.status });
|
||||
var group = {
|
||||
name: sorted[i].name,
|
||||
has_active_failures: sorted[i].has_active_failures,
|
||||
@ -203,7 +204,8 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper'])
|
||||
related: { children: (sorted[i].children.length > 0) ? sorted[i].related.children : '' },
|
||||
status: sorted[i].summary_fields.inventory_source.status,
|
||||
status_badge_class: stat['class'],
|
||||
status_badge_tooltip: stat['tooltip']
|
||||
status_badge_tooltip: stat['tooltip'],
|
||||
selected_class: ''
|
||||
}
|
||||
groups.push(group);
|
||||
id++;
|
||||
@ -266,6 +268,12 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper'])
|
||||
scope.groups[i][p] = properties[p];
|
||||
}
|
||||
}
|
||||
if (scope.groups[i].id == scope.selected_tree_id) {
|
||||
//Make sure potential group name change gets reflected throughout the page
|
||||
scope.selected_group_name = scope.groups[i].name;
|
||||
scope.search_place_holder = 'Search ' + scope.groups[i].name;
|
||||
scope.hostSearchPlaceholder = 'Search ' + scope.groups[i].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
||||
@ -1461,6 +1461,8 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities'])
|
||||
}
|
||||
|
||||
html += "<div class=\"well\">\n";
|
||||
html += "<div class=\"row\">\n";
|
||||
|
||||
html += SearchWidget({ iterator: form.related[itm].iterator, template: form.related[itm], mini: true });
|
||||
|
||||
html += "<div class=\"col-lg-8\">\n";
|
||||
|
||||
@ -393,7 +393,76 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('Breadcrumbs', ['Attr', function(Attr) {
|
||||
return function(params) {
|
||||
|
||||
// Generats breadcrumbs using the list-generator.js method.
|
||||
|
||||
var list = params.list;
|
||||
var mode = params.mode;
|
||||
var html = '';
|
||||
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
|
||||
|
||||
if (list.navigationLinks) {
|
||||
var navigation = list.navigationLinks;
|
||||
if (navigation['ngHide']) {
|
||||
html += "<li class=\"active\" ng-show=\"" + navigation['ngHide'] + "\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n";
|
||||
html += "<li class=\"active\" ng-hide=\"" + navigation['ngHide'] + "\"> </li>\n";
|
||||
}
|
||||
else {
|
||||
html += "<li class=\"active\"> </li>\n";
|
||||
html += "</ul>\n";
|
||||
}
|
||||
html += "<div class=\"dropdown\" ";
|
||||
html += (navigation['ngHide']) ? Attr(navigation, 'ngHide') : '';
|
||||
html += ">\n";
|
||||
for (var itm in navigation) {
|
||||
if (typeof navigation[itm] == 'object' && navigation[itm].active) {
|
||||
html += "<a href=\"\" class=\"toggle\" ";
|
||||
html += "data-toggle=\"dropdown\" ";
|
||||
html += ">" + navigation[itm].label + " <i class=\"fa fa-chevron-circle-down crumb-icon\"></i></a>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
html += "<ul class=\"dropdown-menu\" role=\"menu\">\n";
|
||||
for (var itm in navigation) {
|
||||
if (typeof navigation[itm] == 'object') {
|
||||
html += "<li role=\"presentation\"><a role=\"menuitem\" tabindex=\"-1\" href=\"" +
|
||||
navigation[itm].href + "\" ";
|
||||
// html += (navigation[itm].active) ? "class=\"active\" " : "";
|
||||
html += ">";
|
||||
html += "<i class=\"fa fa-check\" style=\"visibility: ";
|
||||
html += (navigation[itm].active) ? "visible" : "hidden";
|
||||
html += "\"></i> ";
|
||||
html += navigation[itm].label;
|
||||
html += "</a></li>\n";
|
||||
}
|
||||
}
|
||||
html += "</ul>\n";
|
||||
html += "</div><!-- dropdown -->\n";
|
||||
html += "</div><!-- nav-path -->\n";
|
||||
}
|
||||
else {
|
||||
html += "<li class=\"active\">";
|
||||
if (mode == 'select') {
|
||||
html += list.selectTitle;
|
||||
}
|
||||
else {
|
||||
html += list.editTitle;
|
||||
}
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('Column', ['Attr', 'Icon', 'DropDown', 'Badge', 'BadgeCount', function(Attr, Icon, DropDown, Badge, BadgeCount) {
|
||||
return function(params) {
|
||||
var list = params['list'];
|
||||
@ -561,7 +630,6 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
var useMini = params.mini;
|
||||
var html= '';
|
||||
var searchWidgets = (params.searchWidgets) ? params.searchWidgets : 1;
|
||||
html += "<div class=\"row search-widget\">\n";
|
||||
for (var i=1; i <= searchWidgets; i++) {
|
||||
var modifier = (i == 1) ? '' : i;
|
||||
html += "<div class=\"";
|
||||
@ -635,7 +703,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
iterator + "HideAllStartBtn" + modifier + "\"" +
|
||||
"><i class=\"fa fa-search\"></i></a>\n";
|
||||
|
||||
html += "</div><!-- col-lg-x -->\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
// Reset button and spinner
|
||||
@ -645,7 +713,6 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
//html += "<i class=\"icon-spinner icon-spin icon-large\" ng-show=\"" + iterator + "SearchSpin == true\"></i>\n";
|
||||
//html += "</div>\n";
|
||||
|
||||
|
||||
return html;
|
||||
|
||||
}
|
||||
|
||||
@ -9,8 +9,9 @@
|
||||
|
||||
angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
.factory('GenerateList', [ '$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon',
|
||||
'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon',
|
||||
function($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, Column, DropDown, NavigationLink, Button, SelectIcon) {
|
||||
'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon', 'Breadcrumbs',
|
||||
function($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, Column, DropDown, NavigationLink, Button, SelectIcon,
|
||||
Breadcrumbs) {
|
||||
return {
|
||||
|
||||
setList: function(list) {
|
||||
@ -113,222 +114,178 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
var list = this.list;
|
||||
|
||||
if (options.activityStream) {
|
||||
// Breadcrumbs for activity stream widget
|
||||
// Make the links clickable using ng-click function so we can first remove the stream widget
|
||||
// before navigation
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"{{ crumb.ngClick }}\">{{ crumb.title | capitalize }}</a></li>\n";
|
||||
html += "<li class=\"active\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
// Breadcrumbs for activity stream widget
|
||||
// Make the links clickable using ng-click function so we can first remove the stream widget
|
||||
// before navigation
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"{{ crumb.ngClick }}\">{{ crumb.title | capitalize }}</a></li>\n";
|
||||
html += "<li class=\"active\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
}
|
||||
else if (options.mode != 'lookup' && (options.breadCrumbs == undefined || options.breadCrumbs == true)) {
|
||||
//Breadcrumbs
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"{{ '#' + crumb.path }}\">{{ crumb.title | capitalize }}</a></li>\n";
|
||||
|
||||
if (list.navigationLinks) {
|
||||
var navigation = list.navigationLinks;
|
||||
if (navigation['ngHide']) {
|
||||
html += "<li class=\"active\" ng-show=\"" + navigation['ngHide'] + "\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n";
|
||||
html += "<li class=\"active\" ng-hide=\"" + navigation['ngHide'] + "\"> </li>\n";
|
||||
}
|
||||
else {
|
||||
html += "<li class=\"active\"> </li>\n";
|
||||
html += "</ul>\n";
|
||||
}
|
||||
html += "<div class=\"dropdown\" ";
|
||||
html += (navigation['ngHide']) ? Attr(navigation, 'ngHide') : '';
|
||||
html += ">\n";
|
||||
for (var itm in navigation) {
|
||||
if (typeof navigation[itm] == 'object' && navigation[itm].active) {
|
||||
html += "<a href=\"\" class=\"toggle\" ";
|
||||
html += "data-toggle=\"dropdown\" ";
|
||||
html += ">" + navigation[itm].label + " <i class=\"fa fa-chevron-circle-down crumb-icon\"></i></a>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
html += "<ul class=\"dropdown-menu\" role=\"menu\">\n";
|
||||
for (var itm in navigation) {
|
||||
if (typeof navigation[itm] == 'object') {
|
||||
html += "<li role=\"presentation\"><a role=\"menuitem\" tabindex=\"-1\" href=\"" +
|
||||
navigation[itm].href + "\" ";
|
||||
// html += (navigation[itm].active) ? "class=\"active\" " : "";
|
||||
html += ">";
|
||||
html += "<i class=\"fa fa-check\" style=\"visibility: ";
|
||||
html += (navigation[itm].active) ? "visible" : "hidden";
|
||||
html += "\"></i> ";
|
||||
html += navigation[itm].label;
|
||||
html += "</a></li>\n";
|
||||
}
|
||||
}
|
||||
html += "</ul>\n";
|
||||
html += "</div><!-- dropdown -->\n";
|
||||
html += "</div><!-- nav-path -->\n";
|
||||
}
|
||||
else {
|
||||
html += "<li class=\"active\">";
|
||||
if (options.mode == 'select') {
|
||||
html += list.selectTitle;
|
||||
}
|
||||
else {
|
||||
html += list.editTitle;
|
||||
}
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
}
|
||||
html += Breadcrumbs({ list: list, mode: options.mode });
|
||||
}
|
||||
|
||||
if (options.mode == 'edit' && list.editInstructions) {
|
||||
html += "<div class=\"alert alert-info alert-block\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>\n";
|
||||
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"alert alert-info alert-block\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>\n";
|
||||
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (options.mode != 'lookup' && (list.well == undefined || list.well == true)) {
|
||||
html += "<div class=\"well\">\n";
|
||||
html += "<div class=\"well\">\n";
|
||||
}
|
||||
|
||||
if (list.name == 'groups') {
|
||||
// Inventory groups
|
||||
html += "<div class=\"row\">\n";
|
||||
html += "<div class=\"inventory-title " + options.searchSize + "\">" + list.editTitle + "</div>\n";
|
||||
}
|
||||
else {
|
||||
html += "<div class=\"row\">\n";
|
||||
|
||||
if (list.name != 'groups') {
|
||||
// // Inventory groups
|
||||
// html += "<div class=\"inventory-title col-lg-5\">" + list.editTitle + "</div>\n";
|
||||
//}
|
||||
//else if (list.name == 'hosts') {
|
||||
// html += "<div class=\"col-lg-4\">\n";
|
||||
// html += "<span class=\"hosts-title\">{{ selected_group_name }}</span>";
|
||||
// html += "</div><!-- col-lg-4 -->";
|
||||
// html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-5',
|
||||
// searchWidgets: list.searchWidgets });
|
||||
//}
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets });
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets });
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' });
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' });
|
||||
}
|
||||
else if (options.mode == 'lookup' || options.id != undefined) {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' });
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' });
|
||||
}
|
||||
else {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true });
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mode != 'lookup') {
|
||||
//actions
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
//actions
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
html += "<div class=\"";
|
||||
if (list.name == 'groups') {
|
||||
html += "col-lg-12";
|
||||
}
|
||||
else if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
var size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g,''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += 'col-lg-6';
|
||||
}
|
||||
else if (options.id != undefined) {
|
||||
html += "col-lg-4";
|
||||
}
|
||||
else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
|
||||
html += "<div class=\"";
|
||||
if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
var size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g,''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += 'col-lg-6';
|
||||
}
|
||||
else if (options.id != undefined) {
|
||||
html += "col-lg-4";
|
||||
}
|
||||
else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (action in list.actions) {
|
||||
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
|
||||
if ( (list.actions[action].basePaths == undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1) ) {
|
||||
html += this.button({ btn: list.actions[action], action: action, toolbar: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (action in list.actions) {
|
||||
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
|
||||
if ( (list.actions[action].basePaths == undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1) ) {
|
||||
html += this.button({ btn: list.actions[action], action: action, toolbar: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//select instructions
|
||||
if (options.mode == 'select' && list.selectInstructions) {
|
||||
var btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'top',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({ btn: btn, action: 'help', toolbar: true });
|
||||
}
|
||||
//select instructions
|
||||
if (options.mode == 'select' && list.selectInstructions) {
|
||||
var btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'top',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({ btn: btn, action: 'help', toolbar: true });
|
||||
}
|
||||
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- col-lg-7 -->\n";
|
||||
}
|
||||
else {
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
}
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- list-actions-column -->\n";
|
||||
}
|
||||
else {
|
||||
//lookup
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
}
|
||||
|
||||
html += "</div><!-- row -->\n";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
html += (options.mode == 'edit' || options.mode == 'summary') ? list.editTitle : list.addTitle;
|
||||
html += "</div>\n";
|
||||
}
|
||||
html += "</div><!-- row -->\n";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
html += (options.mode == 'edit' || options.mode == 'summary') ? list.editTitle : list.addTitle;
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
// table header row
|
||||
html += "<table id=\"" + list.name + "_table\" ";
|
||||
html += "class=\"table"
|
||||
html += (list['class']) ? " " + list['class'] : "";
|
||||
html += (options.mode !== 'summary' && options.mode !== 'edit' && (options.mode == 'lookup' || options.id)) ?
|
||||
' table-hover-inverse' : '';
|
||||
html += (list.hover) ? ' table-hover' : '';
|
||||
html += (options.mode == 'summary') ? ' table-summary' : '';
|
||||
html += "\" ";
|
||||
html += ">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
if (list.index) {
|
||||
html += "<th>#</th>\n";
|
||||
}
|
||||
for (var fld in list.fields) {
|
||||
if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) &&
|
||||
!(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) {
|
||||
html += "<th class=\"list-header";
|
||||
html += (list.fields[fld].columnClass) ? " " + list.fields[fld].columnClass : "";
|
||||
html += "\" id=\"";
|
||||
html += (list.fields[fld].id) ? list.fields[fld].id : fld + "-header";
|
||||
html += "\"";
|
||||
html += (list.fields[fld].columnShow) ? " ng-show=\"" + list.fields[fld].columnShow + "\" " : "";
|
||||
html += (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) ? "ng-click=\"sort('" + fld + "')\"" : "";
|
||||
html += ">";
|
||||
html += list.fields[fld].label;
|
||||
if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
|
||||
html += " <i class=\"fa ";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "fa-sort-down";
|
||||
// table header row
|
||||
html += "<table id=\"" + list.name + "_table\" ";
|
||||
html += "class=\"table"
|
||||
html += (list['class']) ? " " + list['class'] : "";
|
||||
html += (options.mode !== 'summary' && options.mode !== 'edit' && (options.mode == 'lookup' || options.id)) ?
|
||||
' table-hover-inverse' : '';
|
||||
html += (list.hover) ? ' table-hover' : '';
|
||||
html += (options.mode == 'summary') ? ' table-summary' : '';
|
||||
html += "\" ";
|
||||
html += ">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
if (list.index) {
|
||||
html += "<th>#</th>\n";
|
||||
}
|
||||
for (var fld in list.fields) {
|
||||
if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) &&
|
||||
!(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) {
|
||||
html += "<th class=\"list-header";
|
||||
html += (list.fields[fld].columnClass) ? " " + list.fields[fld].columnClass : "";
|
||||
html += "\" id=\"";
|
||||
html += (list.fields[fld].id) ? list.fields[fld].id : fld + "-header";
|
||||
html += "\"";
|
||||
html += (list.fields[fld].columnShow) ? " ng-show=\"" + list.fields[fld].columnShow + "\" " : "";
|
||||
html += (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) ? "ng-click=\"sort('" + fld + "')\"" : "";
|
||||
html += ">";
|
||||
html += list.fields[fld].label;
|
||||
if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
|
||||
html += " <i class=\"fa ";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "fa-sort-down";
|
||||
}
|
||||
else {
|
||||
html += "fa-sort-up";
|
||||
}
|
||||
}
|
||||
else {
|
||||
html += "fa-sort-up";
|
||||
}
|
||||
}
|
||||
else {
|
||||
html += "fa-sort";
|
||||
}
|
||||
html += "\"></i></a>";
|
||||
}
|
||||
html += "</th>\n";
|
||||
}
|
||||
html += "fa-sort";
|
||||
}
|
||||
html += "\"></i></a>";
|
||||
}
|
||||
html += "</th>\n";
|
||||
}
|
||||
}
|
||||
if (options.mode == 'select' || options.mode == 'lookup') {
|
||||
html += "<th>Select</th>";
|
||||
html += "<th>Select</th>";
|
||||
}
|
||||
else if (options.mode == 'edit') {
|
||||
html += "<th class=\"actions-column\">Actions</th>\n";
|
||||
html += "<th class=\"actions-column\">Actions</th>\n";
|
||||
}
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
@ -343,7 +300,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
html += "\"";
|
||||
html += ">\n";
|
||||
if (list.index) {
|
||||
html += "<td class=\"index-column\">{{ $index + (" + list.iterator + "Page * " + list.iterator + "PageSize) + 1 }}.</td>\n";
|
||||
html += "<td class=\"index-column\">{{ $index + (" + list.iterator + "Page * " + list.iterator + "PageSize) + 1 }}.</td>\n";
|
||||
}
|
||||
var cnt = 2;
|
||||
var base = (list.base) ? list.base : list.name;
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
<div class="tab-pane" id="inventory_edit">
|
||||
<div id="htmlTemplate">
|
||||
<div class="row">
|
||||
<div id="groups-container" class="col-lg-6"></div>
|
||||
<div id="hosts-container" class="col-lg-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="htmlTemplate">
|
||||
<div class="row">
|
||||
<div class="col-lg-12" id="breadcrumbs"></div>
|
||||
</div>
|
||||
<!-- <div class="row">
|
||||
<div id="hosts-title" class="col-lg-offset-6 col-lg-6">{{ selected_group_name }}</div>
|
||||
</div> -->
|
||||
<div class="row">
|
||||
<div id="groups-container" class="col-lg-6"></div>
|
||||
<div id="hosts-container" class="col-lg-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
x
Reference in New Issue
Block a user