1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-07 23:05:26 +02:00

feat(schedules): add the ability to list tasks from snapshots (#2458)

* feat(schedules): add the ability to list tasks from snapshots

* feat(schedules): update schedules

* refactor(schedules): fix linting issue
This commit is contained in:
Anthony Lapenna 2018-11-13 14:39:26 +13:00 committed by GitHub
parent a2d9f591a7
commit 64c29f7402
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 440 additions and 149 deletions

View file

@ -0,0 +1,97 @@
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="datatable">
<rd-widget>
<rd-widget-body classes="no-padding">
<div class="toolBar">
<div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i>
{{ $ctrl.titleText }}
</div>
</div>
<div class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" placeholder="Search..." auto-focus>
</div>
<div class="table-responsive">
<table class="table table-hover table-filters nowrap-cells">
<thead>
<tr>
<th>
<a ng-click="$ctrl.changeOrderBy('Endpoint')">
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Endpoint' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Endpoint' && $ctrl.state.reverseOrder"></i>
Endpoint
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Id')">
Id
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Id' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Id' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Status')">
State
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Created')">
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Created' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Created' && $ctrl.state.reverseOrder"></i>
Created
</a>
</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter: $ctrl.applyFilters | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit))">
<td>
{{ item.Endpoint.Name }}
</td>
<td>
<a ng-click="$ctrl.goToContainerLogs(item.EndpointId, item.Id)">{{ item.Id | truncate: 32 }}</a>
</td>
<td>
<span class="label label-{{ item.Status|containerstatusbadge }}">{{ item.Status }}</span>
</td>
<td>
{{ item.Created | getisodatefromtimestamp}}
</td>
</tr>
<tr ng-if="!$ctrl.dataset">
<td colspan="9" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="9" class="text-center text-muted">No tasks available.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer" ng-if="$ctrl.dataset">
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span style="margin-right: 5px;">
Items per page
</span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span>
<dir-pagination-controls max-size="5"></dir-pagination-controls>
</form>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>
</div>

View file

@ -0,0 +1,13 @@
angular.module('portainer.docker').component('scheduleTasksDatatable', {
templateUrl: 'app/portainer/components/datatables/schedule-tasks-datatable/scheduleTasksDatatable.html',
controller: 'GenericDatatableController',
bindings: {
titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
orderBy: '@',
reverseOrder: '<',
goToContainerLogs: '<'
}
});

View file

@ -33,6 +33,13 @@ function ScriptExecutionJobModel(data) {
this.RetryInterval = data.RetryInterval;
}
function ScriptExecutionTaskModel(data) {
this.Id = data.Id;
this.EndpointId = data.EndpointId;
this.Status = createStatus(data.Status);
this.Created = data.Created;
}
function ScheduleCreateRequest(model) {
this.Name = model.Name;
this.CronExpression = model.CronExpression;

View file

@ -8,6 +8,7 @@ function SchedulesFactory($resource, API_ENDPOINT_SCHEDULES) {
get: { method: 'GET', params: { id: '@id' } },
update: { method: 'PUT', params: { id: '@id' } },
remove: { method: 'DELETE', params: { id: '@id'} },
file: { method: 'GET', params: { id : '@id', action: 'file' } }
file: { method: 'GET', params: { id : '@id', action: 'file' } },
tasks: { method: 'GET', isArray: true, params: { id : '@id', action: 'tasks' } }
});
}]);

View file

