Name

global.WorkspaceCompilerUtils

Description

Set of utilities to assist with compiling Workspace records var wcu = new WorkspaceCompilerUtils(); wcu.

Script

var WorkspaceCompilerUtils = Class.create();

WorkspaceCompilerUtils.prototype = {
  initialize: function() {},

  type: 'WorkspaceCompilerUtils',

  runValidations: function(workspace) {
  	var uxPageUrl = this.makeWorkspaceUxPageUrl(workspace.getValue('workspace_url'));
  	if (this.isInUsePageUrl(uxPageUrl)) {
  		return {
  			passes: false,
  			shouldAbort: true,
  			message: 'Could not save this Workspace with URL path already in use: ' + uxPageUrl
  		};
  	}
  	return {passes: true, shouldAbort: false};
  },
  
  isValidUxPageRegistry: function (pageRegistryId) {
  	if (gs.nil(pageRegistryId))
  		return false;
  	var pageReg = new GlideRecord('sys_ux_page_registry');
  	return pageReg.get(pageRegistryId);
  },
  
  isValidContentExtension: function (contExtId) {
  	if (gs.nil(contExtId))
  		return false;
  	var contExt = new GlideRecord('sys_ux_custom_content_root_elem');
  	return contExt.get(contExtId);
  },

  makeWorkspaceUxPageUrl: function(thisWorkspaceSubpath) {
  	return "workspace/" + thisWorkspaceSubpath;
  },

  isInUsePageUrl: function(url) {
  	var pageRegistry = new GlideRecord('sys_ux_page_registry');
  	pageRegistry.addQuery('path', url);
  	pageRegistry.query();
  	return pageRegistry.hasNext();
  },
  
  getCanonicalUxPage: function() {
  	// sys_id of the Agent Workspace record in sys_ux_page
  	var canonical = gs.getProperty(
  		'com.workspace.canonical_ux_page',
  		'b70867ad0f603300bb57f4a1ff767e15'
  	);
  	var uxPage = new GlideRecord('sys_ux_page');

  	if(uxPage.get(canonical)) {
  		return uxPage.getUniqueValue();
  	}

  	return '';
  },
  
  compileContentExtension: function(libComponent, current, placeholder, label) {
  	if (libComponent == '') {
  		return '';
  	}
  	
  	var name = !!label ? label : current.getValue('label') + ' Module';
  	var contentExtension = this.createContentExtension(name, placeholder, libComponent, current);

  	return contentExtension.getUniqueValue();
  },

  compileSecondaryContentExtension: function(current) {
  	// sys_id of the Workspace Module Secondary Content record in sys_ux_content_placeholder_elem
  	var placeholder = gs.getProperty(
  		'com.workspace.secondary_content_placeholder',
  		'12376f475300330030c3ddeeff7b12bc'
  	);

  	return this.compileContentExtension(current.detail_component, current, placeholder, current.getValue('label') + ' Module Detail');
  },

  compilePrimaryContentExtension: function(current) {
  	// sys_id of the Workspace Module Primary Content record in sys_ux_content_placeholder_elem
  	var placeholder = gs.getProperty(
  		'com.workspace.primary_content_placeholder',
  		'123513475300330030c3ddeeff7b122f'
  	);

  	return this.compileContentExtension(current.content_component, current, placeholder,  current.getValue('label') + ' Module Content');
  },

  createButton: function(current) {
  	var name = (current.getValue('label') || current.getValue('id')) + ' Button';
  	// sys_id of the Workspace Toolbar Buttons record in sys_ux_content_placeholder_elem
  	var placeholder = gs.getProperty(
  		'com.workspace.toolbar_placeholder',
  		'1232bfb5730c330075e8f358caf6a7ca'
  	);
  	// sys_id of the sn-workspace-toolbar-button record in sys_ux_lib_component
  	var component = gs.getProperty(
  		'com.workspace.toolbar_component_button',
  		'c599f5f3b6554fd79cd983bf4ea75968'
  	);
  	var contentExtension = this.createContentExtension(name, placeholder, component, current);
  	
  	this.updateButton(contentExtension, current);
  	
  	return contentExtension.getUniqueValue();
  },
  
  createContentExtension: function(name, placeholder, libComponent, currentModule) {
  	var canonicalPage = this.getCanonicalUxPage();
  	var customContentRootElem = new GlideRecord('sys_ux_custom_content_root_elem');
  	var applicablePage = currentModule.workspace_config.compiled_page_registry;
  	
  	customContentRootElem.newRecord();
  	customContentRootElem.setValue('component', libComponent);
  	customContentRootElem.setValue('name', name);
  	customContentRootElem.setValue('page', canonicalPage);
  	customContentRootElem.setValue('applicability', 'single');
  	customContentRootElem.setValue('applicable_page', applicablePage);
  	customContentRootElem.setValue('placeholder', placeholder);
  	customContentRootElem.setValue('active', currentModule.active);
  	customContentRootElem.setValue('order', currentModule.order);
  	customContentRootElem.insert();

  	customContentRootElem.picker_condition['module_id'] = currentModule.id;
  	customContentRootElem.update();
  	
  	this.setRolesForElement(customContentRootElem.getUniqueValue(), this.getArrayFromGlideList(currentModule, 'roles'));

  	return customContentRootElem;
  },
  
  getArrayFromGlideList: function (record, field) {
  	if (!record.isValidField(field))
  		return [];
  	if (gs.nil(record[field]))
  		return [];
  	return record.getValue(field).split(',');
  },
  
  setRolesForElement: function (elementId, roleIds) {
  	// We try to re-use as many existing permission records as possible
  	// to minimize sys_update_xml generation
  	var elemPermission = new GlideRecord('sys_ux_page_element_m2m_role');
  	var rolesToAdd = roleIds.slice(0).sort().filter(function (item, pos, ary) {
  		return !pos || item != ary[pos - 1];
  	}); // make sorted, deduped copy
  	var permsToDelete = [], roleId, i;
  	elemPermission.addQuery('element', elementId);
  	elemPermission.orderBy('role.sys_id');
  	elemPermission.query();
  	
  	// First, determine if we already have existing that can be kept as-is,
  	// As well, collect any sys_id for records we can over-write, or potentially delete
  	while (elemPermission.next()) {
  		roleId = elemPermission.getValue('role');
  		if (rolesToAdd.length == 0 || rolesToAdd[0] != roleId) {
  			// Mark for re-use or (potential) deletion, if not in toAdd list
  			permsToDelete.push(elemPermission.getUniqueValue());
  		} else {
  			// Remove from toAdd list if exists
  			rolesToAdd.shift();
  			// Clear group setting, if set (we only compile to role based permissions)
  			if (!gs.nil(elemPermission.group)) {
  				elemPermission.group = '';
  				elemPermission.update();
  			}
  		}
  	}
  	
  	// Second, over-write old perm records with any completely new rolesToAdd
  	elemPermission = new GlideRecord('sys_ux_page_element_m2m_role');
  	elemPermission.addQuery('sys_id', 'IN', permsToDelete);
  	elemPermission.query();
  	permsToDelete = [];
  	while (elemPermission.next()) {
  		if (rolesToAdd.length > 0) {
  			elemPermission.role = rolesToAdd.shift();
  			elemPermission.group = '';
  			elemPermission.update();
  		} else {
  			permsToDelete.push(elemPermission.getUniqueValue());
  		}
  	}
  	
  	// Third, delete any superfluous permissions
  	if (permsToDelete.length > 0) {
  		elemPermission = new GlideRecord('sys_ux_page_element_m2m_role');
  		elemPermission.addQuery('sys_id', 'IN', permsToDelete);
  		elemPermission.query();
  		elemPermission.deleteMultiple();
  	}
  	
  	// Last, if any rolesToAdd left, add them!
  	for (i = 0; i < rolesToAdd.length; i++) {
  		elemPermission = new GlideRecord('sys_ux_page_element_m2m_role');
  		elemPermission.newRecord();
  		elemPermission.element = elementId;
  		elemPermission.role = rolesToAdd[i];
  		elemPermission.insert();
  	}
  },
  
  deactivateContentExtension: function(sys_id) {
  	if (gs.nil(sys_id)) {
  		return;
  	}
  	var customContentRootElem = GlideRecord('sys_ux_custom_content_root_elem');

  	if (customContentRootElem.get(sys_id)) {
  		customContentRootElem.setValue('active', false);
  		customContentRootElem.update();
  	}
  },
  
  deactivateAllContentExtensions: function(module) {
  	module.content_component = '';
  	module.detail_component = '';
  	
  	this.deactivateContentExtension(module.content);
  	this.deactivateContentExtension(module.detail);
  },
  
  deleteContentExtension: function(sys_id) {
  	var customContentRootElem = GlideRecord('sys_ux_custom_content_root_elem');

  	while (customContentRootElem.get(sys_id)) {
  		customContentRootElem.deleteRecord();
  	}
  },
  
  deleteAllContentExtensions: function(module) {
  	this.deleteContentExtension(module.content);
  	this.deleteContentExtension(module.detail);
  	
  	module.content_component = '';
  	module.detail_component = '';
  	module.content = '';
  	module.detail = '';
  	
  	// We currently can only safely delete attrs when both content extensions are removed because
  	// we have no reference to which content extension created which attr
  	var variableValue = GlideRecord('sys_variable_value');
  	variableValue.addQuery('document_key', module.getUniqueValue());
  	variableValue.query();
  	while (variableValue.next()) {
  		variableValue.deleteRecord();
  	}
  },
  	
  updateButton: function(button, current) {
  	button.setValue('active', current.getValue('active'));
  	button.setValue('order', current.getValue('order'));
  	button.attrs['module-id'] = current.getValue('id');
  	button.attrs['icon'] = current.getValue('icon');
  	button.attrs['label'] = current.getValue('label');
  	button.update();
  	this.setRolesForElement(button.getUniqueValue(), this.getArrayFromGlideList(current, 'roles'));
  }
};

Sys ID

1f2f4ced531033002f86ddeeff7b121b

Offical Documentation

Official Docs: