Skip to content

Webresources

Peter McDonald edited this page May 22, 2023 · 9 revisions

Dataverse Webresources

Dataverse powertools has a number of features to assist with the management of web resources in Dataverse. These features include:

  • Creating and updating web resources as TypeScript
  • Building the TypeScript into a common JavaScript library
  • Deploying the web resources to Dataverse using spkl
  • Generating TS Typings for Dataverse Web API and FormContext using XRMDefinitelyTyped
  • Jest Tests utilising Xrm-Mock for dataverse fakes.

Table of Contents

Getting Started

To get started with Web Resources, you will need to initialise your project. This can be done by selecting Initialize Project from the command palette or side bar. This will create a instance of the Web Resources template, restore dependencies and create a new TypeScript class called class.ts. The following options will now be available in the command palette or side bar:
Web Resources Menu

Restore Dependencies

This option will restore the local dependencies onto your PC. This is done for you automatically as part of the Initialize Project command. However it will be needed if you add additional dependencies to your project or if you are working on a project that has been cloned from a repository.

Generate Typings

To generate typings for the Web API and FormContext, select Generate Typings from the command palette or side bar. This will create a new folder called typings and add the typings to this folder. Note: This will need to be done each time a new field is added to the form or the underlying schema changes.

Creating new TypeScript Class

To create a new TypeScript class, right click on the webresources_src folder and select Dataverse Powertools: Create Web Resources Class.

Create Web Resources Classs

Visual Studio Code will then ask you for the name of the new class, the dataverse table and the form in which this TypeScript will run.

Note: It will also update the library.ts file with a reference to the new class so that WebPack will include it in the build.

A sample of a new class file configured for the Account table and Information form is below:

export class Account {
  static async OnLoad(executionContext: Xrm.ExecutionContext<unknown, unknown>): Promise<void> {
    const form = <Form.account.Main.Information>executionContext.getFormContext();
    console.log(form.ui.setFormNotification("Loaded", "INFO", "demoid"));

    this.BindEvents(form);
    this.OnLoadLogic(form);
  }

  static async OnLoadLogic(form: Form.account.Main.Information) {
    switch (form.ui.getFormType().valueOf()) {
      case Xrm.FormType.Create:
        // Add logic to run on new records
        break;
      case Xrm.FormType.Update:
        // Add logic to run on existing records
        break;
    }
    // add OnLoad logic here
  }

  static async BindEvents(form: Form.account.Main.Information) {
    form.data.entity.addOnSave(() => this.OnSave(form));
    //Add Bind events here
  }

  static async OnSave(executionContext: Form.account.Main.Information) {
    //Add On Save logic here
  }
}

The OnLoad static will be called when the form loads. The OnLoadLogic method is called from the OnLoad method and is used to separate the logic that runs on new and existing records. The BindEvents method is used to bind events to the form. The OnSave method is called when the form is saved.

The executionContext parameter is cast as Xrm.ExecutionContext, this allows for TypeScript and Intelisense to be aware of the properties and funtions available to the executionContext. Similarly, the form parameter is cast as Form.account.Main.Information to allow for TypeScript and Intelisense to be aware of the properties and functions available to the form including knowing which fields of which datatypes have been added to the form.

Building the TypeScript

Depending on the method of compilation, the TypeScript will be compiled into JavaScript in one of two ways:

Local compilation

When you run the Build Web Resources or the Build & Deploy Web Resources function from within the extension, the TypeScript is compiled into a JavaScript file called prefix_bundle.js where prefix is the prefix of the Dataverse solution. During compilation, webpack will bundle all the classes into a single file.

Additionally, the TypeScript will be added to the output as a sourcemap. This allows you to debug the TypeScript in the browser.

Pipeline compilation

When you build the TypeScript via the Azure DevOps release pipeline, or locallaly in release mode, the TypeScript is compiled into the same bundle.js file as above. However, the sourcemap is not included in the output and the TypeScript undergoes treeshaking to remove any unused code as well as minification to reduce the size of the output. More information is available in the Build Pipleline section below.

Calling the TypeScript from a form

To execute the OnLoad function from Dataverse you will need to add a web resource to the form. The web resource should be configured as follows:

  • Name: prefix_bundle.js
  • Function: prefix.ClassName.OnLoad
    Note: The prefix is the prefix of the Dataverse solution and ClassName is the name of the class you created above.

Web Resource

Debugging the TypeScript

Thanks to the sourcemaps you can debug the original TypeScript from within your browser when running in debug mode. To do this, open the developer tools in your browser and navigate to the sources tab. You should see the TypeScript files in the list of sources. You can then set breakpoints and step through the code as you would with any other TypeScript or JavaScript file.

Debugging

Note in the above image that the id-xxx (blank.htm) folder will be different in your environment and the dor folder will be the prefix of your solution.

Tests

This extension utilised Jest as the testing framework. To run the tests, select Run Tests from the command palette or side bar. This will run the tests in watch mode, meaning that any changes to the tests or the code will cause the tests to be re-run.

Additionally, the extesion uses Xrm-mock as a fake implementation of the Dataverse API to allow yoo to test your webresources locally.

Tests will also be run during the build pipeline and will provide a coverage report and prevent builds being published with failed tests.

To create a new TypeScript class, right click on the webresources_src folder and select Dataverse Powertools: Create New Test.

A sample test is shown below:

import { Account } from "../Account";
import { XrmMockGenerator } from "xrm-mock";

XrmMockGenerator.initialise();
XrmMockGenerator.Attribute.createString("someattribute", "somevalue");
const form = XrmMockGenerator.eventContext.getFormContext() as Form.account.Main.Information;
Account.OnLoad(XrmMockGenerator.eventContext);

it("should be the same value", () => {
  expect(form.getAttribute("someattribute").getValue()).toBe("somevalue");
});

XRMQuery

In addition to providing Typing files for the Dataverse forms, Dataverse Powertools also provides a wrapper for the Web API called XRMQuery. XRMQuery is a fluent API that allows you to write queries in a more readable way. For example, the following query:

let accounts = await XrmQuery.retrieveMultiple(x => x.accounts) // Tells XrmQuery to retrieve accounts
    .select(x => [ x.accountnumber ]) // Select which attributes to retrieve, this case just accountnumber
    .filter(x => Filter.equals(x.name, "Contoso")) // Only get accounts which have a name equal to "Contoso"
    .promise()

// Do something with the retrieved accounts
console.dir(accounts);

See more information about XrmQuery on the XreDefinitelyTyped wiki.

Note: To ensure XrmQuery works correctly, this extension will upload the dependencies to Dataverse. You will need to ensure the dependencies are added to forms where they are requred.

Build Pipeline

Setup Connection String Variable

Configure a variable group to store the credentials for the Dataverse environment. To do this, navigate to the project settings and select Variable Groups under Pipelines. Select + Variable Group and give the group the name DevEnv.

Add a variable called ConnectionString with the value of the connection string for the Dataverse environment. Note: The connection string should be in the format:

AuthType=ClientSecret;Url=https://<orgname>.crm.dynamics.com;ClientId=<clientid>;ClientSecret=<clientsecret>;

Once the variable group has been created, configure the permissions (7) so that either the web resources pipeline or all pipelines have access to these variables.

Create DevOps Variables

Create Pipeline

Create the build pipleine from the templated azure-pipelines.yml file in the root of the repository. This should be the same process as show in the solutions page under Create a pipeline.

Once the pipeline has been configured it will output the following artifacts:

Artifacts

The prefiX_library.js will now be the release version of the webresource that can be included into the managed solution release (minified and treeshaked). The build pipeline for the solution can download this JavaScript file and use it to replace the debug version in the managed solution artifact and ready for release into upstream environments.

Test Results and Code Coverage

Tests and Code Coverage tabs will be available within DevOps after the build pipeline has run, see examples of the output below:

Test Results Code Coverage Code Coverage Detaild

Clone this wiki locally