Some PDIs are currently unavailable, and PDI actions are paused. View the latest updates here. Read More

Make Record Producer variables editable on the ESC "My Submission" tab based on record State

Leonie1
Kilo Expert

What I'm trying to do

On the Employee Center (ESC) ticket page — /esc?id=ticket&table=incident&sys_id=<sys_id> — the "My Submission" tab shows the Record Producer variables read-only (standard OOB behavior of the Standard Ticket framework).

My requirement is:

  1. Make those variables editable only when the target record State = New (1).
  2. On Save, update both:
    • the Record Producer variable answers (question_answer), and
    • the mapped fields on the target record (e.g. incident.urgency, incident.short_description).
  3. In any other state, keep everything read-only, exactly like OOB.

Constraint: the business does not want new ACLs, UI Policies, or Client Scripts — editability should be driven by record state on the server.


What I've built so far (and it's working in DEV)

I avoided touching OOB widgets. Instead I cloned two widgets:

  1. Cloned std_ticket_tab → in the variable_editor case, I branch on state and load either my editable clone or the OOB read-only widget:

    case 'variable_editor':
    case 'variable_summary':
    if (record.variables.getElements(true).length == 0)
    return;
    var widgetParams = tabConfig.widget_param ? JSON.parse(tabConfig.widget_param) : {};
    widgetParams.table = data.table;
    widgetParams.sys_id = data.sys_id;

    if (record.getValue('state') == 1) { // New -> editable
    widgetParams.readonly_variable_editor = 'false';
    tab.widgetId = 'iris-sp-variable-editor';
    } else { // other states -> OOB read-only
    tab.widgetId = tabConfig.widget;
    }
    tab.widgetParams = widgetParams;
    break;

 
  1. Cloned the OOB SC variable editor (custom-sp-variable-editor). In the GET branch I drive read-only from state and set the flag explicitly on each field:

    var editableByState = (gr.isValidField('state') && gr.getValue('state') == 1);
    var isQuestionReadOnly = (options.readonly_variable_editor == 'true') || !editableByState;

    for (var f in data.sc_cat_item._fields) {
    data.sc_cat_item._fields[f].sys_readonly = isQuestionReadOnly;
    data.sc_cat_item._fields[f].readonly = isQuestionReadOnly;
    // ...OOB value population unchanged
    }

 

And in the SAVE (input) branch I keep $sp.saveVariables() and add a second write to the mapped target fields, using the declarative mapping on item_option_new (map_to_field = true, field):

 

// after $sp.saveVariables(input.table, input.sys_id, vars);
var producerId = (input.sc_cat_item && input.sc_cat_item.sys_id)
? input.sc_cat_item.sys_id
: getProducerId(input.table, input.sys_id); // sc_item_produced_record.record_key -> producer
syncMappedFields(input.table, input.sys_id, producerId, fields);

function syncMappedFields(table, sysId, producerId, fields) {
if (!producerId || !fields) return;
var target = new GlideRecord(table);
if (!target.get(sysId) || !target.canWrite()) return;
if (target.isValidField('state') && target.getValue('state') != '1') return; // safeguard

var io = new GlideRecord('item_option_new');
io.addQuery('cat_item', producerId);
io.addQuery('map_to_field', true);
io.query();
var changed = false;
while (io.next()) {
var vName = io.getValue('name');
var col = io.getValue('field');
if (!col || !target.isValidField(col)) continue;
if (fields[vName] && typeof fields[vName].value != 'undefined') {
target.setValue(col, fields[vName].value);
changed = true;
}
}
if (changed) target.update();
}

 

 

 

Two things that tripped me up and are now fixed:

  • The tab reuses the OOB widget_param, which carries readonly_variable_editor: "true" — so I had to override it to 'false' in the New branch (otherwise fields stay read-only and the Save button is hidden).
  • The OOB loop only ever set sys_readonly = true and never cleared it, and $sp.getCatalogItem() returns fields pre-flagged read-only — so I had to set the boolean explicitly.

My questions

  1. Is cloning std_ticket_tab + the SC variable editor the recommended, upgrade-safe way to do this in modern ESC, or is there a cleaner supported extension point (e.g. a ticket_tab_configuration custom tab, or a configuration I'm missing) that avoids cloning the tab widget?
  2. Is writing variable answers with $sp.saveVariables() and then updating mapped target fields with a direct GlideRecord the right pattern, or is there a supported API that updates a produced record's Record Producer answers and its mapped fields together?
  3. For the variable → field mapping, is relying on item_option_new.map_to_field / field correct? How should I handle producers that map variables only in the producer script (no map_to_field)?
  4. Any concerns with MRVS, List Collector, reference, or date variables when writing back to mapped columns via setValue()?
  5. Since I'm intentionally not using ACLs/UI Policies/Client Scripts, is enforcing editability + write security purely server-side (state check + canWrite() at save) considered acceptable/best practice here?
  6. Anything that could break OOB Employee Center behavior (Activity/Attachments tabs, record watcher, etc.) that I should watch for?

Environment: (add your version, e.g., Washington/Xanadu/Yokohama), Employee Center / Service Portal, Record Producer target table = incident.

 

 

Thanks in advance — happy to share the full widget code if useful.

 

#Employee Center, #Service Portal, #Record Producer, #Standard Ticket, #Variable Editor, #question_answer, #item_opt

0 REPLIES 0