cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jtomec...@apache.org
Subject git commit: updated refs/heads/master to 75041b9
Date Thu, 29 Aug 2013 00:02:17 GMT
Updated Branches:
  refs/heads/master f002b8e76 -> 75041b9c5


CLOUDSTACK-883. DOC. How to integrate your 3rd-party plugin with the UI. Contains brief third-party
plugin code tutorial.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/75041b9c
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/75041b9c
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/75041b9c

Branch: refs/heads/master
Commit: 75041b9c55e536eb0a0020f983ec750df4af8832
Parents: f002b8e
Author: Jessica <jessica.tomechak@citrix.com>
Authored: Wed Aug 28 17:01:30 2013 -0700
Committer: Jessica <jessica.tomechak@citrix.com>
Committed: Wed Aug 28 17:01:30 2013 -0700

----------------------------------------------------------------------
 docs/en-US/Developers_Guide.xml      |   1 +
 docs/en-US/images/plugin1.jpg        | Bin 0 -> 32999 bytes
 docs/en-US/images/plugin2.jpg        | Bin 0 -> 35149 bytes
 docs/en-US/images/plugin3.jpg        | Bin 0 -> 41983 bytes
 docs/en-US/images/plugin4.jpg        | Bin 0 -> 32125 bytes
 docs/en-US/images/plugin_intro.jpg   | Bin 0 -> 22247 bytes
 docs/en-US/third-party-ui-plugin.xml | 347 ++++++++++++++++++++++++++++++
 7 files changed, 348 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/Developers_Guide.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Developers_Guide.xml b/docs/en-US/Developers_Guide.xml
index e6fb5ce..7452e29 100644
--- a/docs/en-US/Developers_Guide.xml
+++ b/docs/en-US/Developers_Guide.xml
@@ -51,6 +51,7 @@
     <xi:include href="api-calls.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
     <xi:include href="working-with-usage-data.xml" xmlns:xi="http://www.w3.org/2001/XInclude"
/>
     <xi:include href="storage-plugins.xml" xmlns:xi="http://www.w3.org/2001/XInclude"
/>
+    <xi:include href="third-party-ui-plugin.xml" xmlns:xi="http://www.w3.org/2001/XInclude"
/>
     <xi:include href="working-with-documentation.xml" xmlns:xi="http://www.w3.org/2001/XInclude"
/>
     <xi:include href="tools.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
     <xi:include href="event-types.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/images/plugin1.jpg
----------------------------------------------------------------------
diff --git a/docs/en-US/images/plugin1.jpg b/docs/en-US/images/plugin1.jpg
new file mode 100644
index 0000000..970233d
Binary files /dev/null and b/docs/en-US/images/plugin1.jpg differ

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/images/plugin2.jpg
----------------------------------------------------------------------
diff --git a/docs/en-US/images/plugin2.jpg b/docs/en-US/images/plugin2.jpg
new file mode 100644
index 0000000..9c8a610
Binary files /dev/null and b/docs/en-US/images/plugin2.jpg differ

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/images/plugin3.jpg
----------------------------------------------------------------------
diff --git a/docs/en-US/images/plugin3.jpg b/docs/en-US/images/plugin3.jpg
new file mode 100644
index 0000000..07fae79
Binary files /dev/null and b/docs/en-US/images/plugin3.jpg differ

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/images/plugin4.jpg
----------------------------------------------------------------------
diff --git a/docs/en-US/images/plugin4.jpg b/docs/en-US/images/plugin4.jpg
new file mode 100644
index 0000000..2bcec9f
Binary files /dev/null and b/docs/en-US/images/plugin4.jpg differ

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/images/plugin_intro.jpg
----------------------------------------------------------------------
diff --git a/docs/en-US/images/plugin_intro.jpg b/docs/en-US/images/plugin_intro.jpg
new file mode 100644
index 0000000..113ffb3
Binary files /dev/null and b/docs/en-US/images/plugin_intro.jpg differ

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/75041b9c/docs/en-US/third-party-ui-plugin.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/third-party-ui-plugin.xml b/docs/en-US/third-party-ui-plugin.xml
new file mode 100644
index 0000000..62ee485
--- /dev/null
+++ b/docs/en-US/third-party-ui-plugin.xml
@@ -0,0 +1,347 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "file:///C:/Program%20Files%20(x86)/Publican/DocBook_DTD/docbookx.dtd"
[
+<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
+%BOOK_ENTITIES;
+]>
+   <chapter id="third-party-ui-plugin">
+      <!-- CS-17459 -->
+      <title>Third-Party UI Plugin Framework</title>
+      <para>Using the new third-party plugin framework, you can write and install extensions
to
+        &PRODUCT;. The installed and enabled plugins will appear in the UI alongside
the
+        other features.
+        The code for the plugin is simply placed in a special directory
+        within &PRODUCT;’s installed code at any time after &PRODUCT; installation.
The new plugin
+        appears only when it is enabled by the cloud administrator.</para>
+     <mediaobject>
+       <imageobject>
+         <imagedata fileref="./images/plugin_intro.jpg"/>
+       </imageobject>
+       <textobject>
+         <phrase>plugin_intro.jpg: New plugin button in product navbar</phrase>
+       </textobject>
+     </mediaobject>
+     <para>The left navigation bar of the &PRODUCT; UI has a new Plugins button
to help you work with UI plugins.</para>
+      <section id="plugin-howto-overview">
+        <title>How to Write a Plugin: Overview</title>
+        <para>The basic procedure for writing a plugin is:</para>
+        <orderedlist>
+          <listitem>
+            <para>Write the code and create the other files needed. You will need the
plugin code
+              itself (in Javascript), a thumbnail image, the plugin listing, and a CSS file.</para>
+            <mediaobject>
+              <imageobject>
+                <imagedata fileref="./images/plugin1.jpg"/>
+              </imageobject>
+              <textobject>
+                <phrase>plugin1.jpg: Write the plugin code</phrase>
+              </textobject>
+            </mediaobject>
+            <para>All UI plugins have the following set of files:</para>
+            <programlisting>+-- cloudstack/
+  +-- ui/
+    +-- plugins/
+      +-- csMyFirstPlugin/
+        +-- config.js            --> Plugin metadata (title, author, vendor URL, etc.)
+        +-- icon.png             --> Icon, shown on side nav bar and plugin listing
+                                     (should be square, and ~50x50px)
+        +-- csMyFirstPlugin.css  --> CSS file, loaded automatically when plugin loads
+        +-- csMyFirstPlugin.js   --> Main JS file, containing plugin code            
 
+            </programlisting>
+            <para>The same files must also be present at /tomcat/webapps/client/plugins.</para>
+          </listitem>
+          <listitem>
+            <para>The &PRODUCT; administrator adds the folder containing your plugin
code under the
+              &PRODUCT; PLUGINS folder.</para>
+            <mediaobject>
+              <imageobject>
+                <imagedata fileref="./images/plugin2.jpg"/>
+              </imageobject>
+              <textobject>
+                <phrase>plugin2.jpg: The plugin code is placed in the PLUGINS folder</phrase>
+              </textobject>
+            </mediaobject>
+          </listitem>
+          <listitem>
+            <para>The administrator also adds the name of your plugin to the plugin.js
file in the
+              PLUGINS folder.</para>
+            <mediaobject>
+              <imageobject>
+                <imagedata fileref="./images/plugin3.jpg"/>
+              </imageobject>
+              <textobject>
+                <phrase>plugin3.jpg: The plugin name is added to plugin.js in the PLUGINS
+                  folder</phrase>
+              </textobject>
+            </mediaobject>
+          </listitem>
+          <listitem>
+            <para>The next time the user refreshes the UI in the browser, your plugin
will appear in
+              the left navigation bar.</para>
+            <mediaobject>
+              <imageobject>
+                <imagedata fileref="./images/plugin4.jpg"/>
+              </imageobject>
+              <textobject>
+                <phrase>plugin4.jpg: The plugin appears in the UI</phrase>
+              </textobject>
+            </mediaobject>
+          </listitem>
+        </orderedlist>
+      </section>
+      <section id="plugin-howto-details">
+        <title>How to Write a Plugin: Implementation Details</title>
+        <para>This section requires an understanding of JavaScript and the &PRODUCT;
API. You don't
+          need knowledge of specific frameworks for this tutorial (jQuery, etc.), since the
+          &PRODUCT; UI handles the front-end rendering for you.</para>
+        <para>There is much more to the &PRODUCT; UI framework than can be described
here. The UI is
+          very flexible to handle many use cases, so there are countless options and variations.
The
+          best reference right now is to read the existing code for the main UI, which is
in the /ui
+          folder. Plugins are written in a very similar way to the main UI.</para>
+        <orderedlist>
+          <listitem>
+            <para><emphasis role="bold">Create the directory to hold your plugin.</emphasis></para>
+            <para>All plugins are composed of set of required files in the directory
+              /ui/plugins/pluginID, where pluginID is a short name for your plugin. It's
recommended
+              that you prefix your folder name (for example, bfMyPlugin) to avoid naming
conflicts
+              with other people's plugins.</para>
+            <para>In this example, the plugin is named csMyFirstPlugin.</para>
+            <programlisting>$ cd cloudstack/ui/plugins
+$ mkdir csMyFirstPlugin
+$ ls -l
+
+total 8
+drwxr-xr-x  2 bgregory  staff   68 Feb 11 14:44 csMyFirstPlugin
+-rw-r--r--  1 bgregory  staff  101 Feb 11 14:26 plugins.js
+          </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Change to your new plugin directory.</emphasis></para>
+            <programlisting>$ cd csMyFirstPlugin
+            </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Set up the listing.</emphasis></para>
+            <para>Add the file config.js, using your favorite editor.</para>
+            <programlisting>$ vi config.js</programlisting>
+            <para>Add the following content to config.js. This information will be
displayed on the
+              plugin listing page in the UI:</para>
+            <programlisting>(function (cloudStack) {
+  cloudStack.plugins.csMyFirstPlugin.config = {
+    title: 'My first plugin',
+    desc: 'Tutorial plugin',
+    externalLink: 'http://www.cloudstack.org/',
+    authorName: 'Test Plugin Developer',
+    authorEmail: 'plugin.developer@example.com'
+  };
+}(cloudStack));            
+          </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Add a new main section.</emphasis></para>
+            <para>Add the file csMyFirstPlugin.js, using your favorite editor.</para>
+            <programlisting>$ vi csMyFirstPlugin.js</programlisting>
+            <para>Add the following content to csMyFirstPlugin.js:</para>
+            <programlisting>(function (cloudStack) {
+  cloudStack.plugins.csMyFirstPlugin = function(plugin) {
+    plugin.ui.addSection({
+      id: 'csMyFirstPlugin',
+      title: 'My Plugin',
+      preFilter: function(args) {
+        return isAdmin();
+      },
+      show: function() {
+        return $('&lt;div&gt;').html('Content will go here');
+      }
+    });
+  };
+}(cloudStack));            
+          </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Register the plugin.</emphasis></para>
+            <para>You now have the minimal content needed to run the plugin, so you
can activate the
+              plugin in the UI by adding it to plugins.js. First, edit the file:</para>
+            <programlisting>$ cd cloudstack/ui/plugins
+$ vi plugins.js              
+            </programlisting>
+            <para>Now add the following to plugins.js:</para>
+            <programlisting>(function($, cloudStack) {
+  cloudStack.plugins = [
+    'csMyFirstPlugin'
+  ];
+}(jQuery, cloudStack));            
+          </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Check the plugin in the UI.</emphasis></para>
+            <para>First, copy all the plugin code that you have created so far to
+              /tomcat/webapps/client/plugins. Then refresh the browser and click Plugins
in the side
+              navigation bar. You should see your new plugin.</para>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Make the plugin do something.</emphasis></para>
+            <para>Right now, you just have placeholder content in the new plugin. It's
time to add
+              real code. In this example, you will write a basic list view, which renders
data from
+              an API call. You will list all virtual machines owned by the logged-in user.
To do
+              this, replace the 'show' function in the plugin code with a 'listView' block,
+              containing the required syntax for a list view. To get the data, use the
+              listVirtualMachines API call. Without any parameters, it will return VMs only
for your
+              active user. Use the provided 'apiCall' helper method to handle the server
call. Of
+              course, you are free to use any other method for making the AJAX call (for
example,
+              jQuery's $.ajax method).</para>
+            <para>First, open your plugin's JavaScript source file in your favorite
editor:</para>
+            <programlisting>$ cd csMyFirstPlugin
+$ vi csMyFirstPlugin.js              
+            </programlisting>
+            <para>Add the following code in csMyFirstPlugin.js:</para>
+            <programlisting>(function (cloudStack) {
+  cloudStack.plugins.csMyFirstPlugin = function(plugin) {
+    plugin.ui.addSection({
+      id: 'csMyFirstPlugin',
+      title: 'My Plugin',
+      preFilter: function(args) {
+        return isAdmin();
+      },
+
+      // Render page as a list view
+      listView: {
+        id: 'testPluginInstances',
+        fields: {
+          name: { label: 'label.name' },
+          instancename: { label: 'label.internal.name' },
+          displayname: { label: 'label.display.name' },
+          zonename: { label: 'label.zone.name' }
+        },
+        dataProvider: function(args) {
+          // API calls go here, to retrive the data asynchronously
+          //
+          // On successful retrieval, call
+          // args.response.success({ data: [data array] });
+          plugin.ui.apiCall('listVirtualMachines', {
+            success: function(json) {
+              var vms = json.listvirtualmachinesresponse.virtualmachine;
+
+              args.response.success({ data: vms });
+            },
+            error: function(errorMessage) {
+              args.response.error(errorMessage)
+            }
+          });
+        }
+      }
+    });
+  };
+}(cloudStack));            
+          </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Test the plugin.</emphasis></para>
+            <para>First, copy all the plugin code that you have created so far to
+              /tomcat/webapps/client/plugins. Then refresh the browser. You can see that
your
+              placeholder content was replaced with a list table, containing 4 columns of
virtual
+              machine data.</para>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Add an action button.</emphasis></para>
+            <para>Let's add an action button to the list view, which will reboot the
VM. To do this,
+              add an actions block under listView. After specifying the correct format, the
actions
+              will appear automatically to the right of each row of data.</para>
+            <programlisting>$ vi csMyFirstPlugin.js              
+            </programlisting>
+            <para>Now add the following new code in csMyFirstPlugin.js. (The dots ...
show where we
+              have omitted some existing code for the sake of space. Don't actually cut and
paste
+              that part):</para>
+            <programlisting>...
+      listView: {
+        id: 'testPluginInstances',
+        ...
+
+        actions: {
+          // The key/ID you specify here will determine what icon is
+          // shown in the UI for this action,
+          // and will be added as a CSS class to the action's element
+          // (i.e., '.action.restart')
+          //
+          // -- here, 'restart' is a predefined name in &PRODUCT; that will
+          // automatically show a 'reboot' arrow as an icon;
+          // this can be changed in csMyFirstPlugin.css
+          restart: {
+            label: 'Restart VM',
+            messages: {
+              confirm: function() { return 'Are you sure you want to restart this VM?' },
+              notification: function() { return 'Rebooted VM' }
+            },
+            action: function(args) {
+              // Get the instance object of the selected row from context
+              //
+              // -- all currently loaded state is stored in 'context' as objects,
+              //    such as the selected list view row, 
+              //    the selected section, and active user
+              //
+              // -- for list view actions, the object's key will be the same as
+              //    listView.id, specified above;
+              //    always make sure you specify an 'id' for the listView,
+              //     or else it will be 'undefined!'
+              var instance = args.context.testPluginInstances[0];
+
+              plugin.ui.apiCall('rebootVirtualMachine', {
+                // These will be appended to the API request
+                //
+                // i.e., rebootVirtualMachine&amp;id=...
+                data: {
+                  id: instance.id
+                },
+                success: function(json) {
+                  args.response.success({
+                    // This is an async job, so success here only indicates
+                    // that the job was initiated.
+                    //
+                    // To pass the job ID to the notification UI
+                    // (for checking to see when action is completed),
+                    // '_custom: { jobID: ... }' needs to always be passed on success,
+                    // in the same format as below
+                    _custom: { jobId: json.rebootvirtualmachineresponse.jobid }
+                  });
+                },
+                
+                
+                error: function(errorMessage) {
+                  args.response.error(errorMessage); // Cancel action, show error message
returned
+                }
+              });
+            },
+
+            // Because rebootVirtualMachine is an async job, we need to add
+            // a poll function, which will perodically check
+            // the management server to see if the job is ready
+            // (via pollAsyncJobResult API call)
+            //
+            // The plugin API provides a helper function, 'plugin.ui.pollAsyncJob',
+            /  which will work for most jobs
+            // in &PRODUCT;
+            notification: {
+              poll: plugin.ui.pollAsyncJob
+            }
+          }
+        },
+
+        dataProvider: function(args) {
+          ...
+...             
+           </programlisting>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Add the thumbnail icon.</emphasis></para>
+            <para>Create an icon file; it should be square, about 50x50 pixels, and
named icon.png.
+              Copy it into the same directory with your plugin code:
+              cloudstack/ui/plugins/csMyFirstPlugin/icon.png.</para>
+          </listitem>
+          <listitem>
+            <para><emphasis role="bold">Add the stylesheet.</emphasis></para>
+            <para>Create a CSS file, with the same name as your .js file. Copy it into
the same
+              directory with your plugin code:
+              cloudstack/ui/plugins/csMyFirstPlugin/csMyFirstPlugin.css.</para>
+          </listitem>
+        </orderedlist>
+      </section>
+    </chapter>


Mime
View raw message