The Zurich release has arrived! Interested in new features and functionalities? Click here for more

UI Message in Workspace List View Appears on Next Transaction Instead of Current

Sruthi2512
Tera Contributor

Hi All,

I have an existing functionality in classic UI which displays a UI message in list view when there are restricted records that an itil user should not see.

Problem:
In classic UI, it is working fine.

Sruthi2512_2-1756577689067.png

 


In workspace list view I am facing the below issue:


If I open Incident > Assigned to me list (which has restricted records), the restriction UI message does not show immediately. But when I switch to another list tab (e.g., Incident > Opened by me, which has no restriction), the restriction message from the previous list pops up.

It seems like the message is always getting displayed on the next transaction/tab click, instead of the current list I am viewing.

The scripts that I have used,

 

  • Script Include: c_RestrictedUtils (non-client callable)

    var c_RestrictedUtils = Class.create();
    c_RestrictedUtils.prototype = {
        initialize: function() {
            this.groupNamesToContact = '';
            this.isSingleRecord = false;
            this.amountRestricted = 0;
            this.allRecordsRestricted = false;
        },
    
        hasRestrictions: function(grListOrRecord, queryRP) {
            var showMessage = false;
            var isGroupedList = false;
            var listAmount = 0;
            var listQuery = '';
            var tableName = '';
            this.groupNamesToContact = ': ';
    
            if (typeof grListOrRecord == 'object' && typeof queryRP == 'object' && gs.getUser().hasRole('itil')) {
                isGroupedList = (grListOrRecord.getRowNumber() == -1);
                tableName = grListOrRecord.getTableName();
                listAmount = grListOrRecord.getRowCount(); // either the record amount or the grouped amount
    
                if (queryRP != null) { // only for Lists, null for Forms
                    listQuery = queryRP.toString();
                }
    
                switch (true) {
                    case (listAmount == 0):
                        // no additional actions (not sure when it happens, yet saw it while logging)
                        showMessage = false;
                        break;
    
                    case (listAmount == 1 && !isGroupedList):
                        // non grouped list with one record or form of the record
                        this.isSingleRecord = true;
                        showMessage = this._checkCanReadOneRecord(grListOrRecord);
                        break;
    
                    case (listAmount > 1 && !isGroupedList):
                        if (this._checkAccess(listAmount)) {
                            // 100 or less loop through records to determine access
                            showMessage = this._checkCanReadMultipleRecords(tableName, listQuery);
                            this.allRecordsRestricted = (listAmount == this.amountRestricted);
                        }
                        break;
    
                    case (isGroupedList):
                        // list is grouped, we need to get actual amount of records, not just amount of groupings
                        // as all task tables have more than 100 records => only check when list is filtered by user
                        listQuery = this._cleanQuery(listQuery); // remove order & group by from query
                        if (listQuery != '') { // list has a query => check record amount
                            recordAmount = this._getRealAmount(tableName, listQuery);
                            if (this._checkAccess(recordAmount)) {
                                // 100 or less loop through records to determine access
                                showMessage = this._checkCanReadMultipleRecords(tableName, listQuery);
                                this.allRecordsRestricted = (recordAmount == this.amountRestricted);
                            }
                        }
                        break;
    
                    default:
                        // unforeseen scenario's
                        showMessage = false;
                }
            }
            return showMessage;
        },
    
        bannerMessage: function() {
            var msgParameters = [];
            this.groupNamesToContact = this.groupNamesToContact.replace(": , ", ": "); // remove comma after colon
            msgParameters.push(this.groupNamesToContact);
            msgParameters.push(this.amountRestricted.toString());
    
            var returnMessage = '';
            switch (true) {
                case (this.isSingleRecord):
                    returnMessage = gs.getMessage('ui_action_restricted_ticket_message_single', msgParameters);
                    break;
                case (this.allRecordsRestricted):
                    returnMessage = gs.getMessage('ui_action_restricted_ticket_message_multiple_all', msgParameters);
                    break;
                default:
                    returnMessage = gs.getMessage('ui_action_restricted_ticket_message_multiple', msgParameters);
            }
            return returnMessage;
        },
    
        _checkCanReadOneRecord: function(grTicket) {
            var isRestricted = false;
            var grpName = grTicket.assignment_group.getDisplayValue();
    
            if (!grTicket.canRead()) {
                isRestricted = true;
                this.isSingleRecord = true;
                this.groupNamesToContact += grpName;
            }
            return isRestricted;
        },
    
        _checkCanReadMultipleRecords: function(tableName, encodedQuery) {
            var hasRestricted = false;
            var grRecords = new GlideRecord(tableName);
            grRecords.addEncodedQuery(encodedQuery);
            grRecords.query();
    
            while (grRecords.next()) {
                if (!grRecords.canRead()) {
                    // record not visible, store group name when not already stored
                    this.amountRestricted++;
                    var grpName = grRecords.assignment_group.getDisplayValue();
                    if (!this.groupNamesToContact.includes(grpName)) {
                        this.groupNamesToContact += ', ' + grpName;
                    }
                }
            }
            hasRestricted = (this.amountRestricted != 0);
            return hasRestricted;
        },
    
        _getRealAmount: function(tableName, encodedListQuery) {
            var recordCount = 0;
            gaRecords = new GlideAggregate(tableName);
            gaRecords.addAggregate('COUNT');
            gaRecords.addEncodedQuery(encodedListQuery);
            gaRecords.query();
    
            if (gaRecords.next()) {
                recordCount = gaRecords.getAggregate('COUNT');
            }
            return recordCount;
        },
    
        _cleanQuery: function(queryString) {
            var qry = '';
            if (queryString) {
                qry = queryString;
    
                if (qry.includes('^ORDERBY')) {
                    qry = qry.substring(0, qry.indexOf('^ORDERBY'));
                }
                if (qry.includes('ORDERBY')) {
                    qry = qry.substring(0, qry.indexOf('ORDERBY'));
                }
                if (qry.includes('^GROUPBY')) {
                    qry = qry.substring(0, qry.indexOf('^GROUPBY'));
                }
                if (qry.includes('GROUPBY')) {
                    qry = qry.substring(0, qry.indexOf('GROUPBY'));
                }
            }
            return qry;
        },
    
        _checkAccess: function(amount) {
            var continueCheck = false;
            if (amount) {
                switch (true) {
                    case (amount == 0): // no results in list, no need to check
                        continueCheck = false;
                        break;
    
                    case (amount == 1): // to have proper message
                        this.isSingleRecord = true;
                        continueCheck = true;
                        break;
    
                    case (amount <= 100):
                        this.isSingleRecord = false;
                        continueCheck = true;
                        break;
    
                    default:
                        // no action needed
                }
            }
            return continueCheck;
        },
    
        type: 'c_RestrictedUtils'
    };
  • Called from a UI Action with condition:

var msgUtil = new c_RestrictedUtils();
if (!RP.isRelatedList() && RP.isInteractive() && msgUtil.hasRestrictions(current ,RP.getEncodedQuery()) && gs.getUser().hasRole('itil')) {
    var msg = msgUtil.bannerMessage();
    gs.addInfoMessage(msg);
}

Sruthi2512_1-1756576650814.png

 

This works as expected in classic UI.

Now I am trying to replicate the same functionality in CSM Workspace.

  • I created a wrapper Script Include: RestrictedUtilsDLA (non-client callable), which calls the same logic of c_RestrictedUtils and url check

    var RestrictedUtilsDLA = Class.create();
    RestrictedUtilsDLA.prototype = {
        initialize: function() {
            // No initialization needed for now
        },
    
        evaluateRestriction: function(current) {
            // Only run restriction logic for interactive user sessions
            if (!gs.getSession().isInteractive()) {
                gs.info('RestrictedUtilsDLA: Non-interactive session, skipping restriction.');
                // return false;
            }
    
            // Clear leftover messages from previous transaction
            gs.clearInfoMessages();
            var transaction = GlideTransaction.get();
            var referer = '';
    
            // Attempt to get Referer header from current request
            if (transaction && transaction.getRequest()) {
                referer = transaction.getRequest().getHeader('Referer') || '';
                gs.info('RestrictedUtilsDLA: Current transaction referer header: ' + referer);
    
                // Store Referer header in session for consistency across requests
                gs.getSession().putProperty('referer', referer);
            } else {
                // Fallback: retrieve Referer header from session property if current request unavailable
                referer = gs.getSession().getProperty('referer') || '';
                gs.info('RestrictedUtilsDLA: Retrieved referer from session property: ' + referer);
            }
    
            // Extract list_id from the Referer URL
            var listIdMatch = referer.match(/list-id\/([a-z0-9]+)/i);
            var list_id = listIdMatch ? listIdMatch[1] : '';
    
            if (!list_id) {
                gs.info('RestrictedUtilsDLA: No list_id found in referer.');
                return false;
            }
    
            var grList = new GlideRecord('sys_ux_list');
            if (!grList.get(list_id)) {
                gs.info('RestrictedUtilsDLA: sys_ux_list record not found for list_id: ' + list_id);
                return false;
            }
    
            var listTable = grList.getValue('table');
            gs.info("RestrictedUtilsDLA: list ID : " + list_id + " | table : " + listTable);
    
            if (listTable !== current.getTableName()) {
                gs.info(
                    'RestrictedUtilsDLA: List table "' + listTable +
                    '" does not match current table "' + current.getTableName() + '", skipping restriction.'
                );
                return false;
            }
    
            var encodedCondition = grList.getValue('condition') || '';
            gs.info('RestrictedUtilsDLA: List encoded condition: ' + encodedCondition);
    
            var grCheck = new GlideRecord(listTable);
            if (encodedCondition) {
                grCheck.addEncodedQuery(encodedCondition);
            }
            grCheck.query();
    
            // Create fresh util instance per evaluation to prevent stale state
            var util = new c_RestrictedUtils();
            util.groupNamesToContact = '';
            util.isSingleRecord = false;
            util.amountRestricted = 0;
            util.allRecordsRestricted = false;
    
            var restricted = util.hasRestrictions(grCheck, encodedCondition);
            gs.info('RestrictedUtilsDLA: hasRestrictions result: ' + restricted);
    
            if (restricted && gs.getUser().hasRole('itil')) {
                var bannerMsg = util.bannerMessage();
                gs.info('RestrictedUtilsDLA: Adding banner message: ' + bannerMsg);
                gs.addInfoMessage('[BR_TABLE:' + current.getTableName() + '] ' + bannerMsg);
                return true;
            }
    
            return false;
        },
    
        type: 'RestrictedUtilsDLA'
    };
  • Added a Declarative Action – List Action [Name: error_message] in Workspace.

  • In the Advanced condition script of the Declarative Action, I added:

new global.RestrictedUtilsDLA().evaluateRestriction(current) && false;

Sruthi2512_0-1756576565981.png

 

With this setup, the UI message does appear, but the issue is that the response is delayed.

Problem:
If I open Incident > Assigned to me list (which has restricted records), the restriction UI message does not show immediately. But when I switch to another list tab (e.g., Incident > Opened by me, which has no restriction), the restriction message from the previous list pops up.

It seems like the message is always getting displayed on the next transaction/tab click, instead of the current list I am viewing.


Has anyone faced this delayed UI message issue in Workspace declarative actions?
Is there a way to make the restriction message display immediately for the current list transaction?

Any suggestions are appreciated.

Thanks in advance!

 

0 REPLIES 0