Name
sn_uibtk_api.Screen
Description
No description available
Script
const Screen = Class.create();
Screen.prototype = Object.extendsObject(BuilderToolkitAPIBase, {
TABLE: 'sys_ux_screen',
FIELDS: ['name', 'macroponent', 'parent_macroponent', 'macroponent_config', 'event_mappings', 'rollback_screen', 'order', 'screen_type', 'screen_condition', 'sys_policy'],
/**
* @param fields {string[]}
* @param noDomain {boolean}
*/
initialize: function(fields, noDomain) {
BuilderToolkitAPIBase.prototype.initialize.call(this, this.TABLE, fields || this.FIELDS, noDomain);
this.macroponentHandler = new Macroponent();
},
create: function(experience, screenData, routeParameters = [], applicabilitiesData, screenTestValuesData = {}, templateId = false, mode = false) {
const experienceHandler = new Experience();
const mcpHandler = new Macroponent();
const templateHandler = new UIBTemplate();
const screenTestValueHandler = new ScreenTestValue();
const screenApplicabilityHandler = new ScreenApplicability([], this.noDomain);
let errorMessage = BuilderToolkitConstants.ERRORS.NO_EXPERIENCE_FOUND;
if (screenData) {
let experienceData = experience;
if (typeof experience === 'string') {
const experienceRecord = experienceHandler.getRecordById(experience);
const extensionPoint = new ExtensionPoint().getRecordById(experience);
experienceData = {
appConfig: experienceRecord ? experienceRecord?.adminPanel : null,
parentMacroponent: screenData?.parentMacroponent ?? extensionPoint?.appShell ?? experienceRecord?.rootMacroponent,
extensionPoint: extensionPoint?.sysId ?? null
};
}
let macroponentId = screenData.macroponent ?? false;
let mcpResult = false;
let macroponentConfig = false;
if (templateId && !macroponentId) {
const templateRecord = templateHandler.getRecordById(templateId);
if (templateRecord) {
mcpResult = mcpHandler.copy(templateRecord.macroponent);
if (typeof mcpResult === 'string') {
return mcpResult;
}
const templateProperties = [
...(templateRecord.requiredProperties ?? []),
...(templateRecord.optionalProperties ?? [])
];
const testValues = templateProperties.reduce(templateHandler.getTestValues, {});
screenTestValuesData = screenTestValuesData === {} ? screenTestValuesData : {
macroponentConfig: {
...screenTestValuesData.macroponentConfig ?? {},
...testValues
}
};
macroponentConfig = templateRecord.macroponentConfig ?? macroponentConfig;
} else {
return BuilderToolkitConstants.ERRORS.FAILED_TO_FIND_TEMPLATE;
}
} else {
errorMessage = BuilderToolkitConstants.ERRORS.FAILED_TO_CREATE_MACROPONENT;
mcpResult = macroponentId ? (mode === 'reference' ? macroponentId : mcpHandler.copy(macroponentId)) : mcpHandler.createRecord({
name: screenData.name,
['extends']: BuilderToolkitConstants.PAGE_TEMPLATE_ID,
category: experienceData?.extensionPoint ? BuilderToolkitConstants.SUB_PAGE_CATEGORY : BuilderToolkitConstants.PAGE_CATEGORY,
extensionPoint: experienceData?.extensionPoint ?? null,
props: routeParameters.map(function(routeParam) {
return {
...BuilderToolkitConstants.ROUTE_PARAM_PROPERTIES,
name: routeParam,
label: routeParam,
};
})
});
}
if (mcpResult && !mcpResult.error) {
const screenDataObject = {
...screenData,
...experienceData,
macroponent: mcpResult.newMacroponentId || mcpResult,
};
if (macroponentConfig) {
screenDataObject.macroponentConfig = macroponentConfig;
}
const screenId = this.createRecord(screenDataObject);
errorMessage = BuilderToolkitConstants.ERRORS.FAILED_TO_CREATE_SCREEN;
if (screenId) {
const newApplicabilities = applicabilitiesData.map(function(applicability) {
return {
applicability: applicability,
screen: screenId
};
});
return {
macroponent: mcpResult.newMacroponentId || mcpResult,
screen: screenId,
screenTestValues: screenTestValueHandler.createRecord({
...screenTestValuesData,
screen: screenId,
}),
applicabilities: screenApplicabilityHandler.createRecords(newApplicabilities)
};
}
}
if (mode !== 'reference') {
this.macroponentHandler.deleteRecord({
sysId: mcpResult.newMacroponentId || mcpResult
});
}
}
return errorMessage;
},
/**
* @param screenSysId {string} the sys_id of the screen we are starting from
* @param overrideFieldValues {object} an object with new values for the records e.g {name: value}
* @param isSubscreen {boolean} true if we are a subscreen coming from event queue
* @param scope {string} the sys_id of the scope we should use
* @param domain {string} the sys_id of the domain we should use
*/
duplicate: function(screenSysId, overrideFieldValues = {}, isSubscreen = false, scope = null, domain = null) {
const screen = this.getRecordById(screenSysId, true);
const originalMCPSysId = screen.getValue('macroponent');
const deleteFunctions = [];
let errorMessage = BuilderToolkitConstants.NO_SCREEN_FOUND;
if (!screen) {
return errorMessage;
}
const mcpHandler = new Macroponent();
const mcpResult = mcpHandler.copy(screen.macroponent.getRefRecord(), scope, domain);
if (typeof mcpResult === 'string') {
return mcpResult;
}
const {
newMacroponentId,
} = mcpResult;
const newScreenId = isSubscreen ? new Page().createSubPage(screen, newMacroponentId, overrideFieldValues?.screen, scope, domain) :
this.copyRecord(screen, null, {
...(overrideFieldValues?.screen ?? {}),
macroponent: newMacroponentId
});
deleteFunctions.push({
handler: new Screen(),
records: [{
sysId: newScreenId
}]
});
errorMessage = BuilderToolkitConstants.FAILED_TO_CREATE_SCREEN;
if (!newScreenId) {
this.executeDeleteFunctions(deleteFunctions);
return errorMessage;
}
const applicabilityHandler = new ScreenApplicability([], this.noDomain);
const newApplicabilities = (overrideFieldValues?.applicabilities ?? []).map(function(applicability) {
return {
applicability: applicability,
screen: newScreenId
};
});
const newApplicabilityM2MIds = applicabilityHandler.createRecords(newApplicabilities);
if (newApplicabilityM2MIds !== true) {
deleteFunctions.push({
handler: applicabilityHandler,
records: newApplicabilityM2MIds.map((item) => ({
sysId: item
}))
});
errorMessage = BuilderToolkitConstants.FAILED_TO_CREATE_SCREEN;
if (newApplicabilityM2MIds.some((result) => result === false)) {
this.executeDeleteFunctions(deleteFunctions);
return errorMessage;
}
}
const screenTestValueHandler = new ScreenTestValue();
let newScreenTestValue = screenTestValueHandler.copyRecord(null, screenSysId, {
screen: newScreenId
}, scope, domain);
if (!newScreenTestValue) {
newScreenTestValue = screenTestValueHandler.createRecord({
screen: newScreenId,
sysScope: scope
});
}
// Check for subroutes and emit event
const subscreens = this.getRecordsByQuery('parent_macroponent=' + originalMCPSysId, '', true);
const hasSubscreens = subscreens && subscreens.hasNext();
if (hasSubscreens) {
while (subscreens.next()) {
gs.eventQueue('sn_uibtk_api.create.subscreen', subscreens, this.getUserUpdateSetId(), newMacroponentId);
}
}
return {
macroponent: newMacroponentId,
screen: newScreenId,
screenTestValue: newScreenTestValue,
hasSubscreens
};
},
/**
* @param parentMCP {GlideRecord} the parent macroponent record for the screen
* @param pageRegistry {GlideRecord} the page registry record for the screen
* @param screen {GlideRecord} the current screen
*/
getParent: function(parentMCP, pageRegistry, screen) {
const parentScreen = parentMCP ? this.getRecordsByQuery('macroponent=' + parentMCP.getUniqueValue(), 'name', true) : null;
const hasParentScreen = parentScreen && parentScreen.next();
const parentMacroponentValues = parentMCP ? this.macroponentHandler.getValuesFromGlideRecord(parentMCP) : null;
const upstreamAttributes = parentMacroponentValues ? this.getUpstreamAttributes(parentMacroponentValues) : {
data: []
};
const parentInfo = hasParentScreen ? this.getValuesFromGlideRecord(parentScreen) : {};
const appRoute = new AppRoute().getRecordsByQuery('screen_type=' + screen.getValue('screen_type'));
parentInfo.compositionElementId = appRoute ? appRoute[0].parentMacroponentCompositionElementId : null;
return {
...upstreamAttributes,
appInfo: this.getParentAppInfo(pageRegistry),
info: parentInfo,
state: parentMacroponentValues?.state ?? {},
globalHandledEvents: BuilderToolkitConstants.GLOBAL_HANDLED_EVENT_IDS
};
},
/**
* @param pageRegistry {GlideRecord} the page registry record for the screen
* @param parentMacroponentId {string} the sys_id of the screen's parent macroponent
*/
getAncestor: function(pageRegistry, parentMacroponentId) {
const sessionDataBroker = new Macroponent().getRecordById(BuilderToolkitConstants.SESSION_DATABROKER_SYS_ID);
const hasDifferentAncestor = !pageRegistry.root_macroponent.nil() && pageRegistry.getValue('root_macroponent') !== parentMacroponentId;
let ancestor = {
data: []
};
if (hasDifferentAncestor && !pageRegistry.root_macroponent.nil()) {
const appShellMacroponentValues = this.macroponentHandler.getValuesFromGlideRecord(pageRegistry.root_macroponent.getRefRecord());
ancestor = this.getUpstreamAttributes(appShellMacroponentValues);
}
ancestor.data = ancestor.data.concat(sessionDataBroker.data);
return ancestor;
},
/**
* @param upstreamMCPValues {object} an object with all of the fields from an ancestor macroponent
*/
getUpstreamAttributes: function(upstreamMCPValues) {
const upstreamScreen = this.getRecordsByQuery('macroponent=' + upstreamMCPValues.sysId)?.[0];
const upstreamScreenTestValues = new ScreenTestValue().getRecordsByQuery('screen.macroponent=' + upstreamMCPValues.sysId)?.[0];
let upstreamValues = {
data: upstreamMCPValues.data || [],
elements: this.macroponentHandler.getCompositionElements(upstreamMCPValues.composition),
handledEvents: upstreamMCPValues?.handledEvents ? [{
sourceId: upstreamMCPValues?.sysId,
sourceName: upstreamMCPValues?.name,
handledEvents: upstreamMCPValues?.handledEvents
}] : [],
properties: upstreamMCPValues?.props ?? [],
propertyValues: {
testValues: upstreamScreenTestValues ? upstreamScreenTestValues?.macroponentConfig : {},
values: upstreamScreen ? upstreamScreen.macroponentConfig : {}
}
};
if (upstreamMCPValues['extends']) {
const nextUpstreamMacroponent = this.macroponentHandler.getRecordById(upstreamMCPValues['extends']);
const furtherUpstreamValues = this.getUpstreamAttributes(nextUpstreamMacroponent);
const combinedProperties = upstreamValues?.properties?.concat(furtherUpstreamValues?.properties).reduce((acc, prop) => {
if (!acc.some(({
name
}) => name === prop?.name)) {
acc.push(prop);
}
return acc;
}, []);
return {
data: upstreamValues?.data?.concat(furtherUpstreamValues?.data) ?? [],
elements: upstreamValues?.elements?.concat(furtherUpstreamValues?.elements) ?? [],
handledEvents: upstreamValues?.handledEvents?.concat(furtherUpstreamValues?.handledEvents) ?? [],
properties: combinedProperties,
propertyValues: {
testValues: {
...(upstreamValues?.propertyValues?.testValues ?? {}),
...(furtherUpstreamValues?.propertyValues?.testValues ?? {})
},
values: {
...(upstreamValues?.propertyValues?.values ?? {}),
...(furtherUpstreamValues?.propertyValues?.values ?? {})
}
}
};
}
return upstreamValues;
},
/**
* @param pageRegistry {GlideRecord} the page registry record for the screen
*/
getParentAppInfo: function(pageRegistry) {
if (!pageRegistry.next()) {
return {};
}
const pageRegistryRootMCP = pageRegistry.getValue('root_macroponent');
let parentApp = pageRegistry.parent_app.getRefRecord();
if (!parentApp.isValidRecord() &&
(pageRegistryRootMCP === 'c276387cc331101080d6d3658940ddd2' // agent workspace shell id
||
pageRegistryRootMCP === 'e341e22cc32e2010ea04a5a1d840dd02')) { // breadcrumb shell id
parentApp = this.get('sys_ux_app', 'sys_id=c86a62e2c7022010099a308dc7c26022');
if (parentApp.next()) {
parentApp = null;
}
}
if (parentApp !== null) {
return {
appId: parentApp ? parentApp.getUniqueValue() : null,
appName: parentApp.getValue('name'),
themeId: parentApp.getValue('theme'),
isPolairs: parentApp.getUniqueValue() === 'c86a62e2c7022010099a308dc7c26022'
};
}
return null;
},
/**
* @param parentMacroponentSysId {string} the sys_id of the screen's parent macroponent
*/
getSubroutes: function(parentMacroponentSysId) {
const appRoutes = new AppRoute().getRecordsByQuery('parent_macroponent=' + parentMacroponentSysId, 'name');
const subroutes = [];
appRoutes.forEach((appRoute) => {
const subscreens = [];
const subscreenValues = this.getRecordsByQuery('screen_type=' + appRoute.screenType, 'name');
subscreenValues.forEach((screen) => {
subscreens.push({
additionalConditions: [],
condition: screen.screenCondition,
eventMappings: screen.eventMappings,
id: screen.sysId,
macroponentConfiguration: screen.macroponentConfig,
macroponentSysId: screen.macroponent,
name: screen.name,
order: screen.order,
screenType: screen.screenType,
sysPolicy: screen.sysPolicy,
});
});
subroutes.push({
...appRoute,
controllerDependencyMap: null,
controllerElementId: null,
id: appRoute.sysId,
parentCompositionElementId: appRoute.parentMacroponentCompositionElementId,
macroponents: subscreens,
});
});
return subroutes;
},
/**
* @param extensionPointSysId {string} the sys_id of the extension point we are starting from
*/
getExperiencesForExtensionPoint: function(extensionPointSysId) {
let experiences = [];
const grScreen = this.getRecordsByQuery(`active=true^macroponent.compositionLIKE${extensionPointSysId}`, 'name', true);
if (!grScreen) {
return experiences;
}
while (grScreen.next()) {
const appConfig = grScreen.getValue('app_config');
const grExperience = new GlideRecord('sys_ux_page_registry');
grExperience.addEncodedQuery(`active=true^admin_panel=${appConfig}`);
grExperience.query();
while (grExperience.next()) {
const experience = grExperience.getValue('title');
const sysId = grExperience.getValue('sys_id');
const foundIndex = experiences.findIndex((expValue) => {
return (expValue.experience === experience && expValue.sysId === sysId);
});
if (foundIndex < 0) {
experiences.push({
experience: experience,
sysId: sysId
});
}
}
}
experiences.sort((exp1, exp2) => {
// case insensitive sort
const title1 = exp1.experience.toUpperCase();
const title2 = exp2.experience.toUpperCase();
if (title1 < title2) {
return -1;
}
if (title1 > title2) {
return 1;
}
return 0;
});
return experiences;
},
type: 'Screen'
});
Sys ID
1e17c8b185321110f877e10cffeb7ba7