Extending Admin UI

Revision as of 16:03, 12 April 2006 by KevinH (talk | contribs) (Reverted edit of 69.47.209.35, changed back to last version by KevinH)

The API for extending Admin UI is similar to Zimlets. Unlike Zimlets, this API was not originally meant to be published. However people have asked about it, so I decided to document it. The intended audience is developers, who want to add custom modules to Zimra Admin UI, for example, people have asked about integrating Zimbra with samba. If you want to use this API, you need to have at least basic programming skills and be familiar with JavaScript.

The easiest way to understand how to create extensions for Admin UI is by example. So, lets create a sample "Hello World" extension.

The example will add one tab to the Accounts view. The tab will be called "Hello World" and it will have some text.

The extension will consist of two files: helloworld.xml - XML definition of the extention helloworld.js - JavaScript code of the extension helloworld.xml:


   <zimlet name="helloworld" version="1.0" description="Sample Extension for Admin UI" extension="true">
   <include>helloworld.js</include>
   </zimlet>

That's it. It is that short. It defines the name of the extension, description and included JS files. Note, that unlike Zimlet definition files it has a parameter extension="true". This is what tells zimlet utility that this is not a regular Zimlet, but an extension for Admin UI. So, moving forward. helloworld.js


 function HelloWorldExtension() {}
HelloWorldExtension.AccountXFormModifier = function (xFormObject) {
   //find _TAB_BAR_ element
   var cnt = xFormObject.items.length;
   for(i = 0; i <cnt; i++) {
      if(xFormObject.items[i].type=="tab_bar") 
        break;
   }
   //get a tab index
   var myTabIndex = ++ZaAccountXFormView.TAB_INDEX;
   //add a tab
   xFormObject.items[i].choices.push({value:myTabIndex, label:"Hello World"});
   //define a form for my new tab. This ahs to be a _CASE_ element
   
  var myTab = {type:_CASE_, relevant: ("instance[ZaModel.currentTab] == " + myTabIndex),
                items: [{type:_OUTPUT_, label:null, value:"Hello World!"}]};
 
   //find SWITCH element
   for(i = 0; i <cnt; i++) {
     if(xFormObject.items[i].type=="switch") 
       break;
   }
   //add my tab to the form
   xFormObject.items[i].items.push(myTab);
}
ZaTabView.XFormModifiers["ZaAccountXFormView"].push(HelloWorldExtension.AccountXFormModifier);

Now you zip helloworld.xml and helloworld.js into helloworld.zip file and run zmzimletctl deploy helloworld.zip Done!

Some more background: There are two types of views int Admin UI. List views and XForms views.

- List views are ones that show you lists of Zimbra objects. When you click on Accounts node in the navigation tree, you open Accounts List View, when you click on Servers, you open Servers List View, etc

- XForms views are views that show/edit/create a single Zimbra object. When you double click on an account in Accounts List view, you open an Account XForms view, when you click on Classes Of Service->default node, you open a COS XForms View.

Admin extensions allow you to modify anything on an XForms view, including toobar buttons. However, You cannot modify how the lists are shown in List views, in the List views you can only add new toolbar buttons and pop-up menues to List views. From the helloworld you can learn that in order to add anything to an XForms view you need to define your "modifier" method:

HelloWorldExtension.AccountXFormModifier

Then you need to add this method to the map (ZaTabView.XFormModifiers):

ZaTabView.XFormModifiers["ZaAccountXFormView"].push(HelloWorldExtension.AccountXFormModifier);

This statement adds your method to the list of methods that are called when "ZaAccountXFormView" is created. The map ZaTabView.XFormModifiers has the following arrays of methods:

ZaTabView.XFormModifiers["ZaAccountXFormView"] - modifiers for Account view
ZaTabView.XFormModifiers["ZaCosXFormView"] - modifiers for Class of Service view
ZaTabView.XFormModifiers["ZaDLXFormView"] - modifiers for Distribution List view (this is not a list view, its an XForms view for a distributino list)
ZaTabView.XFormModifiers["ZaDomainXFormView"] - modifiers for Domain view
ZaTabView.XFormModifiers["GlobalConfigXFormView"] - modifiers for Global Settings view
ZaTabView.XFormModifiers["ZaServerXFormView"] - modifiers for Server view

