This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-ui.git
commit fa05e72ace12476d420ade79e1c73ca6b5ebfd9a Author: Alex Heneveld <[email protected]> AuthorDate: Fri Oct 21 14:54:05 2022 +0100 more task list filter selection tweaks --- .../components/task-list/task-list.directive.js | 53 +++++++++++++++------- .../components/workflow/workflow-step.directive.js | 1 + .../workflow/workflow-step.template.html | 14 +++++- .../workflow/workflow-steps.directive.js | 2 +- .../inspect/activities/activities.controller.js | 23 ++++++++-- .../inspect/activities/detail/detail.controller.js | 4 +- .../main/inspect/activities/detail/detail.less | 2 +- .../inspect/activities/detail/detail.template.html | 29 ++++++++---- .../views/main/inspect/confirm.modal.template.html | 2 +- .../app/views/main/inspect/inspect.controller.js | 8 ++-- 10 files changed, 100 insertions(+), 38 deletions(-) diff --git a/ui-modules/app-inspector/app/components/task-list/task-list.directive.js b/ui-modules/app-inspector/app/components/task-list/task-list.directive.js index 4e0d754e..2b9c7c58 100644 --- a/ui-modules/app-inspector/app/components/task-list/task-list.directive.js +++ b/ui-modules/app-inspector/app/components/task-list/task-list.directive.js @@ -165,11 +165,14 @@ export function taskListDirective() { selectFilter('SUB-TASK'); } } + if (!isActivityChildren) selectFilter("_workflowStepsHidden"); selectFilter("_workflowReplayedTopLevel"); selectFilter("_workflowNonLastReplayHidden"); + selectFilter("_workflowCompletedWithoutTaskHidden"); // pick other filter combos until we get some conetnt if ($scope.tasksFilteredByTag.length==0) { + selectFilter('_cross_entity'); selectFilter('INITIALIZATION'); } if ($scope.tasksFilteredByTag.length==0) { @@ -305,15 +308,10 @@ export function taskListDirective() { if (!set || !set.length) return null; let nestedFiltersAvailable = Object.values(scope.filters.available).filter(f => f.category === 'nested'); if (set.length == nestedFiltersAvailable.length-1 && !set[0].isDefault) { - // everything but first is selected, so no message + // everything but first is selected, so no message (assume _top is always shown) return [ 'all' ]; } return set.map(s => s.displaySummary || ''); - // if (set.length==1) { - // return [ getFilterOrEmpty(set[0]).displaySummary ]; - // } - // // only happens if we have - // return null; }, 'type-tag': set => { if (!set || !set.length) return null; @@ -332,6 +330,7 @@ export function taskListDirective() { category: 'nested', onEnabledPre: clearCategory(), onDisabledPost: enableOthersIfCategoryEmpty('_top'), + includeIfZero: true, } if (!isActivityChildren) { filtersFullList['_cross_entity'] = { @@ -395,11 +394,12 @@ export function taskListDirective() { filtersFullList['SUB-TASK'] = false; // add filters for other tags - tasks.forEach(t => - (t.tags || []).filter(tag => typeof tag === 'string' && tag.length < 32).forEach(tag => - addTagFilter(tag, filtersFullList, 'Tag: ' + tag.toLowerCase()) - )); + let tags = _.uniq(tasks.flatMap(t => (t.tags || []).filter(tag => typeof tag === 'string' && tag.length < 32))); + tags.sort( (t1,t2) => t1.toLowerCase().localeCompare(t2.toLowerCase()) ); + // same tag with different cases will be shown multiple times, unable to disambiguate, but that's unlikely + tags.forEach(tag => addTagFilter(tag, filtersFullList, 'Tag: ' + tag.toLowerCase()) ); + Object.entries(filtersFullList).forEach(([k,v]) => { if (!v) delete filtersFullList[k]; }); ['EFFECTOR', 'WORKFLOW', 'SUB-TASK', 'SENSORS', 'INITIALIZATION'].forEach(t => { if (!filtersFullList[t]) delete filtersFullList[t]; }); (filtersFullList['SUB-TASK'] || {}).display = 'Sub-tasks'; (filtersFullList['SENSOR'] || {}).display = 'Sensors'; @@ -426,6 +426,7 @@ export function taskListDirective() { categoryForEvaluation: 'status-scheduled', } + const filterWorkflowsReplayedTopLevel = t => !t.isWorkflowFirstRun && t.isWorkflowLastRun && t.isWorkflowTopLevel; const countWorkflowsReplayedTopLevel = tasksAll.filter(filterWorkflowsReplayedTopLevel).length; filtersFullList['_workflowReplayedTopLevel'] = { @@ -470,7 +471,7 @@ export function taskListDirective() { filter: tasks => tasks.filter(filterWorkflowsWhichAreNotPreviousReplays), count: countWorkflowsWhichArePreviousReplays, countAbsolute: countWorkflowsWhichArePreviousReplays, - categoryForEvaluation: 'workflow1', + categoryForEvaluation: 'workflow-non-last-replays', category: 'workflow', } @@ -483,10 +484,26 @@ export function taskListDirective() { 'or because their tasks have been cleared from memory in this server. ' + 'These can be excluded to focus on more recent tasks.', displaySummary: null, - filter: tasks => tasks.filter(filterWorkflowsWithoutTaskWhichAreCompleted), + filter: tasks => tasks.filter(t => !filterWorkflowsWithoutTaskWhichAreCompleted(t)), count: countWorkflowsWithoutTaskWhichAreCompleted, countAbsolute: countWorkflowsWithoutTaskWhichAreCompleted, - categoryForEvaluation: 'workflow2', + categoryForEvaluation: 'workflow-old-completed', + category: 'workflow', + } + + const filterWorkflowTasksWhichAreSteps = t => getTaskWorkflowTag(t) && !_.isNil(getTaskWorkflowTag(t)); + const countWorkflowTasksWhichAreSteps = tasksAll.filter(filterWorkflowTasksWhichAreSteps).length; + filtersFullList['_workflowStepsHidden'] = { + display: 'Exclude individual workflow steps', + help: 'Individual steps within workflows are hidden in most views, except where showing workflow tasks. ' + + 'This makes it easier to navigate to primary tasks, such as workflows, and from there explore the steps within. ' + + 'If this option is disabled and if nested sub-tasks are enabled, then individual steps will be listed in this view ' + + 'to facilitate finding a specific step.', + displaySummary: null, + filter: tasks => tasks.filter(t => _.isNil((getTaskWorkflowTag(t) || {}).stepIndex)), + count: countWorkflowTasksWhichAreSteps, + countAbsolute: countWorkflowTasksWhichAreSteps, + categoryForEvaluation: 'workflow-steps', category: 'workflow', } @@ -512,6 +529,7 @@ export function taskListDirective() { // filter and move to new map let result = {}; + // include non-zero filters or those included if zero Object.entries(filtersFullList).forEach(([k, f]) => { if (f.countAbsolute > 0 || f.includeIfZero) result[k] = f; }); @@ -522,14 +540,15 @@ export function taskListDirective() { Object.entries(result).filter(([k,f]) => f.category === category).forEach(([k,f])=>delete result[k]); } } - function deleteFiltersInCategoryThatAreEmpty(category) { - Object.entries(result).filter(([k,f]) => f.category === category && f.countAbsolute==0).forEach(([k,f])=>delete result[k]); - } + // function deleteFiltersInCategoryThatAreEmpty(category) { + // // redundant with population of 'result' above + // Object.entries(result).filter(([k,f]) => f.category === category && f.countAbsolute==0 && !f.includeIfZero).forEach(([k,f])=>delete result[k]); + // } function deleteCategoryIfSize1(category) { const found = Object.entries(result).filter(([k,f]) => f.category === category); if (found.length==1) delete result[found[0][0]]; } - deleteFiltersInCategoryThatAreEmpty('nested'); + // deleteFiltersInCategoryThatAreEmpty('nested'); deleteCategoryIfSize1('nested'); deleteCategoryIfAllCountsAreEqualOrZero('type-tag'); // because all tags are on all tasks diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js b/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js index 39bd3a64..3d9dbc60 100644 --- a/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js +++ b/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js @@ -117,6 +117,7 @@ export function workflowStepDirective() { $scope.stepContext = ($scope.isCurrentMaybeInactive ? workflow.data.currentStepInstance : $scope.osi.context) || {}; $scope.isFocusStep = $scope.workflow.tag && ($scope.workflow.tag.stepIndex === index); $scope.isFocusTask = false; + $scope.isErrorHandler = $scope.workflow.tag && ($scope.workflow.tag.errorHandlerForTask); $scope.stepCurrentError = (($scope.task || {}).currentStatus === 'Error') ? 'This step returned an error.' : ($scope.isWorkflowError && $scope.isCurrentMaybeInactive) ? 'The workflow encountered an error around this step.' diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html b/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html index 4480b0c7..8d8f3e0f 100644 --- a/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html +++ b/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html @@ -110,7 +110,19 @@ </span> </div> - <div ng-if="isFocusStep && !isFocusTask" class="space-above"> + <div ng-if="isErrorHandler" class="space-above"> + The task on this page is for the error handler for this step. + More details may be found in the other sections on this page. + </div> + + <div ng-if="stepContext.errorHandlerTaskId && !isErrorHandler" class="space-above"> + The error triggered an error handler in + <b><a ui-sref="main.inspect.activities.detail({entityId: vm.model.entityId, activityId: stepContext.errorHandlerTaskId, workflowId})"> + <span class="monospace">task {{stepContext.errorHandlerTaskId}}</span + ></a></b>. + </div> + + <div ng-if="isFocusStep && !isFocusTask && !isErrorHandler" class="space-above"> <b>The activity currently being viewed (<span class="monospace">{{ task.id }}</span>) is for a previous run of this step.</b> </div> diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js b/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js index 15c9dce9..ab49d345 100644 --- a/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js +++ b/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js @@ -232,7 +232,7 @@ function makeArrows(workflow, steps) { } } - for (var i = -1; i < steps.length - 1; i++) { + for (var i = -1; i < steps.length; i++) { const prevsHere = stepsPrev[i]; if (prevsHere && prevsHere.length) { prevsHere.forEach(prev => { diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js index 2ec31d57..449504e6 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js +++ b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js @@ -72,6 +72,7 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti newActivitiesMap[activity.id] = activity; }); + const workflowActivities = {} Object.values(vm.workflows || {}) .filter(wf => wf.replays && wf.replays.length) .forEach(wf => { @@ -84,7 +85,8 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti if (!t) { // create stub tasks for the replays of workflows t = makeTaskStubFromWorkflowRecord(wf, wft); - newActivitiesMap[wft.taskId] = t; + workflowActivities[wft.taskId] = t; + //newActivitiesMap[wft.taskId] = t; } t.workflowId = wf.workflowId; t.workflowParentId = wf.parentId; @@ -101,8 +103,23 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti lastTask.isWorkflowLastRun = true; }); + // workflow stubs need sorting by us + let workflowStubsToSort = Object.values(workflowActivities); + function firstDate(d1, d2, nextSupplier) { + if (d1==d2) return nextSupplier(); + if (!(d1>0) && !(d2>0)) return nextSupplier(); + if (d1>0 && d2>0) return d2-d1; + return d1>0 ? 1 : -1; + } + workflowStubsToSort.sort( (w1,w2) => + firstDate(w1.endTimeUtc, w2.endTimeUtc, + () => firstDate(w1.startTimeUtc, w2.startTimeUtc, + () => firstDate(w1.submitTimeUtc, w2.submitTimeUtc, + () => 0))) ); + workflowStubsToSort.forEach(wst => newActivitiesMap[wst.id] = wst); + vm.activitiesMap = newActivitiesMap; - vm.activities = Object.values(vm.activitiesMap); + vm.activities = Object.values(newActivitiesMap); } } @@ -178,7 +195,7 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti export function makeTaskStubFromWorkflowRecord(wf, wft) { const result = { id: wft.taskId, - displayName: wf.name + (wft.reasonForReplay ? " ("+wft.reasonForReplay+")" : ""), + displayName: wf.name + (wft.reasonForReplay && wft.reasonForReplay!="initial run" ? " ("+wft.reasonForReplay+")" : ""), entityId: (wf.entity || {}).id, isError: wft.isError===false ? false : true, currentStatus: _.isNil(wft.isError) ? "Unavailable" : wft.status, diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js index c994e19a..79476af8 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js +++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js @@ -106,7 +106,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod // give a better error vm.error = $sce.trustAsHtml('Limited information on workflow task <b>' + _.escape(activityId) + '</b>.<br/><br/>' + (!vm.model.activity.endTimeUtc || vm.model.activity.endTimeUtc == -1 - ? "The run appears to have been interrupted by a server restart or failover." + ? "The run appears to have been interrupted, either by a server restart or a failure or cancellation and removal from memory." : 'The workflow is known but this task is no longer stored in memory.')); } @@ -171,7 +171,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod else if (replayableContinuing) w2 = ''; $scope.actions.workflowReplays.push({targetId: 'start', reason: 'Restart workflow from UI', - label: 'Restart '+(stepIndex>=0 ? 'workflow ' : '')+reason}); + label: w1+' '+(stepIndex>=0 ? 'workflow ' : '')+w2}); } if (!replayableFromStart) { diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less index f72d2922..c26d5989 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less +++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less @@ -234,7 +234,7 @@ } div.workflow-preface-para { margin-top: 12px; - margin-bottom: 24px; + margin-bottom: 12px; } } diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html index 74cdf90b..b8c245c6 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html +++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html @@ -118,10 +118,10 @@ <div class="col-md-3 summary-item summary-item-timestamp"> <div class="summary-item-label">Submitted</div> <div class="summary-item-value"> - <div class="humanized fade" ng-show="!showUTC"> + <div class="humanized fade" ng-show="!showUTC || !(vm.model.activity.submitTimeUtc>0)"> {{vm.model.activity.submitTimeUtc | timeAgoFilter}} </div> - <div class="utcTime fade" ng-show="showUTC"> + <div class="utcTime fade" ng-show="showUTC && vm.model.activity.submitTimeUtc>0"> {{vm.model.activity.submitTimeUtc | dateFilter }} </div> </div> @@ -129,10 +129,10 @@ <div class="col-md-3 summary-item summary-item-timestamp"> <div class="summary-item-label">Started</div> <div class="summary-item-value"> - <div class="humanized fade" ng-show="!showUTC"> + <div class="humanized fade" ng-show="!showUTC || !(vm.model.activity.startTimeUtc>0)"> {{vm.model.activity.startTimeUtc | timeAgoFilter}} </div> - <div class="utcTime fade" ng-show="showUTC"> + <div class="utcTime fade" ng-show="showUTC && vm.model.activity.startTimeUtc>0"> {{vm.model.activity.startTimeUtc | dateFilter }} </div> </div> @@ -140,10 +140,10 @@ <div ng-if="vm.model.activity.endTimeUtc" class="col-md-3 summary-item summary-item-timestamp"> <div class="summary-item-label">Finished</div> <div class="summary-item-value"> - <div class="humanized fade" ng-show="!showUTC"> + <div class="humanized fade" ng-show="!showUTC || !(vm.model.activity.endTimeUtc>0)"> {{vm.model.activity.endTimeUtc | timeAgoFilter}} </div> - <div class="utcTime fade" ng-show="showUTC"> + <div class="utcTime fade" ng-show="showUTC && vm.model.activity.endTimeUtc>0"> {{vm.model.activity.endTimeUtc | dateFilter }} </div> </div> @@ -210,7 +210,7 @@ </ul> </div> </div> - <div style="margin-top: 12px; margin-bottom: 24px;"> + <div class="workflow-preface-para"> This task is <span ng-if="!vm.isNullish(vm.model.workflow.tag.stepIndex)">for step <b>{{ vm.model.workflow.tag.stepIndex+1 }}</b> in @@ -255,8 +255,21 @@ ></a></b>. </div> + <div ng-if="vm.model.workflow.data.errorHandlerTaskId" class="workflow-preface-para"> + <span ng-if="vm.model.activityId==vm.model.workflow.data.errorHandlerTaskId"> + This is the page for the error handler for this workflow. + More details of how the error was handled can be found in other sections on this page. + </span> + <span ng-if="vm.model.activityId!=vm.model.workflow.data.errorHandlerTaskId"> + This workflow had an error which ran error handler + <b><a ui-sref="main.inspect.activities.detail({entityId: vm.model.entityId, activityId: vm.model.workflow.data.errorHandlerTaskId, workflowId})"> + <span class="monospace">task {{vm.model.workflow.data.errorHandlerTaskId}}</span + ></a></b>. + </span> + </div> + <div ng-if="vm.model.workflow.runIsOld" class="workflow-preface-para"> - For previous runs, the subtask view + For previous runs such as this, the subtask view <span ng-if="!vm.isNullish(vm.model.workflow.tag.stepIndex)">for <a ui-sref="main.inspect.activities.detail({entityId: vm.model.entityId, activityId: vm.model.workflow.runReplayId, workflowId})"> the relevant run diff --git a/ui-modules/app-inspector/app/views/main/inspect/confirm.modal.template.html b/ui-modules/app-inspector/app/views/main/inspect/confirm.modal.template.html index 97e443b8..a7a7567d 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/confirm.modal.template.html +++ b/ui-modules/app-inspector/app/views/main/inspect/confirm.modal.template.html @@ -29,5 +29,5 @@ <div class="modal-footer"> <button class="btn btn-default" ng-click="$dismiss('Close modal')" type="button">Cancel</button> - <button class="btn btn-danger" ng-click="$close()" type="button">Ok</button> + <button class="btn btn-danger" ng-click="$close()" type="button">OK</button> </div> diff --git a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js index 636825e9..e3ab4fe2 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js +++ b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js @@ -26,11 +26,11 @@ export const inspectState = { name: 'main.inspect', url: 'application/:applicationId/entity/:entityId', template: template, - controller: ['$scope', '$stateParams', '$uibModal', 'brSnackbar', 'entityApi', inspectController], + controller: ['$scope', '$state', '$stateParams', '$uibModal', 'brSnackbar', 'entityApi', inspectController], controllerAs: 'vm' }; -export function inspectController($scope, $stateParams, $uibModal, brSnackbar, entityApi) { +export function inspectController($scope, $state, $stateParams, $uibModal, brSnackbar, entityApi) { const { applicationId, entityId @@ -68,7 +68,7 @@ export function inspectController($scope, $stateParams, $uibModal, brSnackbar, e entityId: ()=>(entityId), } }).result.then((closeData)=> { - $state.go('main.inspect.activites', { + $state.go('main.inspect.activities.detail', { applicationId: applicationId, entityId: closeData.entityId, activityId: closeData.id @@ -87,7 +87,7 @@ export function inspectController($scope, $stateParams, $uibModal, brSnackbar, e entityId: ()=>(entityId), } }).result.then((closeData)=> { - $state.go('main.inspect.activites', { + $state.go('main.inspect.activities.detail', { applicationId: applicationId, entityId: closeData.entityId, activityId: closeData.id
