Name

sn_uibtk_api.Page

Description

No description available

Script

const Page = Class.create();
Page.prototype = {
  initialize: function(noDomain) {
      this.appRouteHander = new AppRoute();
      this.addonEventMappingHandler = new UXAddOnEventMapping([], noDomain);
      this.clientScriptHandler = new ClientScript();
      this.componentDefinitionHandler = new ComponentDefinitions();
      this.controllerHandler = new Controller();
      this.dataBrokerDefinitionHandler = new DataBrokerDefinitions();
      this.experienceHandler = new Experience();
      this.macroponentHandler = new Macroponent();
      this.presetHandler = new Preset();
      this.controllerPresetHandler = new ControllerPreset();
      this.screenApplicabilityHandler = new ScreenApplicability([], noDomain);
      this.screenCollectionHandler = new ScreenCollection();
      this.screenHandler = new Screen([], noDomain);
      this.screenTestValueHandler = new ScreenTestValue();
      this.uxEventHandler = new UXEvent();
      this.uibTemplateHandler = new UIBTemplate();
      this.extensionPointHandler = new ExtensionPoint();
      this.libComponentHandler = new LibComponent();
  },

  createPage: function(
      experienceId = false,
      screen = false,
      route = false,
      applicabilities = [],
      screenTestValues = {},
      templateId = false,
      mode = false
  ) {
      let errorMessage = BuilderToolkitConstants.ERRORS.NO_EXPERIENCE_FOUND;
      if (screen && route) {
          const extensionPoint = this.extensionPointHandler.getRecordById(experienceId);
          const experience = this.experienceHandler.getRecordById(experienceId);

          const {
              name: routeName
          } = route;
          const experienceData = {
              appConfig: experience ? experience?.adminPanel : null,
              parentMacroponent: extensionPoint?.appShell ?? route?.parentMacroponent ?? experience?.rootMacroponent,
              extensionPoint: extensionPoint ? extensionPoint?.sysId : null
          };
          const screenCollectionId = this.screenCollectionHandler.createRecord({
              name: routeName
          });
          errorMessage = BuilderToolkitConstants.ERRORS.FAILED_TO_CREATE_SCREEN_COLLECTION;
          if (screenCollectionId) {
              const routeId = this.appRouteHander.createRecord({
                  ...route,
                  ...experienceData,
                  screenType: screenCollectionId,
              });
              errorMessage = BuilderToolkitConstants.ERRORS.FAILED_TO_CREATE_APPROUTE;
              if (routeId) {
                  const screenResult = this.screenHandler.create(experienceData, {
                      ...screen,
                      screenType: screenCollectionId
                  }, [...(route.fields ?? []), ...(route.optionalParameters ?? [])], applicabilities, screenTestValues, templateId, mode);
                  if (typeof screenResult !== 'string') {
                      return {
                          ...screenResult,
                          route: routeId,
                          screenCollection: screenCollectionId,
                      };
                  } else {
                      errorMessage = screenResult;
                  }
                  this.appRouteHander.deleteRecord({
                      sysId: routeId
                  });
              }
              this.screenCollectionHandler.deleteRecord({
                  sysId: screenCollectionId
              });
          }
      }
      return errorMessage;
  },

  createSubPage: function(screenGR, newMacroponentId, overrideFieldValues, scope, domain) {
      const newScreenCollectionId = this.screenCollectionHandler.createRecord({
          name: screenGR.screen_type.name.toString(),
          sysScope: scope,
          sysDomain: domain
      });
      const existingAppRoute = this.appRouteHander.getRecordsByQuery('screen_type=' + screenGR.screen_type.toString(), '', true);
      if (!existingAppRoute || !existingAppRoute.next()) {
          newScreenCollectionId ? this.screenCollectionHandler.deleteRecord({
              sysId: newScreenCollectionId
          }) : null;
          return false;
      }
      const newRouteId = this.appRouteHander.copyRecord(existingAppRoute, null, {
          ...overrideFieldValues,
          screenType: newScreenCollectionId,
          sysScope: scope,
          sysDomain: domain
      });
      const newScreenId = this.screenHandler.copyRecord(screenGR, null, {
          ...overrideFieldValues,
          macroponent: newMacroponentId,
          screenType: newScreenCollectionId,
          sysScope: scope,
          sysDomain: domain
      });
      if (!newScreenCollectionId || !newRouteId || !newScreenId) {
          newScreenCollectionId ? this.screenCollectionHandler.deleteRecord({
              sysId: newScreenCollectionId
          }) : null;
          newRouteId ? this.appRouteHander.deleteRecord({
              sysId: newScreenCollectionId
          }) : null;
          newScreenId ? this.screenHandler.deleteRecord({
              sysId: newScreenCollectionId
          }) : null;
          return false;
      }
      return newScreenId;
  },

  /**
   * @param screenGR {GlideRecord} the screen record we are pulling from
   * @param extensionPointGR {GlideRecord | null} the extension point record our route is are tied to
   */
  getContextState: function(screenGR, macroponentGR, extensionPointGR) {
      const pageRegistry = new BuilderToolkitAPIBase('sys_ux_page_registry').getRecordsByQuery(`admin_panel=${screenGR.getValue('app_config')}`, '', true);
      const {
          embeddedExtensionPointControllers,
          extensionPointController
      } = new Controller().getExtensionPointControllers(extensionPointGR);
      const extensionPointValues = extensionPointGR ? this.extensionPointHandler.getValuesFromGlideRecord(extensionPointGR) : {};
      if (pageRegistry && pageRegistry.next()) {
          const parentMacroponent = !screenGR.parent_macroponent.nil() ? screenGR.parent_macroponent.getRefRecord() : null;
          const parent = extensionPointGR ? this.getParentForExtensionPoint(extensionPointGR.getValue('app_shell')) : this.screenHandler.getParent(parentMacroponent, pageRegistry, screenGR);
          const ancestor = extensionPointGR ? {} : this.screenHandler.getAncestor(pageRegistry, parentMacroponent?.getUniqueValue() ?? null);
          const appPageProperties = [{"name":"appId", "value":pageRegistry.sys_id}].concat(new BuilderToolkitAPIBase('sys_ux_page_property', ['name', 'type', 'route', 'value']).getRecordsByQuery('page=' + pageRegistry.getUniqueValue()));
          let theme = '{}';
          // Adding try catch to protect us from any scriptable changes which are in global
          try {
              theme = UIBScriptables.getThemeForUIB(pageRegistry.getValue('admin_panel'), pageRegistry.getValue('parent_app'));
          } catch (err) {
              // No theme information is set for the page or parent app
          }

          return {
              ancestor,
              extensionPoint: extensionPointValues,
              embeddedExtensionPointControllers: embeddedExtensionPointControllers ?? [],
              extensionPointController,
              extendsMacroponent: this.macroponentHandler.getRecordById(macroponentGR.getValue('extends')),
              appPageProperties,
              parent,
              theme
          };
      }
      return {
          parent: extensionPointGR ? this.getParentForExtensionPoint(extensionPointGR.getValue('app_shell')) : {},
          extensionPoint: extensionPointValues,
          embeddedExtensionPointControllers: embeddedExtensionPointControllers ?? [],
          extensionPointController,
          extendsMacroponent: this.macroponentHandler.getRecordById(macroponentGR.getValue('extends'))
      };
  },

  /**
   * This is the full Page getter function when loading a UIB page
   * 
   * @param screenSysId {string} the sys_id of the screen we are getting
   */
  getUIBEditorPageObject: function(screenSysId) {
      const screenGR = this.screenHandler.getRecordById(screenSysId, true);
      if (screenGR) {
          if (screenGR.macroponent.nil()) {
              return gs.getMessage('No page definition has been found');
          }
          const macroponentGR = screenGR.macroponent.getRefRecord();
          if (!macroponentGR.isValidRecord()) {
              return gs.getMessage('No macroponent definition could be found');
          }

          const macroponentValues = this.macroponentHandler.getValuesFromGlideRecord(macroponentGR);
          const {
              mcpIds,
              presetIds
          } = this.macroponentHandler.getCompositionReferenceIds(this.macroponentHandler.parseJSON(macroponentGR.getValue('composition'), {
              field: 'composition',
              sysId: macroponentGR.getUniqueValue()
          }));

          const presetDefinitions = this.presetHandler.convertPresetDefinitions(this.presetHandler.getRecordsByQuery('sys_idIN' + presetIds));
          const bundleMcpIds = (macroponentValues.bundles ?? []).map(bundle => bundle.definitionId);
          const componentDefintions = this.componentDefinitionHandler.getComponentDefinitions([...bundleMcpIds, ...mcpIds, ...this.componentDefinitionHandler.ALWAYS_LOAD_COMPONENT_IDS], true);
          const libComponentDefinitions = this.libComponentHandler.getComponentDefinitions(mcpIds);

          const allComponentDefinitions = [...componentDefintions, ...libComponentDefinitions];
          const allComponentMcpIds = allComponentDefinitions.map(({
              macroponent
          }) => macroponent.sysId);
          const filteredMcpIds = mcpIds.filter((id) => !allComponentMcpIds.includes(id));
          const macroponentDefinitions = this.macroponentHandler.getRecordsByQuery(`sys_idIN${filteredMcpIds}`);
          const embeddedMacroponentDefinitions = (macroponentDefinitions ?? []).reduce((acc, def) => {
              acc[def?.sysId] = def;
              return acc;
          }, {});

          const addOnEventMappings = this.addonEventMappingHandler.getRecordsByQuery('parent_macroponent=' + macroponentGR.getUniqueValue());
          // If we have no parent macroponent we're either broken or in extension point mode
          let contextState = null;
          let extensionPointControllerDefinitionIds = [];
          const routeGR = this.appRouteHander.getRecordsByQuery('extension_point!=^screen_type=' + screenGR.getValue('screen_type'), 'name', true);
          if (routeGR && routeGR.next()) {
              contextState = this.getContextState(screenGR, macroponentGR, routeGR.extension_point.getRefRecord());
              extensionPointControllerDefinitionIds = contextState.embeddedExtensionPointControllers.map(({
                  sysId
              }) => sysId);
          } else {
              contextState = this.getContextState(screenGR, macroponentGR);
          }
          const dataBrokerDefinitions = this.dataBrokerDefinitionHandler.getMacroponentDataBrokerDefinitions(macroponentGR, contextState);
          const allData = [].concat(macroponentValues?.data ?? [], contextState?.parent?.data ?? [], contextState?.ancestor?.data ?? []);
          const controllersFromData = this.controllerHandler.getControllersFromData(allData);
          const allControllerDefinitions = [...controllersFromData, ...this.controllerHandler.getRecordsByQuery(`sys_idIN${extensionPointControllerDefinitionIds}`)];
          const controllerPresetIds = this.controllerHandler.getControllerPresetReferenceIds(allData);
          const controllerPresetDefinitions = this.controllerPresetHandler.convertPresetDefinitions(this.controllerPresetHandler.getRecordsByQuery('sys_idIN' + controllerPresetIds));
          const screen = this.screenHandler.getValuesFromGlideRecord(screenGR);
          const parentHandledEventIds = contextState?.parent?.handledEvents?.reduce((acc, handler) => {
              return acc.concat(handler?.handledEvents);
          }, []);
          const ancestorHandledEventIds = contextState?.ancestor?.handledEvents?.reduce((acc, handler) => {
              return acc.concat(handler?.handledEvents);
          }, []);
          // Get all events for our MCP, dbs, components, controllers, parent mcp, and ancestor mcps, and public ones
          const allUxEventIds = `
              ${this.getAllEventSysIdFromMacroponentValues(macroponentValues)},
              ${this.getEventsFromSupportingRecords(componentDefintions, allControllerDefinitions, dataBrokerDefinitions)},
  			${this.getEventsFromSupportingRecords([], [], [...(contextState?.parent?.data ?? []), ...(contextState?.ancestor?.data ?? [])])},
  			${(parentHandledEventIds ?? '')},
              ${(ancestorHandledEventIds ?? '')},
  			${(contextState?.extendsMacroponent?.handledEvents ?? '')},
  			${BuilderToolkitConstants.PUBLIC_MCP_EVENT_SYS_IDS}
          `.replace(/\s/g, '');

          // We need to query by the eventIds we got, and our DB definition operation query too and we'll do that long query as a new Query
          const dataBrokerDefinitionOperationEventNameQuery = this.dataBrokerDefinitionHandler.getDataBrokerOperationsEventQuery(dataBrokerDefinitions);
          const eventDefinitionRecords = new UXEvent().getRecordsByQuery(`sys_idIN${allUxEventIds}${dataBrokerDefinitionOperationEventNameQuery.replace('^OR', '^NQ')}`, 'name');
          const eventDefinitions = [...eventDefinitionRecords, ...this.dataBrokerDefinitionHandler.getMutationDataBrokerDispatchedEvents(), ...this.dataBrokerDefinitionHandler.getRegularDataBrokerDispatchedEvents()];
          const lastUpgradeGR = new GlideRecord('sys_upgrade_history');
          lastUpgradeGR.orderByDesc('upgrade_started');
          lastUpgradeGR.setLimit(1);
          lastUpgradeGR.query();
          const lastUpgradeDT = lastUpgradeGR.next() ? new GlideDateTime(lastUpgradeGR.getValue('upgrade_started')) : null;
          const lastUpgrade = lastUpgradeDT ? lastUpgradeDT.getNumericValue() : null;

          return {
              screen,
              macroponent: macroponentValues,
              dataBrokerDefinitions,
              componentDefinitions: [...allComponentDefinitions, ...this.componentDefinitionHandler.getPseudoComponents()],
              screenTestValues: this.screenTestValueHandler.getRecordById(screenGR.getUniqueValue()),
              clientScripts: this.clientScriptHandler.getRecordsByQuery('macroponent=' + macroponentGR.getUniqueValue()),
              controllerDefinitions: this.controllerHandler.convertControllerDefinitions(allControllerDefinitions),
              controllerPresetDefinitions,
              presetDefinitions,
              macroponentPublicHandledEvents: BuilderToolkitConstants.PUBLIC_MCP_EVENT_SYS_IDS,
              contextState,
              subroutes: this.screenHandler.getSubroutes(macroponentGR.getUniqueValue()),
              addOnEventMappings,
              eventDefinitions,
              embeddedMacroponentDefinitions,
              lastUpgrade
          };
      }
      return false;
  },

  getEventsFromSupportingRecords: function(componentDefinitions = [], controllerDefinitions = [], dataBrokerDefinitions = {}) {
      const componentEvents = componentDefinitions.reduce((acc, compDef) => {
          return acc.concat(compDef?.macroponent?.dispatchedEvents?.split(',') ?? [],
              compDef?.macroponent?.handledEvents?.split(',') ?? []);
      }, []);

      const controllerEvents = controllerDefinitions.reduce((acc, contDef) => {
          return acc.concat(contDef?.macroponent?.dispatchedEvents?.split(',') ?? [],
              contDef?.macroponent?.handledEvents?.split(',') ?? []);
      }, []);

      const dataBrokerEvents = Object.values(dataBrokerDefinitions).filter((dbDef) => dbDef?.macroponent).reduce((acc, dbDef) => {
          return acc.concat(dbDef?.macroponent?.dispatchedEvents?.split(',') ?? [],
              dbDef?.macroponent?.handledEvents?.split(',') ?? []);
      }, []);
      return [...componentEvents, ...controllerEvents, ...dataBrokerEvents].join(',');
  },

  getAllEventSysIdFromMacroponentValues: function(macroponentValues) {
      const events = [...(macroponentValues?.handledEvents?.split(',') ?? []), ...(macroponentValues?.dispatchedEvents?.split(',') ?? [])];
      return events.join(',');
  },

  /**
   * @param pageRegistry {GlideRecord} the page registry record for the screen
   */
  getParentForExtensionPoint: function(appShellSysId) {
      const appShellGR = this.macroponentHandler.getRecordsByQuery(`sys_id=${appShellSysId}`, '');
      if (appShellGR) {
          return this.screenHandler.getUpstreamAttributes(appShellGR[0]);
      }
      return {};
  },

  type: 'Page'
};

Sys ID

b169b3bc9d231110f8772de6b52d4d7a

Offical Documentation

Official Docs: