Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

Restrict field edit on Project Workspace Planning console

ShaidaC
Mega Sage

 

Hi Everyone,

I have a requirement in Project Workspace Planning Console where I need to restrict editing of a field based on certain validations. Since the Planning Console grid is not the usual UI, I understand that field level ACLs don't work in the Planning grid. I also tried using an onChange Client Script, but it doesn't seem to trigger when the field is edited from the Planning Console.

As a last option, I tried handling the validation through a Business Rule. The validation itself works fine and I can display an error message and abort the update but the Planning Console still shows the newly entered value. The old value is retained in the database, but the user continues to see the changed value until they manually refresh the page.

I'm wondering if there is a way to handle this from the server side so that when the Business Rule aborts the update, the Planning Console also refreshes the value to what is actually saved in the database.

This is the Business Rule I'm currently using:

(function executeRule(current, previous /*null when async*/) {

    gs.addInfoMessage('date check business rule is running');

    var gr = new GlideRecord('project_change_request');
    gr.addQuery('parent', current.parent);
    gr.addQuery('state', 2);
    gr.query();

    if (gr.next()) {
        return;
    } else {

        gs.addErrorMessage(
            'Changes in Planned End Date require a Project Change Request'
        );

        current.setAbortAction(true);
action.setRedirectURL(current); } })(current, previous);
5 REPLIES 5

boteeuwen
Kilo Sage
Hi,
You have hit a very common and frustrating limitation with the modern Project Workspace Planning Console. Because the new console is built on the Next Experience Framework and relies entirely on client-side state management, using current.setAbortAction(true) in a traditional Business Rule only stops the transaction at the database level. It does not send a rollback event back to the Workspace UI grid component, leaving the user with an out-of-sync display until a hard refresh.
Additionally, standard Client Scripts and ACLs do not execute inside this specific grid interface.
To handle this properly, you have two choices: a quick script fix to trick the UI into reverting, or the official ServiceNow solution that disables the field entirely based on your server criteria.

The ideal approach is to prevent the user from editing the cell in the first place. ServiceNow explicitly built a dedicated Extension Point and Script Include pattern called ProjectWorkspaceColumnCriteria specifically to handle field-level read-only logic in the modern Project Workspace grid.

This framework allows you to define server-side queries that determine when a column should be disabled (locked) in the UI before a user can even type into it.

  1. Create a new Script Include in the Project Workspace scope named exactly ProjectWorkspaceColumnCriteria (API Name: sn_pw.ProjectWorkspaceColumnCriteria).
  2. Set Accessible from to This application scope only.
  3. Use the following code template:
javascript
var ProjectWorkspaceColumnCriteria = Class.create();
ProjectWorkspaceColumnCriteria.prototype = Object.extendsObject(sn_pw.ProjectWorkspaceColumnCriteriaSNC, {
    
    getConfig: function(table) {
        var config = {};
        
        // Apply this logic specifically to your project/project task tables
        if (table === 'pm_project_task' || table === 'pm_project') {
            
            config['end_date'] = {
                // Define the query condition that DISABLES editing.
                // This condition locks the cell if a matching Change Request does NOT exist.
                // Adjust the relationship string below to match your actual schema.
                criteria: 'parent.ref_project_change_request.state!=2', 
                
                // Forces the UI grid engine to pre-fetch the parent ID to evaluate the dot-walk
                requiredFields: ['parent'] 
            };
        }
        
        return config;
    },

    type: 'ProjectWorkspaceColumnCriteria'});
 

FYI: you just need to make sure your dot-walked criteria string matches your data structure. 

 

 

 

Hi @boteeuwen ,

Thank you for the detailed explanation. Based on your suggestion, I was able to locate the ProjectWorkspaceColumnCriteria Script Include in my instance.

I have a couple of questions regarding the implementation:

1. I can see the Script Include in my instance, so I wanted to understand why we need to create a new custom Script Include with the same name instead of modifying/extending the existing OOB implementation.

2. For now, I have added the following logic to the existing ProjectWorkspaceColumnCriteria Script Include which doesn't seem to work

getConfig: function(table) {

    var config = {};

    if (table === 'pm_project_task') {

        config['end_date'] = {
            criteria: 'parent.u_has_wip_project_change_request=no',
            requiredFields: ['parent.u_has_wip_project_change_request']
        };
    }

    return config;
},

On the pm_project table, I have a custom Yes/No field called u_has_wip_project_change_request. This field indicates whether there is currently a WIP Project Change Request for the project. I found the guidance in the Script Include that specifically provides an example of using a dot-walked field:

config['assigned_to'] = {
    criteria: 'assigned_to.manager!=' + currentUserId,
    requiredFields: ['assigned_to.manager']
};

Based on this example, it appears that dot-walking is supported by the column criteria framework. Not sure why my code doesn't work

 

 

Thanks in advance for your guidance.

Hi ShaidaC,

You can also adjust the OOB Script Include directly if that is your preference and your instance allows it. The main issue here does not seem to be where the code is placed, but how the requiredFields value and the criteria are configured.

For requiredFields, try using only parent instead of the full dot walked field. The framework can still evaluate parent.u_has_wip_project_change_request in the criteria, but requiredFields should only contain the top level field from the current table.

For the criteria itself, I would also check the actual backend value of u_has_wip_project_change_request. If it is a True or False field, the value for No will normally be false. In that case you can use parent.u_has_wip_project_change_request=false. If it is a Choice field and the stored value for No is actually no, then you can keep parent.u_has_wip_project_change_request=no.

So the main change I would try first is keeping the dot walking in the criteria, but changing requiredFields to just parent. Then verify the stored value of the custom field in the dictionary.

Hi,

I changed the requiredFields parameter to just parent and no it still doesn't work. And since the custom field is of choice type so the backend value used is correct

 

getConfig: function(table) {

    var config = {};

    if (table === 'pm_project_task') {

        config['end_date'] = {
            criteria: 'parent.u_has_wip_project_change_request=no',
            requiredFields: ['parent']
        };
    }

    return config;
},