Punith1
ServiceNow Employee

Learn how to configure field-level editability rules in the Project Workspace grid using ProjectWorkspaceColumnCriteriaSNC script.


DISCLAIMER: This article describes a proposed solution to support this use case. The proposed solution requires configuration; as such, there is no liability for ServiceNow to provide support, apply changes, fix defects, or review impact during future upgrades.

 

What problem does this solve?

Project managers often need field-level control over which grid columns are editable — and under what conditions. For example:

  • Closed tasks — certain fields should be disabled.
  • Only the assignee’s manager should be able to change the assignment.
  • Priority should be disabled once a task becomes inactive.

Traditional ACLs work on forms, but the Project Workspace grid uses a client-side DataGrid. Out-of-box, there is no built-in way to conditionally disable individual columns per row.

Starting with the Project Workspace 7.1.0 release, the ProjectWorkspaceColumnCriteriaSNC script include provides an override point to define column-level editability rules — effectively giving you field-level ACL behavior inside the grid.

 

Prerequisites

  • ServiceNow Zurich or later.
  • Project Workspace 7.1.0 (sn_pw) plugin activated.
  • Admin or scoped-app developer access.

How it works

  1. The platform ships a base script include: ProjectWorkspaceColumnCriteriaSNC.
  2. You create (or update) the extension point: ProjectWorkspaceColumnCriteria — which overrides the getConfig(table) method.
  3. The grid reads your config, fetches any required hidden fields, and disables editing client-side for cells that match your criteria.

Key concept: The criteria you define specifies when a cell should be disabled (not when it should be enabled).

 

Supported operators

Operator

Meaning

=

Equals

!=

Not equals

IN

Value in comma-separated list

ISEMPTY

Field is empty

ISNOTEMPTY

Field is not empty

> >= < <=

Numeric / date comparisons

Multiple conditions can be chained with ^ (AND).

 

Solution

 

Step 1- Create the Script Include

Navigate to System Definition > Script Includes and create:

Field

Value

Name

ProjectWorkspaceColumnCriteria

API Name

sn_pw.ProjectWorkspaceColumnCriteria

Application

Project Workspace

Accessible from

This application scope only

 

Step 2 - Override getConfig() with your rules

Below are practical examples. Select the examples relevant to your use case and add them to your getConfig() method.

 

Base template

    var ProjectWorkspaceColumnCriteria = Class.create();
    ProjectWorkspaceColumnCriteria.prototype = Object.extendsObject(ProjectWorkspaceColumnCriteriaSNC, {
    getConfig: function(table) {
        var config = {};
        if (table === 'pm_project_task') {
            // Add your rules here (see examples below)
         }
        return config;
    },
    type: 'ProjectWorkspaceColumnCriteria'
});

 

Example 1- Disable a field when a task is closed

Scenario: Prevent users from changing the Start Date on closed tasks.

config['start_date'] = {
    criteria: 'state=3',
    requiredFields: ['state']
};

state=3 means “Closed”. The cell becomes disabled when the task’s state is 3.

 

Example 2 - Disable a field for multiple states

Scenario: Disable End Date when the task is Closed ( 3), Cancelled ( 4), or Pending (-5).

config['end_date'] = {
    criteria: 'stateIN3,4,-5',
    requiredFields: ['state']
};

The IN operator matches any value in the comma-separated list.

 

Example 3 — Disable a field when another field is empty

Scenario: Disable editing Short Description until someone is assigned.

config['short_description'] = {
    criteria: 'assigned_toISEMPTY',
    requiredFields: ['assigned_to']
};

ISEMPTY disables the cell when assigned_to has no value.

 

Example 4 - Disable a field based on a boolean

Scenario: Disable Priority on inactive tasks.

config['priority'] = {
    criteria: 'active=false',
    requiredFields: ['active']
};

 

Example 5 - Dot-walk: disable based on assignee’s manager

Scenario: Only the assignee’s manager should be able to change the Assigned To field. For everyone else, it should be disabled.

var currentUserId = gs.getUserID();
config['assigned_to'] = {
    criteria: 'assigned_to.manager!=' + currentUserId,
    requiredFields: ['assigned_to.manager']
};

How it works: The criteria walk from assigned_to to manager and compares it to the logged-in user. If the current user is not the manager, the cell is disabled.

Important: Dot-walked fields must appear in requiredFields so the grid fetches them as hidden columns.

 

Example 6 - Dot-walk: disable based on assignee’s department

Scenario: Disable Work Notes unless the assignee belongs to the IT department (sys_id = abc123...).

config['work_notes'] = {
    criteria: 'assigned_to.department!=abc123def456',
    requiredFields: ['assigned_to.department']
};

Replace abc123def456 with the actual sys_id of the department record.

 

Combining multiple rules

You can define rules for as many columns as needed — just add more keys to config:

if (table === 'pm_project_task') {
    config['start_date'] = {
        criteria: 'state=3',
        requiredFields: ['state']
    };
    config['end_date'] = {
        criteria: 'stateIN3,4,-5',
        requiredFields: ['state']
    };
    config['priority'] = {
        criteria: 'active=false',
        requiredFields: ['active']
    };
}

Each column gets its own independent criteria. The grid evaluates them per row.

 

Step 3 - Verify

  1. Open a project in Project Workspace.
  2. Navigate to the Planning tab (grid view).
  3. Try to inline-edit a field on a row that matches your criteria — the cell should be disabled.
  4. Confirm that rows not matching the criteria remain editable.

Quick reference

Use case

Criteria string

requiredFields

Disable when Closed

state=3

['state']

Disable when inactive

active=false

['active']

Disable for multiple states

stateIN3,4,-5

['state']

Disable if no assignee

assigned_toISEMPTY

['assigned_to']

Disable based on manager (dot-walk)

assigned_to.manager!=<userId>

['assigned_to.manager']

Disable based on department (dot-walk)

assigned_to.department!=<sysId>

['assigned_to.department']

 

Important notes

  • Criteria = disable condition. Define when the cell should be disabled, not when it should be allowed.
  • Dot-walked fields must be listed in requiredFields so the grid fetches them as hidden columns.
  • Dynamic values (like current user) must be resolved server-side in getConfig() using gs.getUserID(), gs.getUser().getRecord(), etc.
  • This does not replace server-side ACLs. It provides client-side grid enforcement as a complement to ACLs.
2 Comments
enired
Tera Contributor

Hi @Punith1 ,

Thanks for the information. Given that all the examples look related to Projects/Project Tasks, does this also work on the Resource Assignment Grid? 

Thanks!

jlepon
Tera Explorer

Hi @Punith1,

 

I believe there may be a bug in ProjectWorkspaceResourceGridSNC - unless custom editability is not supported for Resource Assignment grid as per @enired .

 

The function ProjectWorkspaceResourceGridSNC.getColumns() overwrites the retrieved column configuration via the following mechanism:

 

getColumns: function(table, projectClass) {
    ...
    // pwsApi brings in custom column configuration which this article is about via ProjectWorkspaceColumns._applyCustomColumnCriteria()
    var pwsApi = new ProjectWorkspaceColumns();
    ...
    // reqColsObjs objects initially have the custom configurations via the following mechanism:
    // pwsApi.getNowPlannerColumnObjects i.e.  ProjectWorkspaceColumns.getNowPlannerColumnObjects() > 
    // ProjectWorkspaceColumns._createColumnObject > 
    // ProjectWorkspaceColumns._setEditableToColumn > 
    // ProjectWorkspaceColumns._applyCustomColumnCriteria > 
    // this.columnCriteriaConfig[tableName] = this.columnCriteria.getConfig(tableName); > 
    // columnCriteria = new ProjectWorkspaceColumnCriteria
    var reqColsObjs = pwsApi.getNowPlannerColumnObjects(reqCols, table, true, false);

    // resourceGridColumns contains all your Resource Assignment Grid Columns - including the ones you defined custom configurations for
    var resourceGridColumns = layOutColumnObjs.concat(reqColsObjs);

    // However, the custom column configurations get wiped out by addColumnProperties, see below
    this.addColumnProperties(resourceGridColumns, planningAttributes);
    return resourceGridColumns;
}

addColumnProperties: function(resourceGridColumns, dependecyColumns, dependentColumn = "resource") {
    // This will loop through all columns - including the ones where custom criteria has been defined
    for (let column of resourceGridColumns) {
        if (column['name'] == 'resource_status') {
          ...        
        } else if (column['name'] == 'effort) {
          ...        
        } else if (column['name'] == 'resource_rate') {
          ...        
        }
        // Other than the 3 columns above which have explicitly defined conditions, all other columns' criteria will be changed to this default, this includes columns with custom configurations - essentially wiping them out:
        else {
            column['criteria'] = 'parent.length>0';
        }
        ...
    }
}

 

Current workaround I found is editing the function addColumnProperties() in class extension ProjectWorkspaceResourceGrid and injecting my custom criteria & requiredFields here instead of in ProjectWorkspaceColumnCriteriaSNC. Not sure if this was intentional or Resource Assignment Grid is not yet supported. In any case, ProjectWorkspaceColumnCriteriaSNC is not working for Resource Assignment Grid Column Configuration unless this has been patmy instance isn't up to date.