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">

Reply via email to