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