UNPKG

@spotinst/spinnaker-deck

Version:

Spinnaker-Deck service, forked with support to Spotinst

301 lines (256 loc) 10.1 kB
'use strict'; import UIROUTER_ANGULARJS from '@uirouter/angularjs'; import { module } from 'angular'; import _ from 'lodash'; import { ViewStateCache } from 'core/cache'; import { SETTINGS } from 'core/config/settings'; import { ConfirmationModalService } from 'core/confirmationModal'; import { DISPLAYABLE_TASKS_FILTER } from './displayableTasks.filter'; import { TaskWriter } from './task.write.service'; import { CORE_TASK_TASKPROGRESSBAR_DIRECTIVE } from './taskProgressBar.directive'; export const CORE_TASK_TASKS_CONTROLLER = 'spinnaker.core.task.controller'; export const name = CORE_TASK_TASKS_CONTROLLER; // for backwards compatibility module(CORE_TASK_TASKS_CONTROLLER, [ UIROUTER_ANGULARJS, CORE_TASK_TASKPROGRESSBAR_DIRECTIVE, DISPLAYABLE_TASKS_FILTER, ]).controller('TasksCtrl', [ '$scope', '$state', '$stateParams', '$q', 'app', function ($scope, $state, $stateParams, $q, app) { if (app.notFound || app.hasError) { return; } const controller = this; const application = app; $scope.$state = $state; const tasksViewStateCache = ViewStateCache.get('tasks') || ViewStateCache.createCache('tasks', { version: 1 }); function cacheViewState() { tasksViewStateCache.put(application.name, $scope.viewState); cacheGlobalViewState(); } function cacheGlobalViewState() { tasksViewStateCache.put('#common', { itemsPerPage: $scope.viewState.itemsPerPage, }); } $scope.tasksUrl = [SETTINGS.gateUrl, 'applications', application.name, 'tasks/'].join('/'); $scope.filterCountOptions = [10, 20, 30, 50, 100, 200]; function initializeViewState() { const viewState = tasksViewStateCache.get(application.name) || { taskStateFilter: '', expandedTasks: [], }; viewState.nameFilter = $stateParams.q || ''; viewState.loading = true; viewState.cancelling = false; viewState.itemsPerPage = tasksViewStateCache.get('#common') ? tasksViewStateCache.get('#common').itemsPerPage : 20; $scope.viewState = viewState; if ($stateParams.taskId) { setTaskFilter(); } } const setTaskFilter = () => { const taskId = $stateParams.taskId; if (!$scope.viewState.expandedTasks.includes(taskId)) { controller.toggleDetails(taskId); } $scope.viewState.nameFilter = taskId; $scope.viewState.taskStateFilter = ''; controller.sortTasksAndResetPaginator(); }; controller.taskStateFilter = 'All'; controller.application = application; controller.sortedTasks = []; controller.toggleDetails = function (taskId) { const index = $scope.viewState.expandedTasks.indexOf(taskId); if (index === -1) { $scope.viewState.expandedTasks.push(taskId); } else { $scope.viewState.expandedTasks.splice(index, 1); } }; controller.isExpanded = function (taskId) { return taskId && $scope.viewState.expandedTasks.includes(taskId); }; controller.sortTasksAndResetPaginator = function () { controller.sortTasks(); controller.resetPaginator(); }; controller.sortTasks = function () { const joinedLists = filterRunningTasks().concat(filterNonRunningTasks()); controller.sortedTasks = joinedLists; if ($scope.viewState.nameFilter) { const normalizedSearch = $scope.viewState.nameFilter.toLowerCase(); controller.sortedTasks = _.filter(joinedLists, function (task) { return ( task.name.toLowerCase().includes(normalizedSearch) || task.id.toLowerCase().includes(normalizedSearch) || (task.getValueFor('credentials') || '').toLowerCase().includes(normalizedSearch) || (task.getValueFor('region') || '').toLowerCase().includes(normalizedSearch) || (task.getValueFor('regions') || []).join(' ').toLowerCase().includes(normalizedSearch) || (task.getValueFor('user') || '').toLowerCase().includes(normalizedSearch) || _.get(task, 'execution.authentication.user', '').toLowerCase().includes(normalizedSearch) ); }); } if ($scope.viewState.taskStateFilter) { controller.sortedTasks = _.filter(controller.sortedTasks, { status: $scope.viewState.taskStateFilter }); } }; controller.clearNameFilter = function () { $scope.viewState.nameFilter = ''; controller.nameFilterUpdated(); }; controller.nameFilterUpdated = _.debounce(() => { const params = { q: $scope.viewState.nameFilter }; if ($state.includes('**.taskDetails')) { $state.go('^', params); } else { $state.go('.', params); } controller.sortTasksAndResetPaginator(); }, 300); controller.cancelTask = function (taskId) { const task = application.tasks.data.filter(function (task) { return task.id === taskId; })[0]; const submitMethod = function () { // cancelTask() polls aggressively waiting for a sucessful cancellation, // which triggers equally aggressive updates to the runningTimeInMs field // on the hydrated task object. Because we render that field in templates, // updating so quickly can make Angular think we're doing Bad Things(tm) // and abort its change detection. Instead, we stop rendering that field // while the polling is active. $scope.viewState.cancelling = true; return TaskWriter.cancelTask(taskId).then(() => { $scope.viewState.cancelling = false; application.tasks.refresh(); }); }; ConfirmationModalService.confirm({ header: 'Really cancel ' + task.name + '?', buttonText: 'Yes', cancelButtonText: 'No', submitMethod: submitMethod, }); }; /** * Pagination - largely copied from applications.controller.js */ controller.resetPaginator = function resetPaginator() { $scope.pagination = { currentPage: 1, itemsPerPage: $scope.viewState.itemsPerPage, maxSize: 12, }; }; controller.resultPage = function resultPage() { const pagination = $scope.pagination; const allFiltered = controller.sortedTasks; const start = (pagination.currentPage - 1) * pagination.itemsPerPage; const end = pagination.currentPage * pagination.itemsPerPage; if (!allFiltered || !allFiltered.length) { return []; } if (allFiltered.length < pagination.itemsPerPage) { return allFiltered; } if (allFiltered.length < end) { return allFiltered.slice(start); } return allFiltered.slice(start, end); }; controller.getFirstDeployServerGroupName = function (task) { if (task.execution && task.execution.stages) { const stage = findStageWithTaskInExecution(task.execution, [ 'createCopyLastAsg', 'createDeploy', 'cloneServerGroup', 'createServerGroup', ]); return _.chain(stage).get('context').get('deploy.server.groups').values().head().head().value(); } }; controller.getAccountId = function (task) { return _.chain(task.variables).find({ key: 'account' }).result('value').value(); }; controller.getRegion = function (task) { const regionVariable = (task.variables || []).find((variable) => { return ( ['deploy.server.groups', 'availabilityZones'].includes(variable.key) && Object.keys(variable.value).length ); }); return regionVariable && Object.keys(regionVariable.value)[0]; }; controller.getProviderForServerGroupByTask = function (task) { const serverGroupName = controller.getFirstDeployServerGroupName(task); return _.chain(application.serverGroups.data) .find(function (serverGroup) { return serverGroup.name === serverGroupName; }) .result('type') .value(); }; function findStageWithTaskInExecution(execution, stageName) { return _.chain(execution.stages) .find(function (stage) { return _.some(stage.tasks, function (task) { return stageName.includes(task.name); }); }) .value(); } function filterRunningTasks() { const running = _.chain(application.tasks.data) .filter(function (task) { return task.name && task.isActive; }) .value(); return running.sort(taskStartTimeComparator); } function filterNonRunningTasks() { const notRunning = _.chain(application.tasks.data) .filter(function (task) { return task.name && !task.isActive; }) .value(); return notRunning.sort(taskStartTimeComparator); } function taskStartTimeComparator(taskA, taskB) { return taskB.startTime > taskA.startTime ? 1 : taskB.startTime < taskA.startTime ? -1 : 0; } // angular ui btn-radio doesn't support the ng-change or ng-click directives $scope.$watch('viewState.taskStateFilter', controller.sortTasksAndResetPaginator); $scope.$watch('viewState', cacheViewState, true); initializeViewState(); application.tasks.activate(); application.tasks.ready().then(() => { $scope.viewState.loading = false; $scope.viewState.loadError = app.tasks.loadFailure; if (!app.tasks.loadFailure) { this.sortTasks(); } }); application.setActiveState(application.tasks); $scope.$on('$destroy', () => { application.setActiveState(); application.tasks.deactivate(); }); this.stateChanged = (q) => { if ($scope.viewState.nameFilter !== q) { $scope.viewState.nameFilter = q; this.sortTasksAndResetPaginator(); } else if ($stateParams.taskId) { setTaskFilter(); } }; $scope.$on('$stateChangeSuccess', (_event, _toState, toParams) => this.stateChanged(toParams.q)); this.application.tasks.onRefresh($scope, this.sortTasks); }, ]);