License Editor

../../../../_images/step-project1.png ../../../../_images/step-meta1.png ../../../../_images/step-provision1.png ../../../../_images/step-presentation-b.png ../../../../_images/step-deploy1.png ../../../../_images/step-provisioning1.png

In this document, we will define a license editor that enables the provider to edit an existing license.

../../../../_images/step-presentation-licenses.png ../../../../_images/step-presentation-license-new.png ../../../../_images/step-presentation-license-edit-b.png ../../../../_images/step-presentation-services.png

In this document:

Overview

When editing a license APS resource, the provider must be able to select one or more scopes to be assigned to that license. All possible scopes are specified in the ui/newlicense.json file created earlier.

The license-edit view will be called from the licenses view when a user clicks on a license name. From the navigation variable license declared in the metadata, the view must get the JSON representation of the license to edit . A JavaScript code in ui/license-edit.html must perform the following operations:

  • Presents all allowed scopes stored in the ui/newlicense.json file as a list of checkboxes. Boxes with already selected scopes in the license must be checked. The user can check and clean the boxes as required.

  • When a user clicks Cancel, the view directs the user back to the licenses view. On Submit click, the editor saves the edited license and then directs the user to the licenses view.

Development

The development of this view is similar to the development of the license creation wizard. With some modifications, you can even combine both views in one HTML file.

When creating the ui/license-edit.html file from the project template (as in our case), keep in mind the Typical Structure of View File and follow these steps.

  1. Ensure the require list contains all JavaScript modules that the main callback function will need:

    require([
          "dijit/registry",
          "dojo/when",
          "dojox/mvc/getPlainValue",
          "dojox/mvc/at",
          "dojox/mvc/getStateful",
          "aps/ResourceStore",
          "aps/load",
          "aps/CheckBox",
          "aps/json!./newlicense.json",
          "./displayError.js",
          "aps/ready!"
       ], function (
          registry,
          when,
          getPlainValue,
          at,
          getStateful,
          Store,
          load,
          CheckBox,
          newLicense,
          displayError
       ) {
          // .. To be continued in the next steps ..
    
    });
    
  2. In the main callback function, declare the license store that will interact with the APS controller and the license model that will interact with the widgets:

    /* Declare data sources */
    var licenseStore = new Store({
       apsType:    "http://aps-standard.org/samples/github/license/1.0",
       target:     "/aps/2/resources/"
    });
    /* Get the current license from the navigation variable declared in metadata */
    var licenseModel = getStateful(aps.context.vars.license);
    

    Key:

    • We will need the license store to save the new license on commit.

    • The license model is created with the properties pre-filled from the license opened for editing.

  3. Split the view into two widget groups: one presents the license name and description and the other dynamically builds a list of scopes to be chosen for the new license:

    var widgets = ["aps/PageContainer", {id: "page"}, [
       ["aps/Panel", [
           ["aps/FieldSet", {id: "licenseEdit_general", title: true}, [
               ["aps/TextBox", {
                   id: "licenseEdit_licenseName",
                   label: "License Name",
                   value: at(licenseModel, "name"),
                   required: true
               }],
               ["aps/TextBox", {
                   id: "licenseEdit_description",
                   label: "Description",
                   value: at(licenseModel, "description")
               }]
           ]]
       ]],
       ["aps/Panel", [
           ["aps/FieldSet", {id: "licenseEdit_props", title: true}]
       ]]
    ]];
    

    Key:

    • The general properties are displayed by text boxes synced with the license model.

    • The second widget group will be filled out dynamically in the next step after the whole widget structure is loaded.

  4. Use the asynchronous load->then->otherwise chain to load the widgets and then fill out the second widget group dynamically with checkboxes, each corresponding to a scope specified in the license model.

    load(widgets).then(function() {
       /* Add checkboxes, one per each scope defined in the newLicense default model */
       var scopes = newLicense.scopes;
       var fieldSet = registry.byId("licenseEdit_props");
       scopes.forEach(function(scope) {
           var checked = licenseModel.get("scopes").includes(scope);
           fieldSet.addChild( new CheckBox({
               checked: checked,
               value: scope,
               label: scope
           }));
    
       });
    
       /* Create here handlers for the navigation buttons in the next steps*/
       // ... handlers ...
    
    }).otherwise(displayError);
    
  5. The navigation buttons “Cancel” and “Submit” for the view are declared in APP-meta.xml. Continue development of the load->then->otherwise chain with the definition of the handlers of those navigation buttons:

    aps.app.onCancel = function() {
        aps.apsc.gotoView("licenses");
    };
    
    aps.app.onSubmit = function() {
        var page = registry.byId("page");
        if (!page.validate()) {
           aps.apsc.cancelProcessing();
           return;
        }
           var boxes = registry.byId("licenseEdit_props").getChildren();
           var scopes = [];
           boxes.forEach(function(box) {
               if (box.checked) scopes.push(box.value);
           });
           licenseModel.set("scopes", scopes);
           var payload = getPlainValue(licenseModel);
        when(licenseStore.put(payload),
           function(){
                aps.apsc.gotoView("licenses");
              },
           displayError
        );
    };
    

    Key:

    • The onCancel handler returns the user to the main service view.

    • The onSubmit handler firstly validates the entered values, then collects the selected checkboxes (scopes) in the license model, and finally sends a request to the APS controller to save the license model as a new license APS resource. After that is done, the user is returned back to the main service view.

