Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

How to open a contextual side panel tab in Workspace from a UI Action?

SK07
Tera Contributor

Hi Community,

I have a custom requirement in CSM and FSM Configurable Workspace where I’ve created a UI Action called "AI Summarization" on the Incident form. This UI Action works both in classic view and Workspace.
The GlideAjax call returns an AI-generated summary successfully.

✔ Classic View

I show the result using g_form.addInfoMessage(). This works fine.

✔ Workspace View (CURRENT behavior)

Right now, the summary is also displayed using Workspace addInfoMessage().

What I need to achieve

Instead of showing the AI summary as an info message, I want the summary to appear inside a Workspace contextual side panel tab (right-side panel), with the tab title "AI Summary".

When the user clicks the UI Action:

  1. Workspace should open a contextual panel on the right side

  2. The panel should be titled AI Summary

  3. The AI-generated summary text (returned from GlideAjax) should appear inside the panel

  4. If the user clicks the UI Action again, the same panel should refresh with the new summary

Workspace Client Script:

function summarizeWithGroq(action, sysId, fields, api) {
    // Use Workspace form API if provided, otherwise fall back to g_form
    var form = api || (typeof g_form !== 'undefined' ? g_form : null);

    if (!form) {
        // No API at all (should not happen on a Workspace form)
        try {
            console.error('summarizeWithGroq: no form API (api/g_form) available.');
        } catch (e) {}
        return false;
    }

    // --- Try to resolve sysId from various sources before giving up ---
    sysId = sysId ||
        (fields && (fields.record_sys_id || fields.sys_id || fields['sys_id'])) ||
        (api && typeof api.getRecordID === 'function' && api.getRecordID && api.getRecordID()) ||
        (typeof g_form !== 'undefined' && typeof g_form.getUniqueValue === 'function'
            && g_form.getUniqueValue && g_form.getUniqueValue());

    // If still no sysId, match your original behavior
    if (!sysId) {
        try {
            if (typeof form.clearMessages === 'function') form.clearMessages();
            if (typeof form.addInfoMessage === 'function')
                form.addInfoMessage('⚠️ No incident selected.');
            else if (typeof form.showInfoMessage === 'function')
                form.showInfoMessage('⚠️ No incident selected.');
            else if (typeof g_form !== 'undefined' && typeof g_form.addInfoMessage === 'function') {
                g_form.clearMessages();
                g_form.addInfoMessage('⚠️ No incident selected.');
            }
        } catch (e) {
            try { console.error('summarizeWithGroq: error showing "no incident" message', e); } catch (ignore) {}
        }
        return false; // prevent default navigation
    }

    // --- Immediate feedback (same as your classic version) ---
    try {
        if (typeof form.clearMessages === 'function') form.clearMessages();
        if (typeof form.addInfoMessage === 'function')
            form.addInfoMessage(' Generating AI Summary — please wait...');
        else if (typeof form.showInfoMessage === 'function')
            form.showInfoMessage(' Generating AI Summary — please wait...');
        else if (typeof g_form !== 'undefined' && typeof g_form.addInfoMessage === 'function') {
            g_form.clearMessages();
            g_form.addInfoMessage(' Generating AI Summary — please wait...');
        }
    } catch (e) {
        try { console.error('summarizeWithGroq: error showing progress message', e); } catch (ignore) {}
    }

    // --- GlideAjax call to the same Script Include you already use ---
    try {
        var ga = new GlideAjax('GroqIncidentSummarizer');
        ga.addParam('sysparm_name', 'summarizeIncident');
        ga.addParam('sysparm_incident_sysid', sysId);

        ga.getXMLAnswer(function(response) {
            // Clear old messages first (same as your classic logic)
            try {
                if (typeof form.clearMessages === 'function') form.clearMessages();
                else if (typeof g_form !== 'undefined' && typeof g_form.clearMessages === 'function')
                    g_form.clearMessages();
            } catch (e) {}

            var result;
            try {
                result = JSON.parse(response);
            } catch (e) {
                // Match your original: show invalid response error near short_description
                try {
                    if (typeof form.showFieldMsg === 'function') {
                        form.showFieldMsg('short_description', 'Invalid response from summarizer', 'error', false);
                    } else if (typeof form.showErrorMessage === 'function') {
                        form.showErrorMessage('Invalid response from summarizer');
                    } else if (typeof g_form !== 'undefined' && typeof g_form.showFieldMsg === 'function') {
                        g_form.showFieldMsg('short_description', 'Invalid response from summarizer', 'error', false);
                    }
                } catch (ex) {
                    try { console.error('summarizeWithGroq: error showing parse error message', ex); } catch (ignore) {}
                }
                return;
            }

            // --- Success case (keep your original message HTML) ---
            if (result && result.status === 'success') {
                var successHtml = '<strong>🧠 AI Summary:</strong><br><br>' + result.text;

                try {
                    if (typeof form.addInfoMessage === 'function')
                        form.addInfoMessage(successHtml);
                    else if (typeof form.showInfoMessage === 'function')
                        form.showInfoMessage(successHtml);
                    else if (typeof g_form !== 'undefined' && typeof g_form.addInfoMessage === 'function')
                        g_form.addInfoMessage(successHtml);
                    else
                        console.log('AI Summary:', result.text); // last-resort fallback
                } catch (ex) {
                    try { console.error('summarizeWithGroq: error showing success message', ex); } catch (ignore) {}
                }
            } else {
                // --- Error case (keep your original error semantics) ---
                var msg = (result && (result.message || result.text)) || 'Groq summarizer failed';

                try {
                    if (typeof form.showFieldMsg === 'function') {
                        form.showFieldMsg('short_description', 'Summarizer error: ' + msg, 'error', false);
                    } else if (typeof form.showErrorMessage === 'function') {
                        form.showErrorMessage('Summarizer error: ' + msg);
                    } else if (typeof g_form !== 'undefined' && typeof g_form.showFieldMsg === 'function') {
                        g_form.showFieldMsg('short_description', 'Summarizer error: ' + msg, 'error', false);
                    } else {
                        console.error('Summarizer error:', msg);
                    }
                } catch (ex) {
                    try { console.error('summarizeWithGroq: error showing failure message', ex); } catch (ignore) {}
                }
            }
        });
    } catch (e) {
        // GlideAjax call itself failed
        try {
            if (typeof form.showErrorMessage === 'function')
                form.showErrorMessage('Failed to call summarizer: ' + (e.message || e));
            else if (typeof form.showFieldMsg === 'function')
                form.showFieldMsg('short_description', 'Failed to call summarizer: ' + (e.message || e), 'error', false);
            else if (typeof g_form !== 'undefined' && typeof g_form.showFieldMsg === 'function')
                g_form.showFieldMsg('short_description', 'Failed to call summarizer: ' + (e.message || e), 'error', false);
        } catch (ex) {}
        try { console.error('summarizeWithGroq: GlideAjax call failed', e); } catch (ignore) {}
    }

    // Prevent default button/navigation behavior
    return false;
}

My Question

How can I programmatically open a contextual side panel in Workspace from a UI Action, and pass my summary text (returned from GlideAjax) into that panel?

 

Any guidance, code sample, or best practice would be greatly appreciated!

Thanks in advance!

 

1 REPLY 1

Ankur Bawiskar
Tera Patron
Tera Patron

@SK07 

I don't think that's possible within workspace.

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader