Upgrading to the latest BMC Helix Innovation Studio SDK


If you are using the BMC Helix Innovation Studio SDK to build and deploy applications and libraries, you must upgrade BMC Helix Innovation Studio SDK and any application projects that you created by using the earlier version of BMC Helix Innovation Studio SDK.

Important

These steps are not required for pure codeless development by using BMC Helix Innovation Studio .  

To upgrade to the latest BMC Helix Innovation Studio SDK

  1. After you receive a notification that your BMC Helix Innovation Studio has been updated,  download the BMC Helix Innovation Studio SDK ZIP file (com.bmc.arsys.rx.sdk-23.3.04.zip).
  2. Install Node.js version 16.20.1 and Yarn version v1.22.19. For more information, see To install Node.js and To install Yarn.
  3. The development environment has changed to OpenJDK. To install OpenJDK, see Setting-up-your-IDE-and-installing-BMC-Helix-Innovation-Studio-SDK
  4. Comment the maven-default-http-blocker to avoid the following error on HTTP download:
    Could not transfer artifact com.bmc.arsys.mojo:is-build-helper-maven-plugin:pom:1.0 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [bmcmanaged-nexus-tps (http://<server>:<port>/nexus/content/repositories/BMCRemedyManagedRepo, default, releases+snapshots)

    <!--    

    <mirror>
          <id>maven-default-http-blocker</id>
          <mirrorOf>external:http:*</mirrorOf>
          <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
          <url>http://0.0.0.0/</url>
          <blocked>true</blocked>
    </mirror>

    -->
  5. Some Maven repositories might not be available over HTTP. If your maven compilation fails due to the error, Return code is: 501 , ReasonPhrase:HTTPS Required, add the following entry in the <mirrors> section in the settings.xml file located in your <maven installation>/conf directory. 
    For more information, see Creating-a-Project-using-Maven-and-the-Archetype.

    <mirror>
    <id>central-over-https</id>
    <mirrorOf>central</mirrorOf>
    <name>Maven Central Repository</name>
    <url>https://repo.maven.apache.org/maven2</url>
    </mirror>
  6. Rename your current SDK folder to create a backup.
    For example, rename it to com.bmc.arsys.rx.sdk-23.0.03.BACKUP.
  7. At the location where you want to install the SDK, create a new SDK folder and extract the BMC Helix Innovation Studio SDK ZIP file (com.bmc.arsys.rx.sdk-23.3.04.zip).
  8. Add an environment variable, RX_SDK_HOME, that points to the sdk folder location.
  9. Find the .m2 folder (usually located in your user directory, such as %USERPROFILE%\.m2\repository\com\bmc on windows). Delete the arsys and rx folders located there.
  10. Install BMC Helix Innovation Studio SDK in your Maven repository by using the following commands:

    \com.bmc.arsys.rx.sdk-23.3.04> cd lib
    \com.bmc.arsys.rx.sdk-23.3.04\lib> mvn clean install
  11. Update the archetype-catalog.xml file to delete the earlier archetype versions (for example 23.3.03) and make sure the archetype-catalog.xml file has the archetype version as 23.3.04-SNAPSHOT.

    The archetype-catalog.xml file might be located at the following locations:

    • .m2
    • .m2/repository

    For example: 

    <archetype>    
    <groupId>com.bmc.arsys</groupId>
    <artifactId>rx-sdk-archetype-application</artifactId>
    <version>23.3.04-SNAPSHOT</version>
    <description>Rx SDK application archetype</description>
    </archetype>

To upgrade your application or library by using the SDK version 23.3.03 to 23.3.04

To upgrade your applications or libraries created by using the SDK from version 23.3.03 or earlier to 23.3.04, perform the following steps:

  1. Change the version of the following parameter in the parent pom.xml file located in the project folder:

    Current version

    Updated version

    <rx-sdk.version>23.3.03-SNAPSHOT</rx-sdk.version>
    <rx-sdk.version>23.3.04-SNAPSHOT</rx-sdk.version>

    <javac.version>11</javac.version>

    <javac.version>17</javac.version>

    <maven-bundle-plugin.version>4.0.0</maven-bundle-plugin.version>

    <maven-bundle-plugin.version>5.1.8</maven-bundle-plugin.version>
    <!--felix maven bundle plugin uses bnd lib biz.aQute.bndlib -->
    <bnd.version>6.3.1</bnd.version>

    <jersey.version>2.29</jersey.version>

    <jersey.version>2.42</jersey.version>

  2. Delete the content of the following folders:
    • /bundle/src/main/webapp/scripts/
    • /bundle/src/main/webapp/tools/
    • /bundle/src/main/webapp/apps/
    • /bundle/src/main/webapp/dist/
    • /bundle/src/main/webapp/styles/
    • /bundle/src/main/webapp/node_modules/
  3. Delete the following file: 
    /bundle/src/main/webapp/yarn.lock 
  4. Build, export, and deploy your application project. For example:

    myproj> mvn clean install -Pexport -Pdeploy
  5. Verify that your application functions correctly.
  6. (Optional) Perform this step only if you are running unit test cases. Update the unit test configuration.
    Replace the content of jest.preset.js file from /bundle/src/main/webapp/libs/com-example-foo location with the following content:
    Before

    const {pathsToModuleNameMapper} = require('ts-jest');
    const {compilerOptions} = require('../../tsconfig.base.json');

    module.exports = {
    displayName: 'com-example-foo',
    preset: '../../jest.preset.js',
    coverageDirectory: '../../coverage/libs/com-example-foo',
    snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment'
    ],

    setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],

    globals: {

    "ts-jest": {
    tsconfig: "<rootDir>/tsconfig.spec.json",
    stringifyContentPathRegex: "\\.(html|svg)$",
    },

    },
    transform: {
    '^.+.(ts|mjs|js|html)$': 'jest-preset-angular'
    },
    moduleNameMapper: Object.assign(
    {
    "^uuid$": "uuid",
    "^lodash-es$": "lodash"
    },
    pathsToModuleNameMapper(compilerOptions.paths, {prefix: '<rootDir>/../../'})
    ),
    testEnvironment: 'jsdom',
    transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
    testRunner: 'jest-jasmine2'
    };

    After

    const {pathsToModuleNameMapper} = require('ts-jest');
    const {compilerOptions} = require('../../tsconfig.base.json');

    module.exports = {
    displayName: 'com-example-foo',
    preset: '../../jest.preset.js',
    coverageDirectory: '../../coverage/libs/com-example-foo',
    snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment'
    ],

    setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],

    globals: {

    "ts-jest": {
    tsconfig: "<rootDir>/tsconfig.spec.json",
    stringifyContentPathRegex: "\\.(html|svg)$",
    },

    },
    transform: {
    '^.+.(ts|mjs|js|html)$': 'jest-preset-angular'
    },
    moduleNameMapper: Object.assign(
    {
    "^uuid$": "uuid",
    "^lodash-es$": "lodash",

    "@joint/plus": "file:./scripts/clientio/joint-plus-4.0.1.tgz"

    },
    pathsToModuleNameMapper(compilerOptions.paths, {prefix: '<rootDir>/../../'})
    ),
    testEnvironment: 'jsdom',
    transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
    testRunner: 'jest-jasmine2'
    };

To upgrade your application or library by using the SDK version 23.3.02 to 23.3.03

To upgrade your applications or libraries created by using the SDK from version 23.3.02 or earlier to 23.3.03, perform the following steps:

  1. Change the version of the following parameter in the parent pom.xml file located in the project folder:

    Current version

    Updated version

    <rx-sdk.version>23.3.02-SNAPSHOT</rx-sdk.version>
    <rx-sdk.version>23.3.03-SNAPSHOT</rx-sdk.version>
  2. Delete the content of the following folders:
    • /bundle/src/main/webapp/scripts/
    • /bundle/src/main/webapp/tools/
    • /bundle/src/main/webapp/apps/
    • /bundle/src/main/webapp/dist/
    • /bundle/src/main/webapp/styles/
    • /bundle/src/main/webapp/node_modules/
  3. Delete the following file: 
    /bundle/src/main/webapp/yarn.lock 
  4. Build, export, and deploy your application project. For example:

    myproj> mvn clean install -Pexport -Pdeploy
  5. Verify that your application functions correctly.

To upgrade your application or library by using the SDK version 23.3.01 to 23.3.02

To upgrade your applications or libraries created by using the SDK from version 23.3.01 or earlier to 23.3.02, perform the following steps:

  1. Change the version of the following parameter in the parent pom.xml file located in the project folder:

    Current version

    Updated version

    <rx-sdk.version>23.3.01-SNAPSHOT</rx-sdk.version>
    <rx-sdk.version>23.3.02-SNAPSHOT</rx-sdk.version>
  2. Delete the content of the following folders:
    • /bundle/src/main/webapp/scripts/
    • /bundle/src/main/webapp/tools/
    • /bundle/src/main/webapp/apps/
    • /bundle/src/main/webapp/dist/
    • /bundle/src/main/webapp/styles/
    • /bundle/src/main/webapp/node_modules/
  3. Delete the following file: 
    /bundle/src/main/webapp/yarn.lock 
  4. Build, export, and deploy your application project. For example:

    myproj> mvn clean install -Pexport -Pdeploy
  5. Verify that your application functions correctly.

To upgrade your application or library by using the SDK version 23.3.00 to 23.3.01

To upgrade your applications or libraries created by using the SDK from version 23.3.00 or earlier to 23.3.01, perform the following steps:

  1. Change the version of the following parameter in the parent pom.xml file located in the project folder:

    Current version

    Updated version

    <rx-sdk.version>23.3.00-SNAPSHOT</rx-sdk.version>
    <rx-sdk.version>23.3.01-SNAPSHOT</rx-sdk.version>
    <jackson.version>2.14.0</jackson.version>
    <jackson-databind.version>2.14.0</jackson-databind.version>
    <jackson.version>2.16.0</jackson.version>
    <jackson-databind.version>2.16.0</jackson-databind.version>
  2. Delete the content of the following folders:
    • /bundle/src/main/webapp/scripts/
    • /bundle/src/main/webapp/tools/
    • /bundle/src/main/webapp/apps/
    • /bundle/src/main/webapp/dist/
    • /bundle/src/main/webapp/styles/
    • /bundle/src/main/webapp/node_modules/
  3. Delete the following file: 
    /bundle/src/main/webapp/yarn.lock
  4. Build, export, and deploy your application project. For example:

    myproj> mvn clean install -Pexport -Pdeploy
  5. Verify that your application functions correctly.

To upgrade your application or library by using the SDK version 22.1.xx to 23.3.00

