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 f9d8bcf816fc12e51055b889f16bdbb34e17e55a Author: Alex Heneveld <[email protected]> AuthorDate: Sun Jun 18 11:23:58 2023 +0100 save filters for activity view to session storage, and improve usability * allow reset of filters (clear session storage) * tidy names * fix top-level/subtasks when in list view * remove some confusing badge counts --- .../components/task-list/task-list.directive.js | 233 +++++++++++++++------ .../components/task-list/task-list.template.html | 44 ++-- .../inspect/activities/activities.controller.js | 1 + .../inspect/activities/activities.template.html | 2 +- .../inspect/activities/detail/detail.controller.js | 23 ++ .../inspect/activities/detail/detail.template.html | 3 +- 6 files changed, 220 insertions(+), 86 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 f595e5b8..d951609b 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 @@ -44,6 +44,7 @@ export function taskListDirective() { parentTaskId: '@?', filteredCallback: '&?', search: '<', + contextKey: '@?', // a key to uniquely identify the calling context to save filter settings }, controller: ['$scope', '$element', controller] }; @@ -77,7 +78,7 @@ export function taskListDirective() { Object.values(selected).filter(f => (f.categoryForEvaluation || f.category) === category).forEach(f => { const filter = f.filter; if (!filter) { - console.warn("Incomplete activities tag filter", tagF); + console.warn("Incomplete activities tag filter", f); } else { newResult = newResult.concat(filter(result)); } @@ -119,16 +120,31 @@ export function taskListDirective() { if (!$scope.filters.selectedDisplay.length) $scope.filters.selectedDisplay.push({ class: 'dropdown-category-default', badges: ['all'] }); }; - function selectFilter(filterId, state) { + function selectFilter(filterId, explicitNewValueOrUndefinedForToggle) { + //console.debug("selecting filter: "+filterId+" = "+explicitNewValueOrUndefinedForToggle); const f = $scope.filters.available[filterId]; if (!f) { + //console.debug("selected filter not found; available are", $scope.filters.available); // we tried to select eg effector, when it didn't exist, just ignore return false; } else { - f.select(filterId, f, state); + f.select(filterId, f, explicitNewValueOrUndefinedForToggle); // see defaultToggleFilter for params return true; } } + $scope.clickFilter = (filter, tag) => { + filter.onClick(tag, filter); + if ($scope.contextKey) { + try { + const filters = JSON.stringify(Object.keys($scope.filters.selectedFilters)); + const storageKey = 'brooklyn-task-list-filters-' + $scope.contextKey; + sessionStorage.setItem(storageKey, filters); + //console.debug("Saved filters to session storage", storageKey, filters); + } catch (e) { + console.warn("Unable to save filiters from session storage for", $scope.contextKey, e); + } + } + } $scope.filterValue = $scope.search; @@ -158,47 +174,104 @@ export function taskListDirective() { }); let tasksLoadedTrueReceived = false; + let filtersFromSessionStorage = 'initializing'; // | 'absent' | 'loaded' + + $scope.resetFilters = () => { + tasksLoadedTrueReceived = false; + $scope.uiDropdownInteraction = false; + filtersFromSessionStorage = 'initializing'; + sessionStorage.removeItem('brooklyn-task-list-filters-' + $scope.contextKey) + refreshDropdownsUntilTasksAreLoaded(); + } function refreshDropdownsUntilTasksAreLoaded() { if (tasksLoadedTrueReceived || $scope.uiDropdownInteraction) return; tasksLoadedTrueReceived = $scope.tasksLoaded; - $scope.filters = { available: {}, selectedFilters: {} }; - setFiltersForTasks($scope, isActivityChildren); - selectFilter("_top", true); - selectFilter("_anyTypeTag", true); - if ($scope.taskType) { - if ($scope.taskType == "ALL") { - selectFilter("_top", false); - } else { - selectFilter($scope.taskType); + let preselectedFilters; + if (filtersFromSessionStorage=='initializing') { + if (!$scope.contextKey) filtersFromSessionStorage = 'absent'; + else { + filtersFromSessionStorage = 'absent'; + try { + const filters = sessionStorage.getItem('brooklyn-task-list-filters-' + $scope.contextKey); + if (filters) { + //console.debug("Read filters for", $scope.contextKey, filters); + preselectedFilters = JSON.parse(filters); + } + } catch (e) { + console.warn("Unable to load filiters from session storage for", $scope.contextKey, e); + } } + } + if (filtersFromSessionStorage=='loaded') { + // don't auto-compute if taken from session storage } else { - if (!isActivityChildren) { - // defaults (when not in subtask view; in subtask view it is as above) - selectFilter('_cross_entity'); - selectFilter('_all_effectors'); - selectFilter('EFFECTOR'); - selectFilter('WORKFLOW'); - selectFilter('_scheduled'); - } else { - selectFilter('SUB-TASK'); + + $scope.filters = {available: {}, selectedFilters: {}}; + setFiltersForTasks($scope, isActivityChildren); + + if (preselectedFilters) { + try { + if ($scope.selectedFilters) Object.entries($scope.selectedFilters, (k,v) => selectFilter(k, v, false)); + + $scope.selectedFilters = {}; + preselectedFilters.forEach(fid => { + const f = $scope.filters.available[fid]; + if (!f) { + // don't keep retrying the load, unless tasks aren't loaded yet + if (!$scope.tasksLoaded) { + filtersFromSessionStorage = 'initializing'; // we don't have all the filters yet + } + } else { + selectFilter(fid, f, true); + } + }); + filtersFromSessionStorage = 'loaded'; + } catch (e) { + filtersFromSessionStorage = 'absent'; + console.warn("Unable to process filiters from session storage for", $scope.contextKey, preselectedFilters, e); + } + } + + if (filtersFromSessionStorage == 'absent') { + + selectFilter("_top", true); + selectFilter("_anyTypeTag", true); + if ($scope.taskType) { + if ($scope.taskType == "ALL") { + selectFilter("_top", false); + } else { + selectFilter($scope.taskType); + } + } else { + if (!isActivityChildren) { + // defaults (when not in subtask view; in subtask view it is as above) + selectFilter('_cross_entity'); + selectFilter('_all_effectors'); + selectFilter('EFFECTOR'); + selectFilter('WORKFLOW'); + selectFilter('_periodic'); + } else { + // in children mode we don't want any such filters + } + } + 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('INITIALIZATION'); + } + if ($scope.tasksFilteredByTag.length == 0) { + selectFilter("_anyTypeTag", true); + } + if (!isActivityChildren && $scope.tasksFilteredByTag.length == 0) { + selectFilter("_top", false); + } } - } - 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('INITIALIZATION'); - } - if ($scope.tasksFilteredByTag.length==0) { - selectFilter("_anyTypeTag", true); - } - if ($scope.tasksFilteredByTag.length==0) { - selectFilter("_top", false); } $scope.recomputeTasks(); @@ -256,13 +329,13 @@ export function taskListDirective() { const tasks = tasksAfterGlobalFilters(tasksAll, globalFilters); - function defaultToggleFilter(tag, value, forceValue, fromUi, skipRecompute) { + function defaultToggleFilter(tag, filter, forceValue, fromUi, skipRecompute) { if ((scope.filters.selectedFilters[tag] && _.isNil(forceValue)) || forceValue===false) { delete scope.filters.selectedFilters[tag]; - if (value.onDisabledPost) value.onDisabledPost(tag, value, forceValue); + if (filter.onDisabledPost) filter.onDisabledPost(tag, filter, forceValue); } else { - if (value.onEnabledPre) value.onEnabledPre(tag, value, forceValue); - scope.filters.selectedFilters[tag] = value; + if (filter.onEnabledPre) filter.onEnabledPre(tag, filter, forceValue); + scope.filters.selectedFilters[tag] = filter; } if (fromUi) { // on a UI click, don't try to be too clever about remembered IDs @@ -311,8 +384,17 @@ export function taskListDirective() { const filtersFullList = {}; let tasksById = tasksAll.reduce( (result,t) => { result[t.id] = t; return result; }, {} ); - function filterTopLevelTasks(tasks) { return filterWithId(tasks, tasksById, isTopLevelTask); } - function filterNonTopLevelTasks(tasks) { return filterWithId(tasks, tasksById, isNonTopLevelTask); } + const isChild = (t,tbyid) => { + if (!t.submittedByTask) return false; + return (t.submittedByTask.metadata.id == scope.parentTaskId); + }; + const isNotChild = (t,tbyid) => !isChild(t, tbyid); + function filterTopLevelTasks(tasks) { + return filterWithId(tasks, tasksById, isActivityChildren ? isChild : isTopLevelTask); + } + function filterNonTopLevelTasks(tasks) { + return filterWithId(tasks, tasksById, isActivityChildren ? isNotChild : isNonTopLevelTask); + } function filterCrossEntityTasks(tasks) { return filterWithId(tasks, tasksById, isCrossEntityTask); } function filterNestedSameEntityTasks(tasks) { return filterWithId(tasks, tasksById, isNestedSameEntityTask); } @@ -328,7 +410,9 @@ export function taskListDirective() { 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 (assume _top is always shown) - return [ 'all' ]; + let statusFiltersEnabled = Object.values(scope.filters.selectedFilters).filter(f => f.category === 'status'); + if (statusFiltersEnabled.length) return [ 'some' ]; // if filters applied, indicate that + else return [ 'all' ]; } if (set.length > 1) return [ 'some' ]; // gets too big otherwise return set.map(s => s.displaySummary || ''); @@ -350,7 +434,7 @@ export function taskListDirective() { }, }; filtersFullList['_top'] = { - display: 'Only show ' + (isActivityChildren ? 'direct sub-tasks' : 'top-level tasks'), + display: 'Only list ' + (isActivityChildren ? 'children sub-tasks' : 'top-level tasks'), displaySummary: 'only top-level', isDefault: true, filter: filterTopLevelTasks, // redundant with starting set, but contributes the right count @@ -368,26 +452,26 @@ export function taskListDirective() { onEnabledPre: clearOther('_top'), onDisabledPost: enableFilterIfCategoryEmpty('_top'), } - filtersFullList['_all_effectors'] = { - display: 'Include effector sub-tasks', - displaySummary: 'effectors', - filter: filterForTasksWithTag('EFFECTOR'), + filtersFullList['_recursive'] = { + display: 'Include local sub-tasks', + displaySummary: 'local', + filter: filterNestedSameEntityTasks, category: 'nested', onEnabledPre: clearOther('_top'), onDisabledPost: enableFilterIfCategoryEmpty('_top'), } - filtersFullList['_recursive'] = { - display: 'Include all sub-tasks', - displaySummary: 'sub-tasks', - filter: filterNestedSameEntityTasks, + filtersFullList['_all_effectors'] = { + display: 'Include effector sub-tasks', + displaySummary: 'effectors', + filter: filterForTasksWithTag('EFFECTOR'), category: 'nested', onEnabledPre: clearOther('_top'), onDisabledPost: enableFilterIfCategoryEmpty('_top'), } } else { filtersFullList['_recursive'] = { - display: 'Show all sub-tasks', - displaySummary: 'all sub-tasks', + display: 'Include recursive sub-tasks', + displaySummary: 'recursive', filter: filterNonTopLevelTasks, category: 'nested', onEnabledPre: clearOther('_top'), @@ -404,9 +488,9 @@ export function taskListDirective() { onDisabledPost: enableOthersIfCategoryEmpty('_anyTypeTag'), } - filtersFullList['_scheduled'] = { - display: 'Scheduled', - displaySummary: 'scheduled', + filtersFullList['_periodic'] = { + display: 'Periodic', + displaySummary: 'periodic', filter: tasks => tasks.filter(t => isScheduled(t)), category: 'type-tag', onEnabledPre: clearOther('_anyTypeTag'), @@ -457,8 +541,9 @@ export function taskListDirective() { categoryForEvaluation: 'status-active', } filtersFullList['_scheduled_sub'] = { - display: 'Only show scheduled/repeating tasks', - displaySummary: 'scheduled', + display: 'Only show periodic tasks', + displaySummary: 'periodic', + help: 'If debugging a scheduled repeating task such as a policy or sensor, it can be helpful to show only those tasks.', filter: tasks => tasks.filter(t => { // show scheduled tasks (the parent) and each scheduled run, if sub-tasks are selected // if (!t || !t.submittedByTask) return false; // omit the parent @@ -469,14 +554,18 @@ export function taskListDirective() { onEnabledPre: clearOther('_non_scheduled_sub'), } filtersFullList['_non_scheduled_sub'] = { - display: 'Exclude scheduled/repeating tasks', + display: 'Exclude periodic sub-tasks', displaySummary: 'non-repeating', + help: 'If there are a lot of repeating tasks, it can be helpful to filter them out '+ + 'to find manual and triggers tasks more easily.', filter: tasks => tasks.filter(t => { - return !isScheduled(t, taskId => tasksById[taskId]); + return !isScheduled(t, taskId => tasksById[taskId]) || + isScheduled(t) /* allow root periodic task */; }), category: 'status', categoryForEvaluation: 'status-scheduled', onEnabledPre: clearOther('_scheduled_sub'), + hideBadges: true, // counts don't interact with other filters so it is confusing } const filterWorkflowsReplayedTopLevel = t => !t.isWorkflowFirstRun && t.isWorkflowLastRun && t.isWorkflowTopLevel; @@ -492,6 +581,7 @@ export function taskListDirective() { category: 'workflow', count: countWorkflowsReplayedTopLevel, countAbsolute: countWorkflowsReplayedTopLevel, + hideBadges: true, // counts don't interact with other filters so it is confusing } const countWorkflowsReplayedNested = tasksAll.filter(filterWorkflowsReplayedNested).length; @@ -508,6 +598,7 @@ export function taskListDirective() { category: 'workflow', count: countWorkflowsReplayedNested, countAbsolute: countWorkflowsReplayedNested, + hideBadges: true, // counts don't interact with other filters so it is confusing } const filterWorkflowsWhichAreNotPreviousReplays = t => _.isNil(t.isWorkflowLastRun) || t.isWorkflowLastRun; @@ -525,6 +616,7 @@ export function taskListDirective() { countAbsolute: countWorkflowsWhichArePreviousReplays, categoryForEvaluation: 'workflow-non-last-replays', category: 'workflow', + hideBadges: true, // counts don't interact with other filters so it is confusing } const filterWorkflowsWithoutTaskWhichAreCompleted = t => t.endTimeUtc>0 && t.isTaskStubFromWorkflowRecord; @@ -541,6 +633,7 @@ export function taskListDirective() { countAbsolute: countWorkflowsWithoutTaskWhichAreCompleted, categoryForEvaluation: 'workflow-old-completed', category: 'workflow', + hideBadges: true, // counts don't interact with other filters so it is confusing } const filterWorkflowTasksWhichAreSteps = t => getTaskWorkflowTag(t) && !_.isNil(getTaskWorkflowTag(t)); @@ -557,15 +650,18 @@ export function taskListDirective() { countAbsolute: countWorkflowTasksWhichAreSteps, categoryForEvaluation: 'workflow-steps', category: 'workflow', + hideBadges: true, // counts don't interact with other filters so it is confusing } // fill in fields function updateSelectedFilters(newValues) { + //console.debug("selected filters were", Object.keys(scope.filters.selectedFilters)); Object.entries(scope.filters.selectedFilters).forEach(([filterId, oldValue]) => { const newValue = newValues[filterId]; scope.filters.selectedFilters[filterId] = newValue; if (!newValue) delete scope.filters.selectedFilters[filterId]; }); + //console.debug("selected filters now", Object.keys(scope.filters.selectedFilters)); } updateSelectedFilters(filtersFullList); @@ -584,12 +680,16 @@ export function taskListDirective() { // include non-zero filters or those included if zero Object.entries(filtersFullList).forEach(([k, f]) => { if (f.countAbsolute > 0 || f.includeIfZero) result[k] = f; + //else console.debug("Removing filter", f.display); }); // and delete categories that are redundant function deleteCategoryIfAllCountsAreEqualOrZero(category) { if (_.uniq(Object.values(result).filter(f => f.category === category).filter(f => f.countAbsolute).map(f => f.countAbsolute)).length==1) { - Object.entries(result).filter(([k,f]) => f.category === category).forEach(([k,f])=>delete result[k]); + Object.entries(result).filter(([k,f]) => f.category === category).forEach(([k,f])=> { + //console.debug("Removing category filter", f.display); + delete result[k]; + }); } } // function deleteFiltersInCategoryThatAreEmpty(category) { @@ -598,7 +698,10 @@ export function taskListDirective() { // } function deleteCategoryIfSize1(category) { const found = Object.entries(result).filter(([k,f]) => f.category === category); - if (found.length==1) delete result[found[0][0]]; + if (found.length==1) { + delete result[found[0][0]]; + //console.debug("Removing size 1 category", found[0][0]); + } } // deleteFiltersInCategoryThatAreEmpty('nested'); deleteCategoryIfSize1('nested'); @@ -606,7 +709,7 @@ export function taskListDirective() { if (!result['_cross_entity'] && result['_recursive']) { // if we don't have cross-entity sub-tasks, tidy this message - result['_recursive'].display = 'Include sub-tasks'; + result['_recursive'].display = 'Include nested sub-tasks'; } // // but if we deleted everything, restore them (better to have pointless categories than no categories) @@ -706,7 +809,7 @@ export function durationFilter() { function isTaskWithTag(task, tag) { if (!task.tags) { - console.log("Task without tags: ", task); + // console.log("Task without tags: ", task); return false; } return task.tags.indexOf(tag)>=0; diff --git a/ui-modules/app-inspector/app/components/task-list/task-list.template.html b/ui-modules/app-inspector/app/components/task-list/task-list.template.html index e32d048f..b501ca08 100644 --- a/ui-modules/app-inspector/app/components/task-list/task-list.template.html +++ b/ui-modules/app-inspector/app/components/task-list/task-list.template.html @@ -31,31 +31,33 @@ <ul class="dropdown-menu with-checks" uib-dropdown-menu role="menu" aria-labelledby="single-button"> <li role="menuitem" ng-repeat="(tag,value) in filters.available track by tag" class="activity-tag-filter-tag {{value.classes}}" - ng-click="value.onClick(tag, value)" + ng-click="clickFilter(value, tag)" ng-class="{'selected': filters.selectedFilters[tag]}"> <i class="fa fa-check check if-selected"></i> <span class="main" title="{{value.help}}">{{value.display}}</span> - <span class="badge included" - title="Activities included by this filter"> - {{value.count}} - </span> - <span class="badge excluded-here" - ng-if="value.count > 0" - title="Activities included by this filter"> - {{value.count}} - </span> - <span class="badge more-excluded-elsewhere" - title="Additional activities excluded by other filter categories" - ng-if="value.count > 0 && value.countAbsolute > value.count"> - {{ value.countAbsolute - value.count}} - </span> - <span class="badge all-excluded-elsewhere" - title="Activities are excluded by other filter categories" - ng-if="value.count == 0 && value.countAbsolute > 0"> - {{ value.countAbsolute - value.count}} + <span ng-if="!value.hideBadges"> + <span class="badge included" + title="Activities included by this filter"> + {{value.count}} + </span> + <span class="badge excluded-here" + ng-if="value.count > 0" + title="Activities included by this filter"> + {{value.count}} + </span> + <span class="badge more-excluded-elsewhere" + title="Additional activities excluded by other filter categories" + ng-if="value.count > 0 && value.countAbsolute > value.count"> + {{ value.countAbsolute - value.count}} + </span> + <span class="badge all-excluded-elsewhere" + title="Activities are excluded by other filter categories" + ng-if="value.count == 0 && value.countAbsolute > 0"> + {{ value.countAbsolute - value.count}} + </span> </span> </li> <li role="menuitem" class="activity-tag-filter-action divider-above" style="padding-bottom: 9px;" @@ -64,6 +66,10 @@ <i class="fa fa-check check if-selected"></i> <span class="main" title="{{globalFilters.transient.help}}">{{globalFilters.transient.display}}</span> </li> + <li role="menuitem" class="activity-tag-filter-action divider-above" style="padding-bottom: 9px;" + ng-if="!isEmpty(filters.available)" ng-click="resetFilters()"> + <span class="main" title="Recompute the default filter set for the current tasks">Reset filters</span> + </li> <li role="menuitem" class="activity-tag-filter-error" ng-if="!globalFilters.transient && isEmpty(filters.available)"> <i><span class="main">No filter options</span></i> </li> 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 edf28ff6..d71b81cf 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 @@ -37,6 +37,7 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti } = $stateParams; $scope.search = $stateParams.search; $scope.filter = $stateParams.filter; + $scope.entityId = entityId || applicationId; let vm = this; diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.template.html b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.template.html index 37d8f8e8..01b3864b 100644 --- a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.template.html +++ b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.template.html @@ -21,7 +21,7 @@ <div class="row"> <div ng-class="{ 'col-md-12': true, 'col-lg-8': !vm.wideKilt && vm.isNonEmpty(vm.activitiesDeep), 'col-lg-12': vm.wideKilt || !vm.isNonEmpty(vm.activitiesDeep)}"> <loading-state error="vm.error" ng-if="!vm.activities"></loading-state> - <task-list task-type="{{filter}}" search="search" tasks="vm.activities" tasks-loaded="activitiesLoaded" filtered-callback="vm.onFilteredActivitiesChange" ng-if="vm.activities"></task-list> + <task-list context-key="{{ entityId }}" task-type="{{filter}}" search="search" tasks="vm.activities" tasks-loaded="activitiesLoaded" filtered-callback="vm.onFilteredActivitiesChange" ng-if="vm.activities"></task-list> </div> <div ng-class="{ 'col-md-12': true, 'col-lg-4': !vm.wideKilt, 'col-lg-12': vm.wideKilt }" ng-if="vm.isNonEmpty(vm.activitiesDeep)"> 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 75bcd9a8..d80d1c40 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 @@ -325,9 +325,29 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod }); }); + function onActivityLoadUpdate() { + vm.model.activityChildrenAndDeep = []; + let seen = {}; + if (vm.model.activityChildren) { + vm.model.activityChildren.forEach(t => { + vm.model.activityChildrenAndDeep.push(t); + seen[t.id] = true; + }); + } + if (vm.model.activitiesDeep) { + Object.values(vm.model.activitiesDeep).forEach(t => { + if (!seen[t.id]) { + vm.model.activityChildrenAndDeep.push(t); + seen[t.id] = true; + } + }); + } + } + activityApi.activityChildren(activityId).then((response)=> { vm.model.activityChildren = processActivityChildren(response.data); vm.error = undefined; + onActivityLoadUpdate(); // could improve by making just one call for children+deep, or combining the results; // but for now just read them both frequently @@ -337,6 +357,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod if (!vm.errorBasic) { vm.error = undefined; } + onActivityLoadUpdate(); })); }).catch((error)=> { $log.warn('Error loading activity children for '+activityId, error); @@ -348,6 +369,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod activityApi.activityDescendants(activityId, 8, true).then((response)=> { vm.model.activitiesDeep = response.data; vm.error = undefined; + onActivityLoadUpdate(); if (!vm.model.activity.endTimeUtc || vm.model.activity.endTimeUtc<0) response.interval(1000); observers.push(response.subscribe((response)=> { @@ -355,6 +377,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod if (!vm.errorBasic) { vm.error = undefined; } + onActivityLoadUpdate(); })); }).catch((error)=> { $log.warn('Error loading activity children deep for '+activityId, error); 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 652ce3d8..c78452d7 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 @@ -337,7 +337,8 @@ <div class="row"> <div ng-class="{ 'col-md-12': true, 'col-lg-8': !vm.wideKilt && vm.isNonEmpty(vm.model.activitiesDeep), 'col-lg-12': vm.wideKilt || !vm.isNonEmpty(vm.model.activitiesDeep)}"> - <task-list tasks="vm.model.activityChildren" parent-task-id="vm.model.activityId" filtered-callback="vm.onFilteredActivitiesChange"></task-list> + <task-list context-key="{{ vm.model.activityId }}" tasks="vm.model.activityChildrenAndDeep" parent-task-id="{{ vm.model.activityId }}" filtered-callback="vm.onFilteredActivitiesChange" + tasks-loaded="vm.model.activityChildren && vm.model.activitiesDeep"></task-list> </div> <div ng-class="{ 'col-md-12': true, 'col-lg-4': !vm.wideKilt, 'col-lg-12': vm.wideKilt }" ng-if="vm.isNonEmpty(vm.model.activitiesDeep)"> <expandable-panel expandable-template="vm.modalTemplate" class="panel-table">
