How to show 'HRM Todos Summary' widget in separate tabs for 'My Tasks' page on ESC Portal

Pooja Magadum
Tera Contributor

Hi All,

 

I need to show 'My Tasks' page, 'HRM Todos Summarywidget in below 4 separate tabs, each tab should show the approvals in Open and Completed sections.

1. BAU Request Approvals 

2. New Feature Request Approvals
2. Change Approvals
3. Knowledge Article Approvals

 

I have cloned the OOTB widget ['HRM Todos Summary'] and created a new widget to show the cloned widgets in tabbed format, but I am not able to segregate the records for each tabs. 

 

Basically I need to update the filter to show respective records in each tab.

 

Can someone please help me ?

PoojaMagadum_0-1747804447909.png

 

Thanks,

Pooja

3 REPLIES 3

Ankur Bawiskar
Tera Patron
Tera Patron

@Pooja Magadum 

please share your cloned widget HTML, Client Controller and Server script here

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

Hi @Ankur Bawiskar ,

 

Here it is :

 

Widget : VCG_HRM Knowledge Article Approvals [vcg_hrm_knowledge_article_approvals] for 4th tab

 

HTML : 

 

<div class="todos-widget" ng-class="{'todos-widget-mobile': !c.data.onTicketPage && c.mobileDevice}">
<h2 class="page-title" ng-if="( (!data.onTicketPage && !c.mobileDevice) || (!data.onTicketPage && c.mobileDevice && c.data.todoSummaryLeftPanel))" ng-bind="::c.data.txt.title"></h2>
<div ng-if="!data.onTicketPage">
<sp-widget widget="c.data.todosFilters"></sp-widget>
</div>
<div class="visible-xs back-button-mobile padder-b" ng-if="(c.mobileDevice && !c.data.todoSummaryLeftPanel && !isSignPadVisible)">
<a ng-click="c.openTodosSummaryList()" href class="close-task"><i class="fa fa-chevron-left" ng-class="{'back-padding': !c.data.onTicketPage, 'ticket-back-padding': c.data.onTicketPage}"></i>${Back}</a>
<div class="pull-right" ng-if="c.todoDisplayed[c.currentTab].length > 1">
<a href ng-click="c.getPreviousTodo()" ng-class="{'isDisabled':!c.hasPreviousTodo()}" data-toggle="tooltip" title="Open Previous To-do" aria-label="Open Previous Todo" class="arrow-mobile" tabindex="{{c.hasPreviousTodo() ? '0' : '-1'}}"><i class="fa fa-arrow-up"></i></a>
<a href ng-click="c.getNextTodo()" ng-class="{'isDisabled':!c.hasNextTodo()}" data-toggle="tooltip" title="Open Next To-do" aria-label="Open Next Todo" class="arrow-mobile" tabindex="{{c.hasNextTodo() ? '0' : '-1'}}"><i class="fa fa-arrow-down"></i></a>
</div>
</div>
<div class="visible-xs back-button-mobile padder-b" ng-if="(c.mobileDevice && isSignPadVisible)">
<a ng-click="showSignPad()" href="javascript&colon;void(0)" class="close-task"><i class="fa fa-chevron-left" ng-class="{'back-padding': !data.onTicketPage, 'ticket-back-padding': data.onTicketPage}"></i>${Back}</a>

</div>
<div id="todo-panel" class="content-wrap b row-eq-height" ng-class="{'mobile-todo-panel': c.mobileDevice}">
<div id="todo-left-panel" class="col-md-3 col-sm-3 col-lg-3 col-xs-12 no-padder todo-left-panel" ng-show="(!c.mobileDevice || c.mobileDevice && c.data.todoSummaryLeftPanel)">
<div ng-if="c.data.onTicketPage" class="panel-heading panel-border-bottom">
<h4><a ng-click="c.backToTaskList()" ng-keydown="backToListKeyDown($event)" class="back-to-tasklist" aria-label="{{data.activitySetAriaLabel}}" tabindex="0" href="javascript&colon;void(0)">
<i class="fa fa-chevron-left m-r-sm"></i> {{data.activitySetName}}
</a></h4>
</div>
<div>
<ul class="nav nav-tabs" ng-if="!c.data.onTicketPage" role="tablist">
<li ng-class="{'active': (c.currentTab == tab.name)}" ng-repeat="tab in ::c.data.tabs" ng-click="c.onTabClick(tab)" class="tab" role="presentation">
<a id="tab{{$index}}" data-toggle="tab" data-target="#{{::tab.name}}, #{{::tab.name}}-content" role="tab" ng-bind="tab.label" aria-controls="{{::tab.name}}" aria-label="{{::tab.name}}" tabindex="{{(c.currentTab == tab.name) ? 0 : -1}}" aria-selected="{{(c.currentTab == tab.name) ? 'true' : 'false'}}"></a>
</li>
</ul>
<div class="tab-content clearfix" ng-class="{'large-nav': c.data.onTicketPage || c.navBarScrollable}" aria-live="polite" role="tabpanel">
<ul id="{{::tab.name}}" class="tab-pane" ng-class="{'in active': (c.currentTab == tab.name)}" ng-repeat="tab in ::c.data.tabs" role="list" aria-labelledby="{{tab.name}}" aria-hidden="false">
<li ng-repeat="todo in c.todoDisplayed[tab.name]" role="listitem"
ng-click="c.openTodo(todo.sysId, tab.name);" tabindex="0"
ng-class="{'todos-list': !c.accessibility, 'todos-list-accessibility': c.accessibility, selected: (!c.mobileDevice && todo.isOpen),'completed-to-do': (data.onTicketPage && todo.isCompleted && !todo.isOpen) }"
id="{{todo.sysId}}_task_lineitem_summary">
<div ng-if="todo.delegates.length > 0 || (todo.delegator && todo.delegator.name)"
class="todo-summary-delegates">11
<span tabindex="0"
aria-label="{{ (todo.delegator && todo.delegator.name) ? c.getDelegatedByText(todo.delegator.name) : todo.delegates }}"
uib-tooltip="{{ (todo.delegator && todo.delegator.name) ? c.getDelegatedByText(todo.delegator.name) : todo.delegates }}"
tooltip-placement="top"
tooltip-append-to-body="true">
<i class="fa fa-sm"
ng-class="(todo.delegator && todo.delegator.name) ? 'fa-arrow-circle-o-left' : 'fa-arrow-circle-o-right'"></i>
<span ng-bind="::data.i18n.DELEGATED"></span>
</span>
</div>
<div ng-include="'vcg_hrm-knowledge-article-approvals-header-widget.html'"></div>
</li>
<li ng-if="c.loadingMore[tab.name] || !c.loaded[tab.name]" class="loading-indicator-fetchmore">
<span class="fa fa-spinner fa-spin" aria-hidden="true" name="spinner" spin="true"></span>
${Loading}...
</li>
<li role="listitem" ng-if="c.loaded[tab.name] && !c.stopLoadMore[tab.name] && !c.data.onTicketPage && c.todoDisplayed[tab.name].length > c.limit" class="load-more-button">
<button ng-click="c.fetchMoreRecords(tab.name);" class="btn btn-default">${Show more}</button>
</li>
</ul>
</div>
</div>
</div>
<div id="todo-right-panel" class="col-md-9 col-sm-9 col-lg-9 col-xs-12 b-l no-padder" ng-class="{'todo-right-native':!c.mobileDevice}" ng-if="!c.mobileDevice || (c.mobileDevice && !c.data.todoSummaryLeftPanel) || (c.mobileDevice && c.todoDisplayed[c.currentTab].length == 0)">
<div id="{{::tab.name}}-content" class="tab-pane" ng-class="{'in active': (c.currentTab == tab.name)}" ng-repeat="tab in ::c.data.tabs" role="tabpanel" tab-index="0" aria-labelledby="{{tab.name}}" aria-hidden="false">
<div ng-if="!c.selectedFiltersFromTodoPage.applyFilters && !c.loadingMore[tab.name] && !c.todoDisplayed[tab.name].length && c.loaded[tab.name]" class="panel-heading text-center empty-message">
<p><i class="fa fa-3x fa-check-circle success empty-state-icon"></i></p>
<h3 class= "empty-state-title" ng-if="!c.todoDisplayed[tab.name].length" ng-bind="c.data.txt.empty[tab.name] ? c.data.txt.empty[tab.name].title : c.data.txt.empty[data.defaultTab].title"></h3>
<h4 class= "empty-state-title" ng-if="c.todoDisplayed[tab.name].length" ng-bind="c.data.txt.onComplete"></h4>
</div>
<div ng-if="c.selectedFiltersFromTodoPage.applyFilters && !c.loadingMore[tab.name] && !c.todoDisplayed[tab.name].length && c.loaded[tab.name]" class="panel-heading text-center empty-message">
<p><i class="fa fa-3x fa-times-circle-o empty-state-icon"></i></p>
<h3 class= "empty-state-title" ng-if="!c.todoDisplayed[tab.name].length">${No results match your criteria}</h3>
<h4 class= "empty-state-title" ng-if="c.todoDisplayed[tab.name].length" ng-bind="c.data.txt.onComplete"></h4>
<p ng-if="!c.todoDisplayed[tab.name].length && !c.data.onTicketPage" class= "empty-state-message status">${Try removing some filters}</p>
</div>
<div ng-if="c.todoDisplayed[tab.name].length && todoLine.isOpen" class="task-content" ng-repeat="todoLine in c.todoDisplayed[tab.name]">
<div ng-if="todoLine.todoLineWidget">
<sp-widget widget="todoLine.todoLineWidget"></sp-widget>
</div>
<div class="loading-indicator" ng-if="!todoLine.todoLineWidget">
<span class="fa fa-spinner fa-spin" aria-hidden="true" name="spinner" spin="true"></span>
${Loading}...
</div>
</div>
</div>
</div>
</div>
</div>

 

************************************************************************************************************

 

Server Script : 

 