To upgrade your applications or libraries created by using the SDK from version 22.1.08 or earlier to 23.3.00, perform the following steps:

  1. Change the version of the following parameter in the parent pom.xml file located in the project folder:

    Current version

    Updated version

    <rx-sdk.version>22.1.08-SNAPSHOT</rx-sdk.version>
    <rx-sdk.version>23.3.00-SNAPSHOT</rx-sdk.version>
  2. Delete the content of the following folders:
    • /bundle/src/main/webapp/scripts/
    • /bundle/src/main/webapp/tools/
    • /bundle/src/main/webapp/apps/
    • /bundle/src/main/webapp/dist/
    • /bundle/src/main/webapp/styles/
    • /bundle/src/main/webapp/node_modules/
  3. Delete the following file: 
    /bundle/src/main/webapp/yarn.lock
  4. Update the files from /bundle/src/main/webapp/  location. 
    1. Replace the content of preinstall.js with the following script:

      const path = require('path');

       const preInstall = require(path.resolve(path.join(process.env.RX_SDK_HOME, '/client/target/web-build/webapp/dist/libs/platform/schematics/src/config/preinstall.js')));

       preInstall.initialize();
    2. Find and remove the following property from the angular.json file from /bundle/src/main/webapp/ location.

      "extractCss": true

       

  5. Remove the deprecated bundleId property used in rxViewComponentRegistryService.register() and rxViewActionRegistryService.register().
    • For view components, remove the bundleId property from the registration.module.ts file, for example label-registration.module.ts

      Example

      Update the following code:

      ​​​​​​​​​​​@NgModule({​​​​​
       imports: [LabelDesignModule, LabelModule]
      }​​​​​)
      export class LabelRegistrationModule {​​​​​​​​​​​​​​​​​​​​​​​​​​
       constructor(
         private rxViewComponentRegistryService: RxViewComponentRegistryService,
         private componentFactoryResolver: ComponentFactoryResolver
       ) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
         rxViewComponentRegistryService.register({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
           type: 'comExampleTest210500Label',
           name: 'Default view component for test210500.com-example-test210500 (label)',
           group: 'Test 21.05.00',
           componentFactory: this.componentFactoryResolver.resolveComponentFactory(LabelComponent),
           properties: [ //...],
           designComponentFactory: this.componentFactoryResolver.resolveComponentFactory(LabelDesignComponent),
           designComponentModel: LabelDesignModel,
           bundleId: 'com.example.test210500'
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​  

      To

      @NgModule({​​​​​​​​​​​​​​​​​​​​​​​​​​​​
       imports: [LabelDesignModule, LabelModule]
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
      export class LabelRegistrationModule {​​​​​​​​​​​​​​​​​​​​​​​​​​​​
       constructor(
         private rxViewComponentRegistryService: RxViewComponentRegistryService,
         private componentFactoryResolver: ComponentFactoryResolver
       ) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
         rxViewComponentRegistryService.register({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
           type: 'comExampleTest210500Label',
           name: 'Default view component for test210500.com-example-test210500 (label)',
           group: 'Test 21.05.00',
           componentFactory: this.componentFactoryResolver.resolveComponentFactory(LabelComponent),
           properties: [ //...],
           designComponentFactory: this.componentFactoryResolver.resolveComponentFactory(LabelDesignComponent),
           designComponentModel: LabelDesignModel
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​  
    • For actions, remove the bundleId property from the action.module.ts file, for example confirmation-ootb-action.module.ts

      Example

      Update the following code:

      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ NgModule }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@angular/core';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ RxViewActionRegistryService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@helix/platform/view/api';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbActionService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-action.service';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbActionDesignModel }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-action.design-model';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbDesignManagerService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-design-manager.service';

      @NgModule({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        providers: [ConfirmationOotbActionService, ConfirmationOotbDesignManagerService]
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
      export class ConfirmationOotbActionModule {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        constructor(
          private rxViewActionRegistryService: RxViewActionRegistryService,
          private confirmationOotbActionService: ConfirmationOotbActionService,
          private confirmationOotbDesignManagerService: ConfirmationOotbDesignManagerService
        ) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          this.rxViewActionRegistryService.register({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            name: 'comExampleTest210500ActionConfirmationOotb',
            label: 'Confirmation (OOTB)',
            bundleId: 'com.example.test210500',
            service: this.confirmationOotbActionService,
            designManager: this.confirmationOotbDesignManagerService,
            designModel: ConfirmationOotbActionDesignModel,
            parameters: [// ...]
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      To

      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ NgModule }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@angular/core';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ RxViewActionRegistryService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@helix/platform/view/api';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbActionService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-action.service';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbActionDesignModel }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-action.design-model';
      import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ConfirmationOotbDesignManagerService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './confirmation-ootb-design-manager.service';

      @NgModule({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        providers: [ConfirmationOotbActionService, ConfirmationOotbDesignManagerService]
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
      export class ConfirmationOotbActionModule {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        constructor(
          private rxViewActionRegistryService: RxViewActionRegistryService,
          private confirmationOotbActionService: ConfirmationOotbActionService,
          private confirmationOotbDesignManagerService: ConfirmationOotbDesignManagerService
        ) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          this.rxViewActionRegistryService.register({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            name: 'comExampleTest210500ActionConfirmationOotb',
            label: 'Confirmation (OOTB)',
            service: this.confirmationOotbActionService,
            designManager: this.confirmationOotbDesignManagerService,
            designModel: ConfirmationOotbActionDesignModel,
            parameters: [// ...]
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
  6. Refactor the custom UI View components to:
    • Handle Handle the deprecated Angular class ComponentFactoryResolver used in componentFactory and designComponentFactory. For more information, see ComponentFactoryResolver.

    • Convert View components to Standalone.

      Warning

      If a view component is displayed in a modal view, then the view component must be converted to standalone. 

      For example, a view is displayed by using an action button with action as Open View with presentation as Modal

      Best practice

      We recommend this step to prevent potential dependency injection issues in certain scenarios difficulty, for example displaying views with View components in modal mode.

      For the following steps, consider a view component foo that is created by using an earlier version of the SDK, with the following directory structure of a view component:

      • foo-registration.module.ts
      • design
        • foo-design.component.html
        • foo-design.component.ts
        • foo-design.model.ts
        • foo-design.module.ts
        • foo-design.scss
        • foo.interface.ts
      • runtime
        • foo.component.html
        • foo.component.ts
        • foo.scss
        • foo.service.ts 
        • foo.module.ts

      For the following steps, consider a view component foo that is created by using an earlier version of the SDK, with the following directory structure of a view component:

      • foo-registration.module.ts
      • design
        • foo-design.component.html
        • foo-design.component.ts
        • foo-design.model.ts
        • foo-design.module.ts
        • foo-design.scss
        • foo.interface.ts
      • runtime
        • foo.component.html
        • foo.component.ts
        • foo.scss
        • foo.service.ts 
        • foo.module.ts

      For the following steps, consider a view component foo that is created by using an earlier version of the SDK, with the following directory structure of a view component:

      • foo-registration.module.ts
      • design
        • foo-design.component.html
        • foo-design.component.ts
        • foo-design.model.ts
        • foo-design.module.ts
        • foo-design.scss
        • foo.interface.ts
      • runtime
        • foo.component.html
        • foo.component.ts
        • foo.scss
        • foo.service.ts 
        • foo.module.ts

      To refactor the deprecated properties, perform the following steps:

      1. (Required) In the -registration.module.ts file from the bundle/src/main/webapp/libs/<your-library-name>/src/lib/view-components/<view-component-name> location, replace the deprecated properties componentFactory and designComponentFactory used in rxViewComponentRegistryService.register() method with component and designComponent properties respectively.

        Example

        Update the following code:

        rxViewComponentRegistryService.register({

        type: RxViewComponentType.Foo,

         componentFactory: this.componentFactoryResolver.resolveComponentFactory(FooComponent),
         designComponentFactory: this.componentFactoryResolver.resolveComponentFactory(FooDesignComponent),

        })

        To

        rxViewComponentRegistryService.register({

        type: RxViewComponentType.Foo,

         component: FooComponent,
        designComponent: FooDesignComponent,

        })
      2. (Required) Convert components to a Standalone style.
        A standalone component is a self-defined component that
         contains all the information required by Angular to create the instance of the component. For more information, see Standalone components.

        Example

        Perform the following tasks on registration.module.ts file, for example foo-registration.module.ts:

        1. Remove the design time and runtime modules from the registration @NgModule. These imports are not required because we will convert the components to standalone.
        2. Convert components to standalone, by adding the property standalone: true to the component declaration.
          Perform this step 
          for both the design time component and the runtime component.

          @Component({
          standalone: true
          })

        With the above changes the component is converted to standalone and can be imported the same way a module is imported.

        Depending on the other Angular elements used by the components further refactoring is required. For example, if the foo component uses the bar and baz components, their modules are currently imported in the component module.ts file. They must be imported in the component itself. 

        For each component (design time and runtime), open the .module.ts file and view the imports section of @NgModule.

        A component could depend from another module, whether it is an Angular dependency (CommonModule), a third party module (BarModule), another non-standalone component (BazModule), or another service if this service is provided by another module (ServiceModule).

        In this case, in the .module.ts we would currently have:

        @NgModule({
          
        imports: [CommonModule, BarModule, BazModule, ServiceModule],

        Declare those modules in the imports section of the standalone component. After refactoring, the following structure is available in the standalone component:

        @Component({
        standalone: true,
        imports:[CommonModule, BarModule, BazModule,
        ServiceModule]
        })

        Remove the .module.ts file for the design time and runtime components.

        Example
        • foo-registration.module.ts
        • design
          • foo-design.component.html
          • foo-design.component.ts
          • foo-design.scss
          • foo.interface.ts
        • runtime
          • foo.component.html
          • foo.component.ts
          • foo.scss
          • foo.service.ts 
      3. Revisit the scope of services used in the components and provide the services at the component level rather than in their module (if the service is not stateless, that is the service is not provided in root). A service can be of the following types:
        1. stateless—These services are used as utility functions. Stateless service can be shared across multiple components and does not have to maintain any state internally, hence must be provided at the root level. For more information about providing all services in the application root, see Singleton services.
          A stateless service is usually provided in root:

          @Injectable({
          providedIn: 'root'
          })

          It is usually directly imported in the components, for example:

          import { TestService } from '../services/test.service';

           

        2. stateful— These services maintain a state of data between a few components and must be provided at the component level.

          Example
          • If a service is stateful (not injectable in root), we would have to import its module (ServiceModule) in a component .module.ts file in the import section of @NgModule:

            @NgModule({
              
            imports: [ServiceModule]

            After refactoring in the standalone component, the service module must be imported in the standalone Component:

            @Component({
            standalone: true,
            imports:[ServiceModule]
            })
          • If the Service does not have a Module (TestService), it would have been defined in the providers section of @NgModule:

            @NgModule({
              
            providers: [TestService],

            After refactoring in the standalone component, the service must be provided in the standalone Component:

            @Component({
            standalone: true,
            providers:[TestService]
            })

          A stateful service is usually not provided in root, and does not need to be imported or provided in a module or component. So no code modification is required.
           

          @Injectable()

          It is usually declared in the @NgModule providers section:

          import { TestService } from '../services/test.service';

          @NgModule({
            providers: [TestService],
  7. Implement decorators for view components, actions, and initializers. To make sure the manifestis generated correctly, you must declare your view components, view actions, and initializers by using the Platform decorators such as  @RxViewComponent(), @RxViewAction(), and @RxApplicationInitializer().

    Warning

    If you do not implement the decorators in your code, the view components, actions, and initializer will not be available in the BMC Helix Innovation Studio. The custom UI elements will not be visible in design time and will not be executed in runtime.  

    • For view components, consider the following points:
      • To use the  @RxViewComponent() decorator, you must import the decorator and decorate the Angular Component.
      • If you have two components for the view component (for example one for design time and one for runtime), decorate only the runtime component.
      • The name property declared in the decorator must have the same value as that of the type declared in the view component registration module.

        Example

        If for the Pizza ordering view component, in the pizza-label-registration.module.ts you have the type property set as rx-pizza-ordering :

        rxViewComponentRegistryService.register({
        type: 'rx-pizza-ordering',
        name: 'Pizza Ordering',
        group: 'Foo',
        component: PizzaOrderingComponent,
        designComponent: PizzaOrderingDesignComponent,
        designComponentModel: PizzaOrderingDesignModel,
        properties: [
        //...
         ]
        });

        Then, in Component /runtime/pizza-label.component.ts you should set the @RxViewComponent name as rx-pizza-ordering:  

        ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​import { Component, OnInit } from '@angular/core';
        import { CommonModule } from '@angular/common';
        import { Observable, throwError } from 'rxjs';
        import { BaseViewComponent, IViewComponent } from '@helix/platform/view/runtime';
        import { RxViewComponent } from '@helix/platform/view/api';
        import { IPizzaOrderingParameters } from '../design/pizza-ordering.interface';

        @Component({
        standalone: true,
        selector: 'rx-pizza-ordering',
        styleUrls: ['./pizza-ordering.scss'],
        templateUrl: './pizza-ordering.component.html',
        imports: [CommonModule]
        })
        @RxViewComponent({
        name: 'rx-pizza-ordering',
        })
        export class PizzaOrderingComponent extends BaseViewComponent implements OnInit,IViewComponent {}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
    • For actions, consider the following points:
      • To use the @RxViewAction() decorator you must import the decorator and decorate the Angular Service.
      • The name property declared in the decorator must be the name property declared in the View Action module.

        Example

        For the foo action, the name defined in the registration module foo-action.service.ts is comExampleBundleFoo:

        import { NgModule } from '@angular/core';
        import { RxViewActionRegistryService } from '@helix/platform/view/api';
        import { FooActionService } from './foo-action.service';
        import { FooActionDesignManagerService } from'./foo-action-design-manager.service';
        import { FooActionDesignModel } from './foo-action-design-model.class';

        @NgModule({
        providers: [FooActionService, FooActionDesignManagerService]
        })
        export class FooActionModule {
        constructor(
        rxViewActionRegistryService: RxViewActionRegistryService,
        fooActionService: FooActionService,
        fooActionDesignManagerService: FooActionDesignManagerService
         ) {
        rxViewActionRegistryService.register({
        name: 'comExampleBundleFoo',
        label: 'Foo',
        service: fooActionService,
        designManager: fooActionDesignManagerService,
        designModel: FooActionDesignModel,
        parameters: [
        //...
         ]
        })
        }
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ 

        Then, in the Service foo-action.service.ts you should set the @RxViewAction name as comExampleBundleFoo

        import { Injectable } from '@angular/core';
        import { IViewActionService } from '@helix/platform/view/api';
        import { Observable } from 'rxjs';
        import { RxViewAction } from '@helix/platform/view/api';
        import { IFooActionProperties } from './foo-action.interface';

        @Injectable()
        @RxViewAction({
        name: 'comExampleBundleFoo',
        })
        export class FooActionService implements IViewActionService<IFooActionProperties, any> {
        execute(inputParameters: IFooActionProperties): Observable<any> {
        //...
         }
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​  

       

    • For initializers, consider the following points:
      • To use the @RxApplicationInitializer() decorator you must import the decorator, and decorate the Angular Service.
      • The applicationId declared in the decorator must be the application name declared in the rxApplicationRegistryService.register() method. 

        Example

        If in the com-example-test210500.module.ts, the  rxApplicationRegistryService.register() method is called with com.example.test210500 as the application name value (first parameter).

        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ NgModule }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@angular/core';
        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ CommonModule }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@angular/common';
        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ RxApplicationRegistryService, RxLocalizationService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@helix/platform/shared/api';
        import * as defaultApplicationStrings from './i18n/localized-strings.json';
        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ LabelRegistrationModule }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './view-components/label/label-registration.module';
        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ComExampleTest210500Initializer }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from './com-example-test210500-initializer.service';

        @NgModule({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          imports: [
            CommonModule,
            LabelRegistrationModule
          ],
          providers: [
            ComExampleTest210500Initializer
          ]
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        export class ComExampleTest210500Module {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          constructor(private rxLocalizationService: RxLocalizationService,
                      private comExampleTest210500Initializer: ComExampleTest210500Initializer,
                      private rxApplicationRegistryService: RxApplicationRegistryService) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            this.rxLocalizationService.setDefaultApplicationStrings(defaultApplicationStrings["default"]);

            this.rxApplicationRegistryService.register('com.example.test210500', this.comExampleTest210500Initializer);
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​  

        Then, in the Service com-example-test210500-initializer.service.ts you must set the @RxApplicationInitializer applicationId as com.example.test210500:

        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ Injectable }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@angular/core';
        import {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ IRxApplicationInitializer, RxLogService }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ from '@helix/platform/shared/api';

        @Injectable()
        @RxApplicationInitializer({​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            applicationId: 'com.example.test210500'
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)
        export class ComExampleTest210500Initializer implements IRxApplicationInitializer {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          constructor(private rxLogService: RxLogService) {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
          initialize(): void {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            this.rxLogService.log('Hi, I am being called in the bundle initializer code :)');
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
  8. Enable the manifest file. 
    manifest is a file that contains the list of view components, view actions, and initializers of the coded bundle. It is leveraged in BMC Helix Innovation Studio to lazy load the resources, only when they are used in a view. You can decide to:
    • Generate the manifest.
      If it is not enabled, the view components and view actions will not be visible or available in BMC Helix Innovation Studio
      .
      We recommend that you generate the manifest. 
    • Always load or lazy load the css styles.
      We recommend that you set the property to lazy
    • Always load or lazy load the javascript code.
      We recommend that you set the property to lazy

      The options for the manifest file generation are at the /bundle/src/main/webapp/package.json location.

      "config": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​              
         "manifest": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​          
           "generate": "true",
           "loadCss": "lazy",<- supports any option from "never" | "always" | "lazy"
           "loadJs": "lazy"  <- supports any option from "never" | "always" | "lazy"
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        }​​​​​​​​​​​​​​​​​​​​

      Enable the manifest file generation, by setting the following property:

      "generate": "true",

      The options loadJs and loadCss control whether the bundle UI elements (js/css) are lazy loaded. Lazy loading the UI elements can help with runtime performances, because the js and CSS files would only be loaded if a UI element is used in a view. 

      Important

      If you are using a global css style, for example to apply a css class on a view UI element such as a Container, you would need to set loadCss to always.

      For example:

      {​​​
       "name": "helix",
       "version": "1.0.0",
       "description": "Foo 22.1.0",
       "main": "Index.html",
       "groupId": "com.example",
       "artifactId": "foo",
       "bundleName": "com.example.foo",
       "author": "BMC Software Inc.",
       "license": "Commercial",
       "config": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​               
         "manifest": {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​           
           "generate": "true",
           "loadCss": "always",<- supports any option from "never" | "always" | "lazy"
           "loadJs": "always"  <- supports any option from "never" | "always" | "lazy"
          }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
        }​​​​​​​​​​​​​​​​​​​​
      }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
  9. If you are leveraging the moment-es6 package, refactor the import to use the moment packages. Refactor the following code:

    import moment from 'moment-es6';

    To

    import * as moment from 'moment';

     

  10. Remove the deprecated tilde (~)  import from scss files. Refactor the code that uses ~ from all the *.scss files from /bundle/src/main/webapp/libs/<custom-bundle-name>/src/lib location. 
    Update the following code:

    @import "~styles/variables";

    To

    @import "styles/variables";
  11. (Optional) Prepare for RxJS 7 upgrade. Refactor the existing use of  RxJS . For more information, see Breaking Changes in Version 7 and RxJS 6.x to 7.x Detailed Change List.

  12. (Optional) Perform this step only if you are running unit test cases.
    Update the unit test configuration.

    For unit tests to work after you upgrade to Angular 14, update the following files.

    • Replace the content of jest.preset.js file from /bundle/src/main/webapp/ directory with the following content:

      const nxPreset = require('@nrwl/jest/preset');
      module.exports = {​​​
        
      ...nxPreset
      }​​​​​​​​​​;
    • Replace the content of jest.config.js file from /bundle/src/main/webapp/libs/com-example-foo location with the following content:

      const {pathsToModuleNameMapper} = require('ts-jest');
      const {compilerOptions} = require('../../tsconfig.base.json');

      module.exports = {
      displayName: 'com-example-foo',
      preset: '../../jest.preset.js',
      coverageDirectory: '../../coverage/libs/com-example-foo',
      snapshotSerializers: [
      'jest-preset-angular/build/serializers/no-ng-attributes',
      'jest-preset-angular/build/serializers/ng-snapshot',
      'jest-preset-angular/build/serializers/html-comment'
      ],

      setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],

      globals: {

      "ts-jest": {
      tsconfig: "<rootDir>/tsconfig.spec.json",
      stringifyContentPathRegex: "\\.(html|svg)$",
      },

      },
      transform: {
      '^.+.(ts|mjs|js|html)$': 'jest-preset-angular'
      },
      moduleNameMapper: Object.assign(
      {
      "^uuid$": "uuid",
      "^lodash-es$": "lodash"
      },
      pathsToModuleNameMapper(compilerOptions.paths, {prefix: '<rootDir>/../../'})
      ),
      testEnvironment: 'jsdom',
      transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
      testRunner: 'jest-jasmine2'
      };

       

    • Replace the content of test.setup.ts file from /bundle/src/main/webapp/libs/com-example-foo/src location with the following content:

      import 'jest-preset-angular/setup-jest';
      import 'jest-extended';
  13. Build, export, and deploy your application project. For example:

    myproj> mvn clean install -Pexport -Pdeploy

     

  14. Verify that your application functions correctly.

Troubleshooting

This section describes the steps to resolve issues that you might encounter when upgrading your applications or libraries from version 22.1.xx.

Build issues while installing dependencies

The following error is displayed when you upgrade your applications or libraries to version 23.3.04 or earlier:

error tmp@0.2.3: The engine "node" is incompatible with this module. Expected version ">=14.14". Got "12.20.1"
To resolve the issue, add 0.2.1 tmp library to the resolutions section.

"resolutions": {
  ...
   "tmp": "0.2.1"
 },

View Component or View Action is not available in the palette

A View component and Action is not visible in BMC Helix Innovation Studio palette or in the button action list, and/or is not executed at runtime. Also an Initializer is not executed at runtime.

To resolve this issue, verify the following points: 

  • A View Component, Action, or Initializer is not visible in BMC Helix Innovation Studio palette or button action list, and is not executed at runtime.
  • The View Component, View Action, and Initializer must be declared in the manifest file. To declare the components, make sure the following tasks are complete:

Build issue with schema validation

When you build a coded bundle and the schema validation fails with the following error:

Data path "" must NOT have additional properties(extractCss).

To resolve the issue, locate and delete the " extractCss": true property in the angular.json file from the bundle/src/main/webapp/ location.

Build issue with browserslist

When you build a coded bundle and the following error is displayed:

./libs/foo/src/lib/styles/foo.scss - Error: Module build failed {from ./node_modules/@angular-devkit/build-angular/node_modules/mii-css-extract-plugin/dist/loader.js}; HookWebpackError: Module build failed {from ./node_modules/@angular-devkit/build-angular/node_modules/postcss-loader/dist/cjs.js};

BrowserlistError: Unknown version 104 of android

To resolve this issue, perform the following steps:

  1. Locate and delete the yarn.lock file from the /bundle/src/main/webapp location.
  2. Run the following command:

    mvn clean install

Build issue with yarn cache

When you build a coded bundle and the following error is displayed:

error an unexpected error occurred: "There should only be one folder in a package cache (got in C:\\Users\\Administrator\\AppDainfog report with the information provided in "C:\\foo\\bundle\\src\\main\\webapp\\yarn-error.log".

To resolve the issue, clear the yarn cache by running the following command:

yarn cache clean

Issues with unit test cases

If the custom application uses third-party libraries defined in the bundle/src/main/webapp/libs/<library-name>/package.json file, and includes unit tests, the following error is displayed during the build:

Error: Need to call TestBed.initTestEnvironment() first

Warning

The following steps are necessary due to an issue with Yarn 1.x. Applying these steps will automatically install Yarn 4.

To resolve the issue, you must enable local yarn by performing the following steps:

  1. Set the environment variable YARN_IGNORE_NODE=1.
  2. Set the enableLocalYarn flag to true in package.json file from /bundle/src/main/webapp/ location.

    "config": {
        "enableLocalYarn": true
      }
  3. Remove the preinstall script from the package.json file from /bundle/src/main/webapp/ location.
  4. Update the build commands in the bundle\pom.xml file.

    Example

    Update the following code:

    <execution>
       <id>run-yarn-install</id>
       <phase>generate-sources</phase>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
           <executable>yarn</executable>
           <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory>
           <arguments>
               <argument>install</argument>
           </arguments>
       </configuration>
    </execution>

    To

    <execution>
       <id>run-pre-install</id>
       <phase>generate-sources</phase>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
           <executable>node</executable>
           <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory>
           <arguments>
               <argument>preinstall.js</argument>
           </arguments>
       </configuration>
    </execution>
    <execution>
       <id>run-yarn-install</id>
       <phase>generate-sources</phase>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
           <executable>yarn</executable>
           <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory>
           <arguments>
               <argument>install</argument>
           </arguments>
       </configuration>
    </execution>
    <execution>
       <id>run-post-install</id>
       <phase>generate-sources</phase>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
           <executable>yarn</executable>
           <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory>
           <arguments>
               <argument>run</argument>
               <argument>postinstall</argument>
           </arguments>
       </configuration>
    </execution>
  5. Exclude the following files from the source control from /bundle/src/main/webapp/ location.
    • .yarn/*
    • !.yarn/releases
  6. Add the following files in the source control:
    • .yarn/releases/yarn-4.0.0.cjs
    • .yarnrc.yml
    • yarn.lock
  7. Delete the node_modules and tools, folders, and the yarn.lock file from the /bundle/src/main/webapp/ location.
  8. Run the following command:
mvn clean install

​​​​​​​

Typescript compilation issues

When you encounter the following issue, replace validationIssue type with IValidationIssue:

Type '"error"' is not assignable to type 'ValidationIssueType'.

Update the following code:

validationIssues.push({
  type: 'error',
  propertyName: issuePropertyName,
  description: `${actionDescriptor.label}
});

To

import { IValidationIssue } from '@helix/platform/ui-kit';

validationIssues.push({
 type:IValidationIssue.Error,
  propertyName: issuePropertyName,
  description: `${actionDescriptor.label}
});