@ -36,6 +36,23 @@ function ScheduleService($q, Schedules, FileUploadService) {
return deferred.promise;
};
service.scriptExecutionTasks = function(scheduleId) {
var deferred = $q.defer();
Schedules.tasks({ id: scheduleId }).$promise
.then(function success(data) {
var tasks = data.map(function (item) {
return new ScriptExecutionTaskModel(item);
});
deferred.resolve(tasks);
})
.catch(function error(err) {
deferred.reject({ msg: 'Unable to retrieve tasks associated to the schedule', err: err });
});
return deferred.promise;
};
service.createScheduleFromFileContent = function(model) {
var payload = new ScheduleCreateRequest(model);
return Schedules.create({ method: 'string' }, payload).$promise;

View file

@ -13,15 +13,53 @@
<div class="col-sm-12">
<rd-widget>
<rd-widget-body>
<schedule-form
ng-if="schedule"
model="schedule"
endpoints="endpoints"
groups="groups"
form-action="update"
form-action-label="Update schedule"
action-in-progress="state.actionInProgress"
></schedule-form>
<uib-tabset active="state.activeTab">
<uib-tab index="0">
<uib-tab-heading>
<i class="fa fa-wrench" aria-hidden="true"></i> Configuration
</uib-tab-heading>
<schedule-form
ng-if="schedule"
model="schedule"
endpoints="endpoints"
groups="groups"
form-action="update"
form-action-label="Update schedule"
action-in-progress="state.actionInProgress"
></schedule-form>
</uib-tab>
<uib-tab index="1">
<uib-tab-heading>
<i class="fa fa-tasks" aria-hidden="true"></i> Tasks
</uib-tab-heading>
<div class="col-sm-12 form-section-title">
Information
</div>
<div class="form-group">
<span class="col-sm-12 text-muted small">
Tasks are retrieved across all endpoints via snapshots. Data available in this view might not be up-to-date.
</span>
</div>
<div class="col-sm-12 form-section-title" style="margin-bottom: 20px;">
Tasks
</div>
<schedule-tasks-datatable
ng-if="tasks"
title-text="Tasks" title-icon="fa-tasks"
dataset="tasks"
table-key="schedule-tasks"
order-by="Status" reverse-order="true"
go-to-container-logs="goToContainerLogs"
></schedule-tasks-datatable>
</uib-tab>
</uib-tabset>
</rd-widget-body>
</rd-widget>
</div>

View file

@ -1,12 +1,13 @@
angular.module('portainer.app')
.controller('ScheduleController', ['$q', '$scope', '$transition$', '$state', 'Notifications', 'EndpointService', 'GroupService', 'ScheduleService',
function ($q, $scope, $transition$, $state, Notifications, EndpointService, GroupService, ScheduleService) {
.controller('ScheduleController', ['$q', '$scope', '$transition$', '$state', 'Notifications', 'EndpointService', 'GroupService', 'ScheduleService', 'EndpointProvider',
function ($q, $scope, $transition$, $state, Notifications, EndpointService, GroupService, ScheduleService, EndpointProvider) {
$scope.state = {
actionInProgress: false
};
$scope.update = update;
$scope.goToContainerLogs = goToContainerLogs;
function update() {
var model = $scope.schedule;
@ -25,25 +26,48 @@ function ($q, $scope, $transition$, $state, Notifications, EndpointService, Grou
});
}
function goToContainerLogs(endpointId, containerId) {
EndpointProvider.setEndpointID(endpointId);
$state.go('docker.containers.container.logs', { id: containerId });
}
function associateEndpointsToTasks(tasks, endpoints) {
for (var i = 0; i < tasks.length; i++) {
var task = tasks[i];
for (var j = 0; j < endpoints.length; j++) {
var endpoint = endpoints[j];
if (task.EndpointId === endpoint.Id) {
task.Endpoint = endpoint;
break;
}
}
}
}
function initView() {
var id = $transition$.params().id;
var schedule = null;
$q.all({
schedule: ScheduleService.schedule(id),
file: ScheduleService.getScriptFile(id),
tasks: ScheduleService.scriptExecutionTasks(id),
endpoints: EndpointService.endpoints(),
groups: GroupService.groups()
})
.then(function success(data) {
schedule = data.schedule;
var schedule = data.schedule;
schedule.Job.FileContent = data.file.ScheduleFileContent;
var endpoints = data.endpoints;
var tasks = data.tasks;
associateEndpointsToTasks(tasks, endpoints);
$scope.schedule = schedule;
$scope.tasks = data.tasks;
$scope.endpoints = data.endpoints;
$scope.groups = data.groups;
return ScheduleService.getScriptFile(schedule.Id);
})
.then(function success(data) {
schedule.Job.FileContent = data.ScheduleFileContent;
$scope.schedule = schedule;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint list');