Difference between revisions of "Extending Admin UI"

Line 1: Line 1:
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 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
 
 
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).
 

Revision as of 15:02, 26 March 2006

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

Jump to: navigation, search