Conclusion

Following the instructions in this document you have created a simple resource editor that the provider can use to fix or update a license.

The view source HTML file you have created should be similar to the sample license-edit.html file:

<!DOCTYPE html>
<html>
<head>
<script src="/aps/2/ui/runtime/client/aps/aps.js"></script>
<script>
require([
       "dijit/registry",
       "dojo/when",
       "dojox/mvc/getPlainValue",
       "dojox/mvc/at",
       "dojox/mvc/getStateful",
       "aps/ResourceStore",
       "aps/load",
       "aps/CheckBox",
       "aps/json!./newlicense.json",
       "./displayError.js",
       "aps/ready!"	],
   function (
      registry,
      when,
      getPlainValue,
      at,
      getStateful,
      Store,
      load,
      CheckBox,
      newLicense,
      displayError
   ) {
      /* Declare data sources */
      var licenseStore = new Store({
         apsType:    "http://aps-standard.org/samples/github/license/1.0",
         target:     "/aps/2/resources/"
      });
      /* Get the current license from the navigation variable declared in metadata */
      var licenseModel = getStateful(aps.context.vars.license);

		/* Define and load the widgets */
      var widgets = ["aps/PageContainer", {id: "page"}, [
         ["aps/Panel", [
            ["aps/FieldSet", {id: "licenseEdit_general", title: true}, [
               ["aps/TextBox", {
                  id: "licenseEdit_licenseName",
                  label: "License Name",
                  value: at(licenseModel, "name"),
                  required: true
               }],
               ["aps/TextBox", {
                  id: "licenseEdit_description",
                  label: "Description",
                  value: at(licenseModel, "description")
               }]
            ]]
         ]],
         ["aps/Panel", [
            ["aps/FieldSet", {id: "licenseEdit_props", title: true}]
         ]]
      ]];
      load(widgets).then(function() {
         /* Add checkboxes, one per each scope defined in the newLicense default model */
         var scopes = newLicense.scopes;
         var fieldSet = registry.byId("licenseEdit_props");
         scopes.forEach(function(scope) {
            var checked = licenseModel.get("scopes").includes(scope);
            fieldSet.addChild( new CheckBox({
               checked: checked,
               value: scope,
               label: scope
            }));

         });

         /* Create here handlers for the navigation buttons */
         aps.app.onCancel = function() {
            aps.apsc.gotoView("licenses");
         };

         aps.app.onSubmit = function() {
            var page = registry.byId("page");
            if (!page.validate()) {
               aps.apsc.cancelProcessing();
               return;
            }
            var boxes = registry.byId("licenseEdit_props").getChildren();
            var scopes = [];
            boxes.forEach(function(box) {
               if (box.checked) scopes.push(box.value);
            });
            licenseModel.set("scopes", scopes);
            var payload = getPlainValue(licenseModel);
            when(licenseStore.put(payload),
               function(){
                  aps.apsc.gotoView("licenses");
               },
               displayError
            );
         };
      }).otherwise(displayError);
});
</script>
</head>
<body>
</body>
</html>