xFormObject argument which is passed to your modifier function (HelloWorldExtension.AccountXFormModifier in the example) will normally look like this:


/** you can take a look at files ZaDomainXFormView.js, ZaAccountXFormView.js, GlobalConfigXFormView.js etc, to see how each 
* xFormObject looks for each view. You will want to look at myXFormModifier methods in each of these classes 
**/
{
 tableCssStyle:"width:100%;overflow:auto",
 items:[
    {type:_GROUP_, cssClass:"ZmSelectedHeaderBg", colSpan:"*", /* this defines the top element of the form, a header */
        items: [
            {type:_GROUP_, numCols:4, colSizes:["32px","350px","100px","250px"],
                 items: [
                    {type:_AJX_IMAGE_, src:"Domain_32", label:null},
                    {type:_OUTPUT_, ref:ZaDomain.A_domainName, label:null,cssClass:"AdminTitle", rowSpan:2},			
                    {type:_OUTPUT_, ref:ZaItem.A_zimbraId, label:ZaMsg.NAD_ZimbraID}
                 ]
        ]
    },
    {type:_TAB_BAR_,  ref:ZaModel.currentTab, /* this defines the tab bar */
         choices:[ /* this array defines the buttons in the tab bar */
             {value:1, label:ZaMsg.Domain_Tab_General}, /* each button in the tab bar is defined as an object that has "value" and "label" */
             {value:2, label:ZaMsg.Domain_Tab_GAL},
             {value:3, label:ZaMsg.Domain_Tab_Authentication}
        ],cssClass:"ZaTabBar"
    },
    {type:_SWITCH_, /* this object contains all the "tabs" */
       items:[
          {type:_CASE_, relevant:"instance[ZaModel.currentTab] == 1", /* _CASE_ object defines a single tab */
              items:[ /* form elements for the first tab ar defined here */
          },
          {type:_CASE_, relevant:"instance[ZaModel.currentTab] == 2", 
              items:[ /* form elements for the second tab ar defined here */
          }
       ]
    }
 ]
}

"helloworld" was very simple, however totally disfunctional :) In real life you will probably want your extension to take some input from users, communicate to server and display meaningful data. So, lets start with sending/receiving data from the server. We want to be able to call some URL with some parameters every time a Zimbra user is created. We will continue with Helloworld extension: helloworld.js


HelloWorldExtension.createSambaAccount = function (tmpObj, account, app) {
    /** this method is called after zimbra account is created. account argument is an instande of ZaAccount class 
    * and has all the information about a zimbra account 
    **/
    var url = ["https://localhost/mysambaWebService.php?action=createUser&username=",account.name, "&zimbraId=",account.id,
            "&email=",account.attrs[ZaAccount.A_mailDeliveryAddress]].join("");
    var result=AjxRpc.invoke(null, url, null, null, true);
}
ZaItem.createMethods["ZaAccount"].push(HelloWorldExtension.createSambaAccount);

Similar to ZaTabView.XFormModifiers, there is a map ZaItem.createMethods that holds references to methods that are called when objects are created. Right now, this map has entries only for ZaAccount object, but I will add more entries for all other objects.

ZaItem.createMethods["ZaAccount"]

Besides, createMethods, there are also methods that are called, when an object is modified. Also, currently there is only one entry in that map:

ZaItem.modifyMethods["ZaAccount"]

Modify method is applied to the instance of the object being modified. The statement that calls functions in modifyMethods is ZaItem.modifyMethods[key][i].call(this, mods), where mods is a map of modified attributes. At this point, I recommend looking at ZaItem.js and ZaAccount.js for more details on this, untill there is a better documentation (which hopefully will happen soon).

Jump to: navigation, search