(function() {
    //Check if current task is survey
    data.isTaskSurvey = false;
   
    data.todoParameter = $sp.getParameter('todo');
    data.selectedFiltersFromTodoPage = [];
    data.isLPActive = new GlidePluginManager().isActive('sn_lp');

    if (input && input.action == 'checkTaskType'){
        var gr = new GlideRecordSecure(input.table);
        if (gr.get(input.sysId) && gr.hr_task_type == 'take_survey')
            data.isTaskSurvey = true;
    } if(input && input.action == 'addNotification'  && data.isLPActive) {
        var pulseUtils = new sn_lp.PulseUtilsAjax();
        data.taskInfo = pulseUtils.checkForTriggeredConditions ? pulseUtils.checkForTriggeredConditions(input.table, input.taskId) : {};
    }

    // translated text
    data.i18n = {
        DELEGATED: gs.getMessage("Delegated"),
        DELEGATED_BY: gs.getMessage("Delegated by: {}")
    };

    data.isMobile = gs.isMobile();
    data.todoSummaryLeftPanel = true;
    data.todosToShow = {
            recordsToShow : {},
            recordWatchers : []
    };
    data.watchers =[];
    data.async = (input && input.onTicketPage) ? false : true;

    var util = new sn_hr_sp.todoPageUtils();
    data.tabs = util.getTabs();
    data.defaultTab = data.tabs[0].name;
    data.queryLimit = todoPageUtils.QUERY_LIMIT;

    data.todosFilters = $sp.getWidget('todos-filters', {});

    data.txt = {
        empty: {},
        onComplete: gs.getMessage('All tasks are Complete'),
        title: gs.getMessage('My tasks'),
        breadcrumb: gs.getMessage('My tasks'),
        backToAriaLabel: gs.getMessage('Back to {0}')
    };
    data.txt.empty[data.defaultTab] = {
        title: gs.getMessage("You don't have any tasks right now.")
    };

    data.txt.empty.completed = {
        title: gs.getMessage("You don't have any completed tasks yet.")
    };

    if (input && input.action == "loadFromTicketPage") {
        data.todosToShow.recordsToShow = util.splitInTabs(new sn_hr_sp.hr_PortalUtil().processRecordsForSummary(input.recordsToShow), data.defaultTab);
        data.todosToShow.recordWatchers = input.recordWatchers;
        data.watchers = data.todosToShow.recordWatchers||[];
        data.onTodoPage = false;
        data.onTicketPage = true;
        data.parentCaseId = input.parent;
        data.activitySetName = input.activitySetName;
        data.activitySetAriaLabel = data.txt.backToAriaLabel.replace('{0}', data.activitySetName);
        data.activitySetId = input.activitySetId;
        data.selectedTodo = input.todoSelected;
        data.currentTodoIndex = (data.todosToShow.recordsToShow[data.defaultTab] && data.todosToShow.recordsToShow[data.defaultTab].length > input.currentTodoIndex) ? input.currentTodoIndex: 0;
        data.hideTodoSummary = input.hideTodoSummary;
    } else if (input && input.action == "loadTodos") {
        data.onTodoPage = true;
        data.onTicketPage = false;
        if (input.limit) {
                       data.queryLimit = input.limit;
        }
        if(input.tab){
            data.tab = input.tab;
        } else{
            data.tab = data.defaultTab;
        }
        if(input.selectedFiltersFromTodoPage){
            data.todosToShow = util.getMyTodos(data.queryLimit, [], input.includeTodo,undefined,undefined,input.selectedFiltersFromTodoPage.finalFilterConditions,input.selectedFiltersFromTodoPage.applyFilters,data.tab);
        } else{
            data.todosToShow = util.getMyTodos(data.queryLimit, [], input.includeTodo,undefined,undefined,undefined,undefined, data.tab);
        }

        data.watchers = data.todosToShow.recordWatchers||[];
    } else if (input && input.action == "loadFilteredTodos") {
        data.selectedFiltersFromTodoPage = util.fetchSelectedFilters(input.filtersData);
        data.onTodoPage = true;
        data.onTicketPage = false;
        data.todosToShow = util.getMyTodos(data.queryLimit, [], input.includeTodo,undefined,undefined,data.selectedFiltersFromTodoPage.finalFilterConditions,data.selectedFiltersFromTodoPage.applyFilters);
        data.watchers = data.todosToShow.recordWatchers||[];
    } else if (input && input.action == "insertOrUpdateTodoRecord") {
        var noOfRecords = Math.ceil(input.currentCount/data.queryLimit)*data.queryLimit;
        if(noOfRecords < (todoPageUtils.QUERY_LIMIT*2))
            noOfRecords = todoPageUtils.QUERY_LIMIT*2;
        data.onTodoPage = true;
        data.onTicketPage = false;
        data.newTodosList = util.getMyTodos(noOfRecords,undefined,undefined,undefined,undefined,data.selectedFiltersFromTodoPage);
    } else if (input && input.action == "loadMoreTodos") {
        data.todosToShow = util.getMyTodos(data.queryLimit,input.excludeList,undefined,undefined,undefined,input.selectedFiltersFromTodoPage.finalFilterConditions,input.selectedFiltersFromTodoPage.applyFilters);
    } else if (input && input.action == "loadFillerTodos"){
        data.fillerTodosList = util.getMyTodos(input.fillerCount, input.fillerExcludeList,undefined,undefined,undefined,data.selectedFiltersFromTodoPage.finalFilterConditions,data.selectedFiltersFromTodoPage.applyFilters);
    }

    Object.keys(data.todosToShow.recordsToShow).forEach(function(tab) {
        (data.todosToShow.recordsToShow[tab] || []).forEach(function(todo) {
            if (!todo.displayValueList) return;
            todo.displayValueList = todo.displayValueList.map(function (displayValue) {
                return GlideSecurityUtils.escapeScript(displayValue);
            });
        });
    });

    if (data.onTicketPage) {
        data.txt.empty[data.defaultTab].message = gs.getMessage('All tasks are Complete');
    }

})();
 
 
***************************************************************************************
 
Client Controller:
 
function hrmTodosSummaryController($scope, $rootScope, $sanitize, spUtil, $window, $sce, $timeout, spAriaUtil, cabrillo, i18n) {
    var c = this;
    c.loaded = {};
    c.updateTab = {};
    c.loadingMore = {};
    c.todoDisplayed = {};
    c.defaultTodoDisplayed = {};
    c.selectedTodo = {};
    c.stopLoadMore = {};
    c.isMobileLeftPanelOpen = true;
    c.limit = c.data.queryLimit - 1;
    c.mobileDevice = c.data.isMobile || ($window.innerWidth < 767);
    c.currentTab = c.data.tabs[0].name; // Sets default current Tab
    c.accessibility = spAriaUtil.isAccessibilityEnabled();
    c.currentPageTitle = $scope.page.title;
    c.filtersData = [];
    c.selectedFiltersFromTodoPage = [];
    c.navBarScrollable = false;

    var todoDetailTitle = 'To-do detail';
    var resizeTime;
    var resizeTimeout = false;
    var delta = 500;
    $window.addEventListener('resize', function(event) {
        resizeTime = new Date();
        if (resizeTimeout === false) {
            resizeTimeout = true;
            $timeout(isMobileDevice, delta);
        }

        handlePageTitleOnResize();
    });

    function handlePageTitleOnResize() {
        if (isTodoDetail() && c.currentPageTitle !== todoDetailTitle) {
            setPageTitle(todoDetailTitle);
        } else if ($window.innerWidth > 767 && !c.data.onTicketPage && c.currentPageTitle == todoDetailTitle) {
            setPageTitle($scope.page.title);
        }
    }

    function isTodoDetail() {
        return $window.innerWidth < 767 && !c.data.onTicketPage && !c.data.todoSummaryLeftPanel;
    }

    function isMobileDevice() {
        if (new Date() - resizeTime < delta) {
            $timeout(isMobileDevice, delta);
        } else {
            c.mobileDevice = c.data.isMobile || ($window.innerWidth < 767);
            resizeTimeout = false;
        }
    }

    c.getDelegatedByText = function(delegatorName) {
        return $scope.data.i18n.DELEGATED_BY.replace('{}', delegatorName);
    };

    // instead  of adding more recordWatcher, listen to change from HRM To-Dos Task Item widget
    $scope.$on('updateDelegateRecord', function($event) {
        $event.stopPropagation();
        getMyTodos();
    });

    $scope.$on('sn_ex_sp.applyFilters', function($event, data) {
        $event.stopPropagation();
        c.data.action = "loadFilteredTodos";
        c.data.filtersData = data;
        c.loadingMore[c.data.defaultTab] = true;
        c.todoDisplayed[c.data.defaultTab] = [];
        c.server.update().then(function() {
            getMyTodos();
            c.loadingMore[c.data.defaultTab] = false;
            c.filtersData = c.data.filtersData;
            c.selectedFiltersFromTodoPage = c.data.selectedFiltersFromTodoPage;
        });
    });

    function announceTodoDisplayed(todo, isTabSwitch) {
        isTabSwitch = isTabSwitch || false;
        $rootScope.$broadcast('sn_hr_sp.todoDisplayed', todo, isTabSwitch);
    }

    // get the task-line-item widget template
    function loadTodoWidget(index, finalTodoList, tab) {
        finalTodoList[index].currentIndex = index;
        finalTodoList[index].totalTodos = finalTodoList.length;

        if (finalTodoList[index].taskConfigurationSysId && finalTodoList[index].taskConfigurationSysId !== '') {
            var taskObj = {
                taskSysId: finalTodoList[index].sysId,
                taskConfigurationSysId: finalTodoList[index].taskConfigurationSysId,
                Url: finalTodoList[index].url,
                widgetSpan: 9,
                tableName: finalTodoList[index].tableName,
                tabName: finalTodoList[index].tab
            };
            return spUtil.get("task-configuration", taskObj).then(function(response) {
                finalTodoList[index].todoLineWidget = response;
                if (c.data.todoParameter && c.defaultTodoDisplayed.recordsToShow && c.defaultTodoDisplayed.recordsToShow[tab] && c.defaultTodoDisplayed.recordsToShow[tab][index]) {
                    c.defaultTodoDisplayed.recordsToShow[tab][index].todoLineWidget = response;
                }

                createApprovalWatcher(taskObj.taskSysId, taskObj.tableName);
                if (c.data.isLPActive)
                    createTaskCompletionWatcher(taskObj.taskSysId, taskObj.tableName);

                $scope.$applyAsync(function() {
                    if (tab == c.currentTab)
                        announceTodoDisplayed(finalTodoList[index]);
                });
            });
        } else {
            return spUtil.get("hrm-todos-line-item", finalTodoList[index]).then(function(response) {
                finalTodoList[index].todoLineWidget = response;
                if (c.data.todoParameter && c.defaultTodoDisplayed.recordsToShow && c.defaultTodoDisplayed.recordsToShow[tab] && c.defaultTodoDisplayed.recordsToShow[tab][index]) {
                    c.defaultTodoDisplayed.recordsToShow[tab][index].todoLineWidget = response;
                }

                createAttachmentWatcher(response.data.sysId);
                createApprovalWatcher(response.data.sysId, response.data.tableName);
                if (c.data.isLPActive)
                    createTaskCompletionWatcher(response.data.sysId, response.data.tableName);

                $scope.$applyAsync(function() {
                    if (tab == c.currentTab)
                        announceTodoDisplayed(finalTodoList[index]);
                });
            });
        }
    }

    function createTaskCompletionWatcher(taskSysId, tableName) {
        if (tableName == "sn_hr_core_task") {
            if (createTaskCompletionWatcher.watchers[taskSysId]) return;
            createTaskCompletionWatcher.watchers[taskSysId] = true;
            spUtil.recordWatch($scope, tableName, "stateIN10,18^active=true^sys_id=" + taskSysId, function(updateInfo) {
                // broadcast the sn_lp.task_completed event if the updated task have triggered conditions configured in Listening Posts
                if (updateInfo.data.action === "exit" && updateInfo.data.changes && updateInfo.data.changes.indexOf('state') != -1) {
                    c.server.get({
                        action: "addNotification",
                        taskId: updateInfo.data.sys_id,
                        table: updateInfo.data.table_name
                    }).then(function(response) {
                        response.action = undefined;
                        if (response.data.taskInfo && response.data.taskInfo.taskId && c.lastInstanceNotified !== response.data.taskInfo.taskId) {
                            c.lastInstanceNotified = response.data.taskInfo.taskId;
                            var taskInfo = {
                                taskId: response.data.taskInfo.taskId,
                                taskDescription: response.data.taskInfo.taskDescription
                            };
                            $rootScope.$broadcast("sn_lp.task_completed", taskInfo);
                        }
                    });
                }
            });
        }
    }
    createTaskCompletionWatcher.watchers = {};

    function selectTodo(finalTodoList, tab) {
        // If array position exists, open to-do
        if (finalTodoList[c.selectedTodo[tab]]) {
            finalTodoList[c.selectedTodo[tab]].isOpen = true;
            // if there's no selected to-do, open the first one
        } else if (finalTodoList.length > 0 && !c.selectedTodo[tab]) {
            if (!(c.data.onTicketPage && c.data.hideTodoSummary)) {
                //If mobile view then reload the task list
                if (c.mobileDevice)
                    c.backToTaskList();
                finalTodoList[0].isOpen = true;
                c.selectedTodo[tab] = 0;
            }
            // If array position does not exist, and not the first one, select the last to-do
        } else if (!finalTodoList[c.selectedTodo[tab]] && c.selectedTodo[tab] > 0) {
            c.selectedTodo[tab] = _.findLastIndex(finalTodoList);
        }
    }

    c.trustAsHtml = function(htmlContent) {
        return $sce.trustAsHtml($sanitize(htmlContent));
    };

    function getLeftMenuItems(todosToShow, tab, loadMore) {
        var finalTodoList = _.map(todosToShow, function(todo) {
            todo.firstLoad = true;
            todo.isOpen = false; // Default
            return todo;
        });

        c.loaded[tab] = true;

        if (!loadMore) {
            selectTodo(finalTodoList, tab);
            if (!(c.data.onTicketPage && c.data.hideTodoSummary)) {
                loadTodoWidget(c.selectedTodo[tab], finalTodoList, tab);
            }
        }

        return finalTodoList;
    }

    $scope.$on('sn_hr_sp.todoSummaryDetail', function(e, data) {
        if (data == null || data.parent != c.data.parentCaseId || !c.data.onTicketPage)
            return;
        c.data.hideTodoSummary = false;
        if (data.todoId != '')
            c.openTodo(data.todoId);
    });

    c.hasPreviousTodo = function() {
        return hasNextOrPreviousTodo(false);
    };

    c.hasNextTodo = function() {
        return hasNextOrPreviousTodo(true);
    };

    function hasNextOrPreviousTodo(next) {
        var todos, index, value;
        todos = c.todoDisplayed[c.currentTab];
        index = c.selectedTodo[c.currentTab];
        value = (next) ? index + 1 : index - 1;
        if (todos[value]) {
            return true;
        }
        return false;
    }

    function getPreviousOrNextTodo(next) {
        var todos, index, sysId, value;
        todos = c.todoDisplayed[c.currentTab];
        index = c.selectedTodo[c.currentTab];
        value = (next) ? index + 1 : index - 1;
        if (todos[value]) {
            sysId = todos[value].sysId;
        } else {
            sysId = todos[_.findLastIndex(todos)].sysId;
        }
        c.openTodo(sysId, c.currentTab);
    }

    c.getPreviousTodo = function() {
        if (c.hasPreviousTodo()) {
            return getPreviousOrNextTodo();
        }
    };

    c.getNextTodo = function() {
        return getPreviousOrNextTodo(true);
    };

    function find(sysId, tab) {
        return _.find(c.todoDisplayed[tab], {
            sysId: sysId
        });
    }

    function setOpenStatus(sysId, tab) {
        if (c.selectedTodo.hasOwnProperty(tab)) {
            c.todoDisplayed[tab][c.selectedTodo[tab]].isOpen = false;
        }
        var todo = find(sysId, tab);
        todo.isOpen = true;
        c.selectedTodo[tab] = _.findIndex(c.todoDisplayed[tab], {
            sysId: sysId
        });
    }

    function announceIsOpen(sysId, index) {
        $scope.$applyAsync(function() {
            $rootScope.$broadcast("sn_hr_sp.todoSummaryOpened", {
                parent: c.data.parentCaseId,
                todoSelected: sysId,
                currentTodoIndex: index
            });
        });
    }

    /**
     * Element el is considered in viewport when any part of the element is visible in the viewport.
     * Use offset to indicate how much of the element may be in view to consider the full element in view
     * ie. If we set offset = elem.offsetHeight then the element would be considered out of view unless
     * the entire element was visible in the view port.
     */
    function isElementInViewport(el, offset) {
        offset = offset || 0;
        var rect = el.getBoundingClientRect();
        var bottom = (window.innerHeight || document.documentElement.clientHeight) + el.offsetHeight - offset;
        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= bottom &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        );
    }

    // checks if the element is completely visible within the container
    function isElementVisible(elem, container) {
        var elemRect = elem.getBoundingClientRect();
        var containerRect = container.getBoundingClientRect();
        return (
            elemRect.top >= containerRect.top &&
            elemRect.left >= containerRect.left &&
            elemRect.bottom <= containerRect.bottom &&
            elemRect.right <= containerRect.right
        );
    }

    c.openTodo = function(sysId, tab) {
        if (c.data.onTicketPage) { // Ticket page does not use tabs
            tab = c.data.defaultTab;
        }

        $rootScope.$broadcast('sp.update.breadcrumbs', [{
            label: c.data.txt.breadcrumb,
            url: "javascript&colon;void(0)"
        }]);

        setOpenStatus(sysId, tab);
        var index = _.findIndex(c.todoDisplayed[tab], {
            sysId: sysId
        });
        c.todoDisplayed[tab][index].todoLineWidget = undefined;
        loadTodoWidget(index, c.todoDisplayed[tab], tab).then(function() {
            // scroll to the current todo if it is not completely visible in the todos list
            if (!c.mobileDevice) {
                $timeout(function() {
                    var selectedTodoElem = angular.element('#' + c.todoDisplayed[tab][index].sysId + '_task_lineitem_summary');
                    var scrollContainer = document.querySelector(".tab-content.clearfix");
                    if (typeof jQuery === "function" && selectedTodoElem instanceof jQuery) {
                        selectedTodoElem = selectedTodoElem[0];
                    }
                    if (selectedTodoElem) {
                        if (!isElementVisible(selectedTodoElem, scrollContainer)) {
                            scrollContainer.scrollBy(0, selectedTodoElem.getBoundingClientRect().top - scrollContainer.getBoundingClientRect().top);
                        }
                    }
                }, 0, false);
            }
        });

        c.data.todoSummaryLeftPanel = false;
        if (!c.data.onTicketPage && c.mobileDevice) {
            setPageTitle(todoDetailTitle);
        }

        if (c.data.onTicketPage) {
            announceIsOpen(sysId, index);
        }
    };

    c.backToTaskList = function() {
        $rootScope.$broadcast("sn_hr_sp.backToTimeline");
    };

    c.openTodosSummaryList = function() {
        if (cabrillo.isNative())
            cabrillo.viewLayout.setBottomButtons();
        if (c.data.onTicketPage) {
            c.backToTaskList();
        } else {
            c.data.todoSummaryLeftPanel = true;
            setPageTitle($scope.page.title);
        }
    };

    c.onTabClick = function(tab) {
        if (c.currentTab != tab.name) {
            c.currentTab = tab.name;
            if (c.updateTab[tab.name] || !c.todoDisplayed[tab.name] || !c.todoDisplayed[tab.name].length) {
                loadData(getMyTodos, tab);
            }
        }
    };

    function setPageTitle(prefix) {
        c.currentPageTitle = prefix;
        $(document).prop('title', prefix + ' - ' + $scope.portal.title);
    }



    function loadData(callback, tab) {
        c.data.includeTodo = c.data.todoParameter;
        c.data.action = "loadTodos";
        if (c.existingTodoLength > 10) {
            c.data.limit = c.existingTodoLength;
        }
        if (tab) {
            c.data.tab = tab.name;
            c.loaded[tab.name] = false;
            c.defaultTodoDisplayed = JSON.parse(JSON.stringify(c.data.todosToShow));
            c.defaultRecordWatchers = c.data.todosToShow.recordWatchers;
        } else {
            c.data.tab = c.currentTab;
        }
        if (c.selectedFiltersFromTodoPage.applyFilters) {
            c.data.selectedFiltersFromTodoPage = c.selectedFiltersFromTodoPage;
        }
        c.server.update().then(function(response) {
            callback();
            if (tab) {
                c.defaultTodoDisplayed.recordsToShow[tab.name] = c.data.todosToShow.recordsToShow[tab.name];
                c.defaultTodoDisplayed.recordWatchers = c.defaultTodoDisplayed.recordWatchers.concat(c.data.todosToShow.recordWatchers);
                c.data.todosToShow = c.defaultTodoDisplayed;
                c.data.watchers = c.data.todosToShow.recordWatchers;
                c.todoDisplayed = c.data.todosToShow.recordsToShow;
                c.loaded[tab.name] = true;
                c.updateTab[tab.name] = false;
            }

            if (c.data.todoParameter && c.searchLinkedTodo) {
                if (c.todoDisplayed.completed && c.todoDisplayed.completed.length < 1)
                    loadData(getMyTodos, c.data.tabs[1]);

                c.searchLinkedTodo = false;
            }
        });
    }

    function hasChanged(w, dbEventDetails) {

        var tableName = w.data.table_name || w.table_name;
        var operation = w.data.operation || w.operation;
        var changes = w.data.changes || [];
        dbEventDetails = dbEventDetails || {};
        var currentTab = c.currentTab;
        var currentTodo = c.todoDisplayed[currentTab][c.selectedTodo[currentTab]].sysId;
        var changedTodo = w.data.sys_id;

        //prevent refresh if any other todo apart from current todo has been changed in the backend
        if (currentTodo !== changedTodo && tableName != 'sys_attachment')
            return false;

        //set the record watcher for all the fields other than comments and worknotes
        if (changes.length == 1 && ((_.includes(changes, 'comments')) || _.includes(changes, 'work_notes')))
            return false;
        if (changes.length == 2 && _.includes(changes, 'comments') && _.includes(changes, 'work_notes'))
            return false;
        if (changes.length == 1 && _.includes(changes, 'state') && dbEventDetails.isTaskSurvey)
            return false;
        if (operation === 'update' && changes.length === 0) // change in relationships
            return false;
        if (tableName === 'sys_attachment' && operation === 'update' && changes.length === 0) // change in relationships
            return false;
        if (tableName === 'sys_attachment' && operation === 'update' && changes[0] === 'file_name') // attachment renaming
            return false;
        if (tableName === 'sys_attachment' && changes.length <= 2 && _.includes(['state', 'image_width', 'image_height', 'average_image_color'], changes[0])) // img feature detection
            return false;
        return true;
    }

    c.lastInstanceNotified = null;

    function update(watcher) {
        _getDbEventDetails(watcher).then(function(dbEventDetails) {
            c.isTaskSurvey = dbEventDetails.isTaskSurvey;
            // cheap sync pre-filter just in case `watcher` has enough info to skip this iteration
            if (!hasChanged(watcher, dbEventDetails))
                return;

            // only the latest change triggers the actual refresh
            clearTimeout(update.timer);
            update.timer = setTimeout(function() {
                var isLocalChange = c.data.onTicketPage || watcher.data.table_name === 'sys_attachment' || watcher.table_name === 'sys_attachment';
                if (isLocalChange) {
                    _executeSidePanelUpdate(watcher);
                } else {
                    _executeFullPageUpdate(watcher);
                }
            }, 300);
        });
    }
    update.timer = null;
    update.surveys = {};

    function _getDbEventDetails(watcher) {

        var tableName = watcher.data.table_name;
        var sysId = watcher.data.sys_id;

        if (tableName === 'sys_attachment') {
            return Promise.resolve({
                isTaskSurvey: false
            });
        }

        if (update.surveys.hasOwnProperty(sysId)) {
            return Promise.resolve({
                isTaskSurvey: update.surveys[sysId]
            });
        }

        return c.server.get({
            action: "checkTaskType",
            sysId: sysId,
            table: tableName
        }).then(function(response) {
            response.action = undefined;
            update.surveys[sysId] = response.data.isTaskSurvey;
            return Promise.resolve({
                isTaskSurvey: response.data.isTaskSurvey
            });
        });

    }

    function _executeSidePanelUpdate(watcher) {

        var selectedIndex = c.selectedTodo[c.currentTab];
        var selectedTicket = c.todoDisplayed[c.currentTab][selectedIndex];
        commitToDom(function() {
            selectedTicket.isOpen = false;
        }).then(function() {
            c.openTodo(selectedTicket.sysId, c.currentTab);
        });
    }

    function _executeFullPageUpdate(watcher) {
        c.existingTodoLength = c.todoDisplayed[c.data.tab].length;
        $rootScope.$broadcast('sp.update.breadcrumbs', [{
            label: c.data.txt.breadcrumb,
            url: "javascript&colon;void(0)"
        }]);
        _.each(c.loaded, function(value, key) {
            c.loaded[key] = false;
            c.updateTab[key] = false;
        });
        c.todoDisplayed = {};
        // If the last todo is approved, reset the selected todo to open first todo
        if (c.selectedTodo[c.data.tab] === c.existingTodoLength - 1) {
            c.selectedTodo = {};
        }
        loadData(function() {
            loadTodos();
        });
    }

    function createAttachmentWatcher(taskSysId) {
        if (createAttachmentWatcher.watchers[taskSysId]) return;
        createAttachmentWatcher.watchers[taskSysId] = true;
        spUtil.recordWatch(
            $scope,
            'sys_attachment',
            'table_sys_id=' + taskSysId,
            update
        );
    }
    createAttachmentWatcher.watchers = {};

    $rootScope.$on('list.updated', function(e, r) {
        // ignore sys_attachment to avoid unnecessary call to loadData
        if (r.table_name === 'sys_attachment' || c.data.onTicketPage)
            return;

        r.data = r;
        update(r);
    });

    function loadRecordWatchers(watchers, scope) {
        if (watchers.length > 0) {
            _.each(watchers, function(watcher) {
                spUtil.recordWatch(scope, watcher.table, watcher.filter, updateRequired);
            });
        }
    }

    function updateRequired(watcher) {
        _.each(c.data.tabs, function(tab) {
            c.updateTab[tab.name] = true;
        });
        update(watcher);
    }

    function loadWatchers() {
        loadRecordWatchers(c.data.watchers, $scope);
        if (c.mobileDevice && c.data.onTicketPage) {
            c.data.todoSummaryLeftPanel = false;
        }
    }

    function loadTodos() {
        _.each(c.data.todosToShow.recordsToShow, function(todos, tab) {
            c.todoDisplayed[tab] = getLeftMenuItems(todos, tab);
        });

        // Handle no results, and empty state
        _.each(c.data.tabs, function(tab) {
            if (!c.data.todosToShow.recordsToShow[tab.name] || (c.data.todosToShow.recordsToShow[tab.name] && c.data.todosToShow.recordsToShow[tab.name].length < 1) || !c.todoDisplayed[tab.name]) {
                c.todoDisplayed[tab.name] = [];
                c.loaded[tab.name] = true;
            } else if (c.todoDisplayed[tab.name].length > c.limit) // When the page is reloaded, show 'show more' button.
                c.stopLoadMore[tab.name] = false;
        });
    }

    function searchTodoInTab(todoSysId, tab) {
        var todosToSearch = c.todoDisplayed[tab];
        if (todosToSearch && todosToSearch.length > 0) {
            for (var i = 0; i < todosToSearch.length; i++)
                if (todosToSearch[i].sysId === todoSysId)
                    return true;
        }
        return false;
    }

    function openLinkedTodo(todoSysId) {
        if (todoSysId) {
            for (var tabIdx = 0; tabIdx < c.data.tabs.length; tabIdx++) {
                var tabName = c.data.tabs[tabIdx].name;
                if (searchTodoInTab(todoSysId, tabName)) {
                    c.currentTab = tabName;
                    c.openTodo(todoSysId, tabName);
                    return true;
                }
            }
            return false;
        }
        return false;
    }

    function getMyTodos() {
        loadWatchers();
        loadTodos();

        if (c.data.todoParameter && !c.searchLinkedTodo) {
            if (!openLinkedTodo(c.data.todoParameter)) {
                c.searchLinkedTodo = true;
            }
        }
    }

    c.processGetMoreTodos = function(tab) {
        var todosToShow = c.data.todosToShow.recordsToShow[tab];
        if (!todosToShow) {
            c.stopLoadMore[tab] = true;
        }
        var todoList = getLeftMenuItems(todosToShow, tab, true);
        c.todoDisplayed[tab] = c.todoDisplayed[tab].concat(todoList);
        if (todoList && todoList.length > 0) {
            $timeout(function() {
                $('#' + todoList[0].sysId + '_task_lineitem_summary').focus();
            }, 0);
        }
    }

    c.fetchMoreRecords = function(tab) {
        c.loadingMore[tab] = true;
        c.data.action = "loadMoreTodos";
        c.data.excludeList = _.map(c.todoDisplayed[tab], 'sysId');
        c.data.selectedFiltersFromTodoPage = c.selectedFiltersFromTodoPage;
        c.server.update().then(function() {
            c.processGetMoreTodos(tab);
            c.loadingMore[tab] = false;
        });
    };

    function commitToDom(taskFn) {
        return new Promise(function(resolve) {
            // execute the change
            taskFn();
            $timeout(function() {
                // wait 1 tick, then run a digest, then resolve, then run another digest
                $timeout(resolve);
            });
        });
    }

    // start of the server call.
    if (c.data.async && !c.data.onTicketPage) {
        loadData(getMyTodos);
    } else {
        getMyTodos();
    }

    /**  Making tabs accessible **/

    $scope.$applyAsync(function() {
        new Tab("todo-panel");
    });

    function Tab(id) {
        this._id = id;
        this.$tpanel = $('#' + id);
        this.$tabs = this.$tpanel.find('.tab');
        this.$panels = this.$tpanel.find('.tab-pane');
        this.$navTabs = this.$tpanel.find('.nav.nav-tabs');
        this.bindHandlers();
        this.init();
    }

    createApprovalWatcher.watchers = {};

    function createApprovalWatcher(sysId, tableName) {
        if (!tableName) {
            tableName = 'sysapproval_approver';
        }
        if (createApprovalWatcher.watchers[sysId]) return;
        createApprovalWatcher.watchers[sysId] = true;
        spUtil.recordWatch(
            $scope,
            tableName,
            'sys_id=' + sysId,
            update
        );
    }

    Tab.prototype.keys = {
        left: 37,
        right: 39
    };
    Tab.prototype.init = function() {
        if (this.$navTabs && this.$navTabs[0] && (this.$navTabs[0].clientWidth < this.$navTabs[0].scrollWidth)) {
            c.navBarScrollable = true;
        }
        var $tab = this.$tabs.filter('.active');
        this.$tpanel.find('#' + $tab.find('a').attr('aria-controls')).addClass('active in').attr('aria-hidden', 'false');
    };
    Tab.prototype.switchTabs = function($curTab, $newTab) {
        if ($curTab[0] === $newTab[0])
            return;

        var $curLink = $curTab.find('a'),
            $newLink = $newTab.find('a');
        c.currentTab = $newLink.attr('aria-controls');
        var newTodoIndex = c.selectedTodo[c.currentTab];
        if (!c.mobileDevice) {
            if (newTodoIndex != undefined && c.todoDisplayed[c.currentTab][newTodoIndex] && c.todoDisplayed[c.currentTab][newTodoIndex].sysId)
                c.openTodo(c.todoDisplayed[c.currentTab][newTodoIndex].sysId, c.currentTab);
            if (c.data.todosToShow && c.data.todosToShow.recordsToShow && c.data.todosToShow.recordsToShow[c.currentTab] && c.data.todosToShow.recordsToShow[c.currentTab][newTodoIndex])
                announceTodoDisplayed(c.data.todosToShow.recordsToShow[c.currentTab][newTodoIndex], true);
        }

        $newTab.addClass('active');
        $newLink.attr('aria-selected', 'true');
        this.$tpanel.find('#' + $curLink.attr('aria-controls')).removeClass('active in').attr('aria-hidden', 'true');
        this.$tpanel.find('#' + $curLink.attr('aria-controls') + "-content").removeClass('active in').attr('aria-hidden', 'true');
        this.$tpanel.find('#' + $newLink.attr('aria-controls')).addClass('active in').attr('aria-hidden', 'false');
        this.$tpanel.find('#' + $newLink.attr('aria-controls') + "-content").addClass('active in').attr('aria-hidden', 'false');
        $newLink.attr('tabindex', '0');
        $newLink.focus();
    };
    Tab.prototype.bindHandlers = function() {
        var self = this;
        this.$tabs.keydown(function(e) {
            return self.handleTabKeyDown($(this), e);
        });
        this.$tabs.click(function(e) {
            return self.handleTabClick($(this), e);
        });
    };
    Tab.prototype.moveToPreviousOrNext = function(e, $tab, next) {
        var $newTab, tabIndex;
        tabIndex = this.$tabs.index($tab);
        var index = (next) ? this.$tabs.length - 1 : 0;
        if (tabIndex === index) {
            $newTab = (next) ? this.$tabs.first() : this.$tabs.last();
        } else {
            var newIndex = (next) ? tabIndex + 1 : tabIndex - 1;
            $newTab = this.$tabs.eq(newIndex);
        }
        this.switchTabs($tab, $newTab);
        e.preventDefault();
        return false;
    };
    Tab.prototype.handleTabKeyDown = function($tab, e) {
        $tab.click();
        if (e.keyCode == this.keys.left) {
            this.moveToPreviousOrNext(e, $tab);
        } else if (e.keyCode == this.keys.right) {
            this.moveToPreviousOrNext(e, $tab, true);
        }
    };
    Tab.prototype.handleTabClick = function($tab, e) {
        var $oldTab = this.$tpanel.find('.tab.active');
        this.switchTabs($oldTab, $tab);
    };
    /**  Making tabs accessible **/
    $scope.isSignPadVisible = false;
    $scope.$on('mobile-showSignPad', function(event, args) {
        $scope.isSignPadVisible = !$scope.isSignPadVisible;
    });

    $scope.showSignPad = function() {
        $rootScope.$broadcast('mobile-showSignPad');
    };

    $scope.backToListKeyDown = function(event) {
        if (event.keyCode == 13 || event.keyCode == 32)
            c.backToTaskList();
    }

    $scope.$on('sn_hr_sp.summaryCountUpdate', function(event, data) {

        if (data.summaryCounts && data.summaryCounts.recordsToShow.length > 0) {

            c.data.todosToShow.recordsToShow.open = [];
            c.data.todosToShow.recordsToShow.open = data.summaryCounts.recordsToShow.map(function(record) {
                return Object.assign({}, {
                    sysId: record.summaryData.recordInfo.sys_id
                }, record.summaryData);
            });

            c.data.activitySetName = data.summaryCounts.activitySetName;
            c.data.activitySetAriaLabel = i18n.format(c.data.txt.backToAriaLabel, c.data.activitySetName);
            c.data.activitySetId = data.summaryCounts.activitySetId;
            c.data.hideTodoSummary = data.summaryCounts.hideTodoSummary;
            c.data.todosToShow.recordWatchers = data.summaryCounts.recordWatchers;
            c.data.watchers = c.data.todosToShow.recordWatchers || [];
            c.data.onTodoPage = false;
            c.data.onTicketPage = true;
            c.data.parentCaseId = data.summaryCounts.parent;
            c.data.selectedTodo = data.summaryCounts.todoSelected;
            c.data.currentTodoIndex = (c.data.todosToShow.recordsToShow[c.data.defaultTab] && c.data.todosToShow.recordsToShow[c.data.defaultTab].length > data.summaryCounts.currentTodoIndex) ? data.summaryCounts.currentTodoIndex : 0;

            //To initiate reading data again and make the UI
            loadTodos();
        } else {
            c.backToTaskList();
        }
        $rootScope.targetLength = data.summaryCounts.recordsToShow.length;
    })
}

@Pooja Magadum 

I believe you can use some AI tool to get the code and might be some minor change is required there

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader