mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 09:27:36 -02:30
Applied status field changes to home/groups page.
This commit is contained in:
@@ -122,7 +122,7 @@ Home.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location',
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
function HomeGroups($filter, $compile, $location, $routeParams, LogViewer, HomeGroupList, GenerateList, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||||
GetBasePath, SearchInit, PaginateInit, FormatDate, GetHostsStatusMsg, GetSyncStatusMsg, ViewUpdateStatus, Stream, GroupsEdit, Wait,
|
GetBasePath, SearchInit, PaginateInit, FormatDate, GetHostsStatusMsg, GetSyncStatusMsg, ViewUpdateStatus, Stream, GroupsEdit, Wait,
|
||||||
Alert, Rest, Empty, InventoryUpdate, Find) {
|
Alert, Rest, Empty, InventoryUpdate, Find) {
|
||||||
|
|
||||||
@@ -135,6 +135,35 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces
|
|||||||
scope = generator.inject(list, { mode: 'edit' }),
|
scope = generator.inject(list, { mode: 'edit' }),
|
||||||
opt;
|
opt;
|
||||||
|
|
||||||
|
function ellipsis(a) {
|
||||||
|
if (a.length > 20) {
|
||||||
|
return a.substr(0,20) + '...';
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachElem(event, html, title) {
|
||||||
|
var elem = $(event.target).parent();
|
||||||
|
try {
|
||||||
|
elem.tooltip('hide');
|
||||||
|
elem.popover('destroy');
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
elem.attr({ "aw-pop-over": html, "data-title": title, "data-placement": "right" });
|
||||||
|
$compile(elem)(scope);
|
||||||
|
elem.on('shown.bs.popover', function() {
|
||||||
|
$('.popover').each(function() {
|
||||||
|
$compile($(this))(scope); //make nested directives work!
|
||||||
|
});
|
||||||
|
$('.popover-content, .popover-title').click(function() {
|
||||||
|
elem.popover('hide');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
elem.popover('show');
|
||||||
|
}
|
||||||
|
|
||||||
if (scope.removePostRefresh) {
|
if (scope.removePostRefresh) {
|
||||||
scope.removePostRefresh();
|
scope.removePostRefresh();
|
||||||
}
|
}
|
||||||
@@ -145,7 +174,9 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces
|
|||||||
scope.home_groups[i].inventory_name = scope.home_groups[i].summary_fields.inventory.name;
|
scope.home_groups[i].inventory_name = scope.home_groups[i].summary_fields.inventory.name;
|
||||||
|
|
||||||
stat = GetSyncStatusMsg({
|
stat = GetSyncStatusMsg({
|
||||||
status: scope.home_groups[i].summary_fields.inventory_source.status
|
status: scope.home_groups[i].summary_fields.inventory_source.status,
|
||||||
|
source: scope.home_groups[i].summary_fields.inventory_source.source,
|
||||||
|
has_inventory_sources: scope.home_groups[i].has_inventory_sources
|
||||||
}); // from helpers/Groups.js
|
}); // from helpers/Groups.js
|
||||||
|
|
||||||
hosts_status = GetHostsStatusMsg({
|
hosts_status = GetHostsStatusMsg({
|
||||||
@@ -174,6 +205,7 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces
|
|||||||
list: list,
|
list: list,
|
||||||
url: defaultUrl
|
url: defaultUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
PaginateInit({
|
PaginateInit({
|
||||||
scope: scope,
|
scope: scope,
|
||||||
list: list,
|
list: list,
|
||||||
@@ -258,7 +290,8 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces
|
|||||||
scope: scope,
|
scope: scope,
|
||||||
group_id: group_id,
|
group_id: group_id,
|
||||||
inventory_id: inventory_id,
|
inventory_id: inventory_id,
|
||||||
groups_reload: false
|
groups_reload: false,
|
||||||
|
mode: 'edit'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -306,9 +339,136 @@ function HomeGroups($location, $routeParams, HomeGroupList, GenerateList, Proces
|
|||||||
scope.search(list.iterator, null, false, true);
|
scope.search(list.iterator, null, false, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (scope.removeHostSummaryReady) {
|
||||||
|
scope.removeHostSummaryReady();
|
||||||
|
}
|
||||||
|
scope.removeHostSummaryReady = scope.$on('HostSummaryReady', function(e, event, data) {
|
||||||
|
var html, title = "Recent Jobs", url = GetBasePath('jobs');
|
||||||
|
Wait('stop');
|
||||||
|
if (data.length > 0) {
|
||||||
|
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||||
|
html += "<thead>\n";
|
||||||
|
html += "<tr>";
|
||||||
|
html += "<th>Status</th>";
|
||||||
|
html += "<th>View</th>";
|
||||||
|
html += "<th>Name</th>";
|
||||||
|
html += "</tr>\n";
|
||||||
|
html += "</thead>\n";
|
||||||
|
html += "<tbody>\n";
|
||||||
|
data.forEach(function(row) {
|
||||||
|
html += "<tr>\n";
|
||||||
|
html += "<td><a ng-click=\"viewJob('" + url + row.id + "/')\" " + "aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) +
|
||||||
|
". Click for details\" aw-tip-placement=\"top\"><i class=\"fa icon-job-" +
|
||||||
|
row.status + "\"></i></a></td>\n";
|
||||||
|
//html += "<td>" + ($filter('date')(row.finished,'MM/dd HH:mm:ss')).replace(/ /,'<br />') + "</td>";
|
||||||
|
html += "<td><a href=\"/#/jobs/" + row.id + "/job_events\">Events</a><br />" +
|
||||||
|
"<a href=\"/#/jobs/" + row.id + "/job_host_summaries\">Hosts</a></td>";
|
||||||
|
html += "<td><a href=\"\" ng-click=\"viewJob('" + url + row.id + "/')\" >" + ellipsis(row.name) + "</a></td>";
|
||||||
|
html += "</tr>\n";
|
||||||
|
});
|
||||||
|
html += "</tbody>\n";
|
||||||
|
html += "</table>\n";
|
||||||
|
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
html = "<p>No recent job data available for this inventory.</p>\n" +
|
||||||
|
"<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
|
||||||
|
}
|
||||||
|
attachElem(event, html, title);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (scope.removeGroupSummaryReady) {
|
||||||
|
scope.removeGroupSummaryReady();
|
||||||
|
}
|
||||||
|
scope.removeGroupSummaryReady = scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
|
||||||
|
var html, title;
|
||||||
|
|
||||||
|
Wait('stop');
|
||||||
|
|
||||||
|
// Build the html for our popover
|
||||||
|
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
|
||||||
|
html += "<thead>\n";
|
||||||
|
html += "<tr>";
|
||||||
|
html += "<th>Status</th>";
|
||||||
|
html += "<th>Last Sync</th>";
|
||||||
|
html += "<th>Group</th>";
|
||||||
|
html += "</tr>";
|
||||||
|
html += "</thead>\n";
|
||||||
|
html += "<tbody>\n";
|
||||||
|
data.results.forEach( function(row) {
|
||||||
|
html += "<tr>";
|
||||||
|
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\" aw-tool-tip=\"" + row.status.charAt(0).toUpperCase() + row.status.slice(1) + ". Click for details\" aw-tip-placement=\"top\"><i class=\"fa icon-job-" + row.status + "\"></i></a></td>";
|
||||||
|
html += "<td>" + ($filter('date')(row.last_updated,'MM/dd HH:mm:ss')).replace(/ /,'<br />') + "</td>";
|
||||||
|
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\">" + ellipsis(row.summary_fields.group.name) + "</a></td>";
|
||||||
|
html += "</tr>\n";
|
||||||
|
});
|
||||||
|
html += "</tbody>\n";
|
||||||
|
html += "</table>\n";
|
||||||
|
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
|
||||||
|
title = "Sync Status";
|
||||||
|
attachElem(event, html, title);
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.showGroupSummary = function(event, id) {
|
||||||
|
var group, status;
|
||||||
|
if (!Empty(id)) {
|
||||||
|
group = Find({ list: scope.home_groups, key: 'id', val: id });
|
||||||
|
status = group.summary_fields.inventory_source.status;
|
||||||
|
if (status === 'failed' || status === 'error' || status === 'successful') {
|
||||||
|
Wait('start');
|
||||||
|
Rest.setUrl(group.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
|
||||||
|
Rest.get()
|
||||||
|
.success(function(data) {
|
||||||
|
scope.$emit('GroupSummaryReady', event, group, data);
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors( scope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + group.related.inventory_sources + ' failed. GET returned status: ' + status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.showHostSummary = function(event, id) {
|
||||||
|
var url, jobs = [];
|
||||||
|
if (!Empty(id)) {
|
||||||
|
Wait('start');
|
||||||
|
url = GetBasePath('hosts') + "?groups__id=" + id + "&last_job__isnull=false&order_by=-last_job&page_size=5";
|
||||||
|
Rest.setUrl(url);
|
||||||
|
Rest.get()
|
||||||
|
.success( function(data) {
|
||||||
|
data.results.forEach(function(host) {
|
||||||
|
host.summary_fields.recent_jobs.every(function(job) {
|
||||||
|
if (job.id === host.last_job) {
|
||||||
|
jobs.push(job);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
scope.$emit('HostSummaryReady', event, jobs);
|
||||||
|
})
|
||||||
|
.error( function(data, status) {
|
||||||
|
ProcessErrors( scope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + ' failed. GET returned: ' + status
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.viewJob = function(url) {
|
||||||
|
LogViewer({
|
||||||
|
scope: scope,
|
||||||
|
url: url
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HomeGroups.$inject = ['$location', '$routeParams', 'HomeGroupList', 'GenerateList', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller',
|
HomeGroups.$inject = ['$filter', '$compile', '$location', '$routeParams', 'LogViewer', 'HomeGroupList', 'GenerateList', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller',
|
||||||
'ClearScope', 'GetBasePath', 'SearchInit', 'PaginateInit', 'FormatDate', 'GetHostsStatusMsg', 'GetSyncStatusMsg', 'ViewUpdateStatus',
|
'ClearScope', 'GetBasePath', 'SearchInit', 'PaginateInit', 'FormatDate', 'GetHostsStatusMsg', 'GetSyncStatusMsg', 'ViewUpdateStatus',
|
||||||
'Stream', 'GroupsEdit', 'Wait', 'Alert', 'Rest', 'Empty', 'InventoryUpdate', 'Find'
|
'Stream', 'GroupsEdit', 'Wait', 'Alert', 'Rest', 'Empty', 'InventoryUpdate', 'Find'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -175,6 +175,12 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
|||||||
launch_tip = 'Can only be updated by running a sync on the parent group.';
|
launch_tip = 'Can only be updated by running a sync on the parent group.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_inventory_sources === false && Empty(source)) {
|
||||||
|
launch_class = 'btn-disabled';
|
||||||
|
status_tip = 'Cloud source not configured. Click <i class="fa fa-pencil"></i> to update.';
|
||||||
|
launch_tip = 'Cloud source not configured.';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"class": stat_class,
|
"class": stat_class,
|
||||||
"tooltip": status_tip,
|
"tooltip": status_tip,
|
||||||
|
|||||||
@@ -45,11 +45,6 @@ angular.module('CompletedJobsDefinition', [])
|
|||||||
{ name: "Canceled", value: "canceled" }
|
{ name: "Canceled", value: "canceled" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
inventory: {
|
|
||||||
label: 'Inventory ID',
|
|
||||||
searchType: 'int',
|
|
||||||
searchOnly: true
|
|
||||||
},
|
|
||||||
finished: {
|
finished: {
|
||||||
label: 'Finished On',
|
label: 'Finished On',
|
||||||
noLink: true,
|
noLink: true,
|
||||||
|
|||||||
@@ -21,6 +21,28 @@ angular.module('HomeGroupListDefinition', [])
|
|||||||
well: true,
|
well: true,
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
|
status: {
|
||||||
|
label: 'Status',
|
||||||
|
columnClass: 'col-md-2 col-sm-2 col-xs-2',
|
||||||
|
searchable: false,
|
||||||
|
nosort: true,
|
||||||
|
ngClick: "null",
|
||||||
|
iconOnly: true,
|
||||||
|
icons: [{
|
||||||
|
icon: "{{ 'icon-cloud-' + group.status_class }}",
|
||||||
|
awToolTip: "{{ group.status_tooltip }}",
|
||||||
|
dataTipWatch: "group.launch_tooltip",
|
||||||
|
awTipPlacement: "top",
|
||||||
|
ngClick: "showGroupSummary($event, group.id)",
|
||||||
|
ngClass: "group.launch_class"
|
||||||
|
},{
|
||||||
|
icon: "{{ 'icon-job-' + group.hosts_status_class }}",
|
||||||
|
awToolTip: "{{ group.hosts_status_tip }}",
|
||||||
|
awTipPlacement: "top",
|
||||||
|
ngClick: "showHostSummary($event, group.id)",
|
||||||
|
ngClass: ""
|
||||||
|
}]
|
||||||
|
},
|
||||||
name: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Group',
|
label: 'Group',
|
||||||
@@ -82,6 +104,7 @@ angular.module('HomeGroupListDefinition', [])
|
|||||||
},
|
},
|
||||||
|
|
||||||
fieldActions: {
|
fieldActions: {
|
||||||
|
/*
|
||||||
sync_status: {
|
sync_status: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "viewUpdateStatus(group.id, group.group_id)",
|
ngClick: "viewUpdateStatus(group.id, group.group_id)",
|
||||||
@@ -96,6 +119,7 @@ angular.module('HomeGroupListDefinition', [])
|
|||||||
ngHref: "/#/inventories/{{ group.inventory }}/",
|
ngHref: "/#/inventories/{{ group.inventory }}/",
|
||||||
iconClass: "{{ 'fa icon-failures-' + group.hosts_status_class }}"
|
iconClass: "{{ 'fa icon-failures-' + group.hosts_status_class }}"
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
group_update: {
|
group_update: {
|
||||||
//label: 'Sync',
|
//label: 'Sync',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ angular.module('InventoriesListDefinition', [])
|
|||||||
searchable: false,
|
searchable: false,
|
||||||
nosort: true,
|
nosort: true,
|
||||||
ngClick: "null",
|
ngClick: "null",
|
||||||
dataTitle: "Sync Status",
|
iconOnly: true,
|
||||||
icons: [{
|
icons: [{
|
||||||
icon: "{{ 'icon-cloud-' + inventory.syncStatus }}",
|
icon: "{{ 'icon-cloud-' + inventory.syncStatus }}",
|
||||||
awToolTip: "{{ inventory.syncTip }}",
|
awToolTip: "{{ inventory.syncTip }}",
|
||||||
|
|||||||
@@ -36,12 +36,8 @@ angular.module('QueuedJobsDefinition', [])
|
|||||||
dataTitle: "{{ queued_job.status_popover_title }}",
|
dataTitle: "{{ queued_job.status_popover_title }}",
|
||||||
icon: 'icon-job-{{ queued_job.status }}',
|
icon: 'icon-job-{{ queued_job.status }}',
|
||||||
iconOnly: true,
|
iconOnly: true,
|
||||||
ngClick:"viewJobLog(queued_job.id)"
|
ngClick:"viewJobLog(queued_job.id)",
|
||||||
},
|
searchable: false
|
||||||
inventory: {
|
|
||||||
label: 'Inventory ID',
|
|
||||||
searchType: 'int',
|
|
||||||
searchOnly: true
|
|
||||||
},
|
},
|
||||||
created: {
|
created: {
|
||||||
label: 'Created On',
|
label: 'Created On',
|
||||||
|
|||||||
@@ -36,12 +36,8 @@ angular.module('RunningJobsDefinition', [])
|
|||||||
dataTitle: "{{ running_job.status_popover_title }}",
|
dataTitle: "{{ running_job.status_popover_title }}",
|
||||||
icon: 'icon-job-{{ running_job.status }}',
|
icon: 'icon-job-{{ running_job.status }}',
|
||||||
iconOnly: true,
|
iconOnly: true,
|
||||||
ngClick:"viewJobLog(running_job.id)"
|
ngClick:"viewJobLog(running_job.id)",
|
||||||
},
|
searchable: false
|
||||||
inventory: {
|
|
||||||
label: 'Inventory ID',
|
|
||||||
searchType: 'int',
|
|
||||||
searchOnly: true
|
|
||||||
},
|
},
|
||||||
started: {
|
started: {
|
||||||
label: 'Started On',
|
label: 'Started On',
|
||||||
|
|||||||
@@ -1249,7 +1249,8 @@ input[type="checkbox"].checkbox-no-label {
|
|||||||
|
|
||||||
/* Inventory Edit */
|
/* Inventory Edit */
|
||||||
|
|
||||||
#inventories_table i[class*="icon-job-"] {
|
#inventories_table i[class*="icon-job-"],
|
||||||
|
#home_groups_table i[class*="icon-job-"] {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ angular.module('GeneratorHelpers', [])
|
|||||||
html += "aw-pop-over=\"" + field.awPopOver + "\" ";
|
html += "aw-pop-over=\"" + field.awPopOver + "\" ";
|
||||||
html += (field.dataPlacement) ? "data-placement=\"" + field.dataPlacement + "\" " : "";
|
html += (field.dataPlacement) ? "data-placement=\"" + field.dataPlacement + "\" " : "";
|
||||||
}
|
}
|
||||||
|
html += (field.ngClass) ? Attr(field, 'ngClass') : '';
|
||||||
html += ">";
|
html += ">";
|
||||||
|
|
||||||
// Add icon:
|
// Add icon:
|
||||||
|
|||||||
@@ -1,4 +1,41 @@
|
|||||||
<div class="tab-pane" id="home">
|
<div class="tab-pane" id="home">
|
||||||
<div ng-cloak id="htmlTemplate"></div>
|
<div ng-cloak id="htmlTemplate"></div>
|
||||||
<div id="inventory-modal-container"></div>
|
<div id="inventory-modal-container"></div>
|
||||||
|
<div id="group-modal-dialog" style="display: none;">
|
||||||
|
<ul id="group_tabs" class="nav nav-tabs">
|
||||||
|
<li class="active"><a id="properties_link" ng-click="toggleTab($event, 'properties_link', 'group_tabs')"
|
||||||
|
href="#properties-tab" data-toggle="tab">Properties</a></li>
|
||||||
|
<li><a id="source_link" ng-click="toggleTab($event, 'source_link', 'group_tabs')"
|
||||||
|
href="#sources-tab" data-toggle="tab">Source</a></li>
|
||||||
|
<li ng-show="showSourceTab"><a id="schedules_link" ng-click="toggleTab($event, 'schedules_link', 'group_tabs')"
|
||||||
|
href="#schedules-tab" data-toggle="tab">Schedule</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="properties-tab"></div>
|
||||||
|
<div class="tab-pane" id="sources-tab"></div>
|
||||||
|
<div class="tab-pane" id="schedules-tab">
|
||||||
|
<div id="schedules-overlay"></div>
|
||||||
|
<div id="schedules-list"></div>
|
||||||
|
<div id="schedules-form-container">
|
||||||
|
<div id="schedules-title">
|
||||||
|
<h4 ng-bind="schedulesTitle"></h4>
|
||||||
|
<button type="button" class="close pull-right" ng-click="cancelScheduleForm()">x</button>
|
||||||
|
</div>
|
||||||
|
<div id="schedules-form-container-body">
|
||||||
|
<div id="schedules-form"></div>
|
||||||
|
<div id="schedules-detail"></div>
|
||||||
|
</div>
|
||||||
|
<div id="schedules-buttons">
|
||||||
|
<a id="schedules-flip-link" ng-show="formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-search-plus"></i> View Details</a>
|
||||||
|
<a id="schedules-flip-link" ng-show="!formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-arrow-circle-left"></i> Back to options</a>
|
||||||
|
<button type="button" class="btn btn-default btn-sm" id="reset-button" ng-click="cancelScheduleForm()"><i class="fa fa-times"></i> Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="save-button" ng-click="saveScheduleForm()"><i class="fa fa-check"></i> Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div>
|
||||||
|
<div ng-include="'/static/partials/logviewer.html'"></div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user