Project setup scripts
When you create a new project, the following scripts are required to set up the project. You can find these scripts in the local setupScripts folder.
| Script | Description |
|---|---|
| uploadScripts | Uploads the project scripts stored in scripts/NextScriptEngine/scrips/js as Script objects in the Item Service |
| userConfigImports | Creates the required UserConfigs for the defined user roles in the app |
| bimpkOperations | Uploads the project's Bimpk file. |
| importModel | Imports the model composite from the Bimpk file. |
| createCollections | Creates collections for the imported model elements and types |
| mapRevitTypeCollection | Maps the Revit types to the model elements. |
| createOtherCollections | Creates the telemetry, IoT, warranty data and file collections required for the project as well as a permission profile for the project Orchestrators |
| fileAttributesImport | Imports attributions that are applied to files you upload to the project, such as design or engineering documents. |
| apiConfigImport | Creates an ApiConfig for the project's custom REST APIs which execute on the server side |
Running the setup scripts#
User interface project setup#
When you create a new project using the Reference App user interface, the ProjectSetup platform component itself creates an orchestrator that runs each script. For more information on the ProjectSetup component, see ProjectSetup platform component.
VS code extension project setup#
If you want to manually set up a project using the VS code extension, you must run each script and select the required inputs, such as project scripts and configs. For more information on the VS code extension project setup process, see Setting up a project with the VS code extension.
ProjectSetup platform component#
handleProjectSetUp#
In the componenent, the handleProjectSetUp function calls the createScripts function to upload the scripts as Script items in the Item Service, then calls runOrchestrator to run each script in a sequence.
createScripts#
In the createScripts function contains Script type definitions for the setup scripts:
let scriptsDescriptors = [ { _name: "Upload Scripts", _shortName: "uploadRunnableScripts", _description: "Upload all Scripts", _userType: "uploadRunnableScripts", }, { _name: "User Config Import", _shortName: "configUpload", _description: "Upload config files", _userType: "configUpload", }, { _name: "Upload bimpk file", _shortName: "uploadBimpk", _description: "Upload and extract bimpk files", _userType: "uploadBimpk", }, { _name: "Create Collections", _shortName: "createCollections", _description: "Create collections", _userType: "createCollections", }, { _name: "Import File Attributes", _shortName: "fileAttributesImport", _description: "Import File Attributes", _userType: "fileAttributesImport", }, { _name: "Import Api Config", _shortName: "apiConfigImport", _description: "Import Api Config File", _userType: "apiConfigImport", }, ];Next, the function fetches the URL for the zipped setup scripts folder stored in cloud storage, taking the URL from the setupZipFileOrigin in your endPointConfig:
Note: The
endPointConfigcontains the environment endpoints for the platform services as well as the URLs for your zipped setup scripts and project scripts. For more information on theendPointConfig, go toapp/public/config.jsin your Reference App folder.
//Fetch Zip let myZipFile; await fetch(`${endPointConfig.setupZipFileOrigin}`) //fetch zip file using link .then((response) => response.blob()) .then((blob) => { // Store the binary blob in a variable myZipFile = new Blob([blob], { type: "application/zip" }); }) .catch((error) => { console.error(error); }); let zipFileObj = { //object of zip file to passed on _loadZipFile fileObj: myZipFile, };It loads the zipped file using IafLocalFile.loadZipFile from the UiUtils package:
let scriptFiles = await UiUtils.IafLocalFile._loadZipFile(zipFileObj); //load all files using scriptFilesThe script extracts the file name and file content:
let scripts = []; const scriptNames = [ "uploadRunnableScripts", "configUpload", "uploadBimpk", "createCollections", "fileAttributesImport", "apiConfigImport", ]; for (let i = 0; i < scriptNames.length; i++) { const scriptName = scriptNames[i]; const scriptContent = await scriptFiles.files[ `setupScripts/${scriptName}.js` ].async("string"); scripts.push({ scriptName, scriptContent }); }Then it pushes the script content to the relevant Script type definition:
//* Adding more information like version and namesapce let scriptItems = []; scripts.forEach((c) => { let item = scriptsDescriptors.find( (obj) => obj._shortName === c.scriptName ); if (item) { item._version = { _userData: c.scriptContent }; item._namespaces = project._namespaces; scriptItems.push(item); } });Finally, it creates the scripts as Script items in the Item Service:
let createScriptRes = await PlatformApi.IafScripts.create(scriptItems, ctx);runOrchestrator#
The runOrchestrator function creates an orchestrator, then creates an orchRun to run that orchestrator and poll it.
First, it defines and orchestrator configuration and passes it to IafScriptEngine.addDatasource to create the orchestrator. Each task has a sequence number and its _actualparams value contains the userType that identifies the Script item and a _scriptName value that identifies the script within the Script file to run:
async function runOrchestrator() { let orchestratorConfig = await IafScriptEngine.addDatasource({ _name: "Setup Project", _description: "Run all scripts needed for setup", _namespaces: ctx._namespaces, _userType: "setup_runner", _params: { tasks: [ // the ordered list of steps that are a part of the orchestrator { _sequenceno: 1, _name: "Uploading User Scripts:", _orchcomp: "default_script_target", _actualparams: { userType: "uploadRunnableScripts", _scriptName: "uploadScripts", // the named script to run in the file above }, }, { _sequenceno: 2, _name: "Creating User Configurations:", _orchcomp: "default_script_target", _actualparams: { userType: "configUpload", _scriptName: "userConifgImports", // the named script to run in the file above }, }, { _sequenceno: 3, _name: "Uploading Model File:", _orchcomp: "default_script_target", _actualparams: { userType: "uploadBimpk", _scriptName: "bimpkOperations", // the named script to run in the file above }, }, { _sequenceno: 4, _name: "Creating Collections:", _orchcomp: "default_script_target", _actualparams: { userType: "createCollections", _scriptName: "createCollections", // the named script to run in the file above }, }, { _sequenceno: 5, _name: "Importing File Attributes:", _orchcomp: "default_script_target", _actualparams: { userType: "fileAttributesImport", _scriptName: "fileAttributesImport", // the named script to run in the file above }, }, { _sequenceno: 6, _name: "Importing OMAPI Configurations:", _orchcomp: "default_script_target", _actualparams: { userType: "apiConfigImport", _scriptName: "apiConfigImport", // the named script to run in the file above }, }, ], }, });Before running the orchestrator, we pass a params argument which contains the orchestrator's id and the parameters to pass to each step's script, which in this example is the Ctx, Project, and the URL to the project's model scripts, which you can find in app/scripts/NextScriptEngine/scripts/js in your Reference App folder.
let datasourceRunRequest = { orchestratorId: runSetupOrch.id, _actualparams: [ { sequence_type_id: runSetupOrch.orchsteps[0]._compid, params: { ctx: JSON.stringify(ctx), project: project, zipLink: endPointConfig.projectZipFileOrigin, }, }, ], };With the parameters defined, run the orchestrator using IafDataSource.runOrchestrator:
// run the orchestrator - this returns an orchestrator run item that indicates the orchestrator has been 'QUEUED' const orchRun = await IafDataSource.runOrchestrator( runSetupOrch.id, datasourceRunRequest, ctx ); console.log("orchRun", orchRun);This queues the orchestrator to run. To poll the status of the orchRun at intervals using setInterval and based on the status, such as RUNNING, COMPLETED, or ERROR, it performs an action:
//Check status every 10 seconds let startTime = Date.now(); const map_orch_timer = setInterval(async () => { let status = await IafScriptEngine.getDatasourceRunStatus( { runid: orchRun.id }, ctx ); status = status.find((f) => f._usertype == "setup_runner"); console.log("SetupProject Run Status", status); switch (status._status) { case "COMPLETED": console.log("COMPLETED SetupProject", status); clearInterval(map_orch_timer); console.log("handleProjectSetUp === done"); div.style.display = "none"; document.getElementById("donebtn").style.display = "block"; break;
case "RUNNING": let endTime = Date.now(); let diffInSeconds = (endTime - startTime) / 1000; console.log( `Project setup running since ${(diffInSeconds / 60).toFixed( 2 )} minutes.` );
let messageArray = []; let sequencedOrchSteps = status.orchrunsteps.sort( (a, b) => a._sequenceno - b._sequenceno ); messageArray = sequencedOrchSteps.map((x) => { return x._name + " " + x._status; }); div.style.display = "block"; div.innerHTML = ""; messageArray.forEach((x) => { const [name, status] = x.split(" "); div.innerHTML += `<div style="display:flex; flex-direction:row; justify-content: space-between;"><p style="font-size: 15px; margin:1px; padding-left:5px">${name}</p><p style="font-size: 15px; margin:1px; padding-right:5px">${status}</p></div>`; }); break;
case "ERROR": console.error("Error message", status.orchrunsteps[0]._statusmsg); clearInterval(map_orch_timer); div.style.display = "block"; div.innerHTML = "Setup did not Complete, An error occured during setup!"; div.style.color = "red"; break;
default: div.style.display = "block"; div.innerHTML = "Setup is in progress, please wait..."; break; } }, 10000); } };