------=_Part_11440654_422058147.1351013711837
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Hi Chris,=20
well, I planned to implement simple "show dialog with content loaded from g=
iven URL" plugin API function some time ago, but then I thought you might b=
e experimenting with it already :) please feel free to work on that, we can=
include it into PoC revision 7.=20
Regarding planned items for revision 7, here's my current list (feel free t=
o add/modify things here if necessary):=20
* "add custom sub tab" plugin API function, with initial sub tab implem=
entation showing content of the given URL (we can add more tab types later =
on, e.g. form-based or table-based tab)=20
* "add custom task to task pane" plugin API function, requires some UiC=
ommon integration coding (I will handle this)=20
* "show dialog with content loaded from given URL" plugin API function,=
initial implementation could simply open new browser popup window using wi=
ndow.open (but any other approach is fine as well)=20
* integration with REST API, e.g. "obtain REST API authentication token=
" plugin API function, maybe also some API for performing actual HTTP REST =
calls?=20
As for the Engine REST API authentication token, need to learn more about i=
t, as WebAdmin GUI currently uses GWT RPC instead of REST API when communic=
ating with the backend.=20
You also mentioned that "we can make calls from our server into the REST AP=
I" - I assume this will be used together with "custom content for tab/dialo=
g" plugin API functionality? (Otherwise I'd say the UI Plugin itself could =
make REST API calls on its own..)=20
Regards,=20
Vojtech=20
----- Original Message -----
From: "Christopher Morrissey" <Christopher.Morrissey(a)netapp.com>=20
To: "Vojtech Szocs" <vszocs(a)redhat.com>, "engine-devel"
<engine-devel@ovirt=
.org>=20
Sent: Monday, October 22, 2012 5:25:53 PM=20
Subject: RE: [Engine-devel] UI Plugins: PoC patch revision 6 now available=
=20
Hi Vojtech,=20
Thanks again for the delivery of the patch. For revision 7, do you have a l=
ist of content? I had previously indicated I could work on adding the plugi=
n API to launch a dialog, but hadn=E2=80=99t been able to get started on it=
until now. I wanted to see if you by chance were already working on it or =
if you were planning to deliver that yourself in the next revision?=20
A couple of other items we are looking for are the ability to add tasks for=
execution and get access to the session ID or some kind of authentication =
token so that we can make calls from our server into the REST API. I=E2=80=
=99m not very familiar yet with the REST API so I=E2=80=99m not sure what a=
uthentication methods are available and which would be best.=20
-Chris=20
From: engine-devel-bounces(a)ovirt.org [mailto:engine-devel-bounces@ovirt.org=
] On Behalf Of Vojtech Szocs=20
Sent: Thursday, October 18, 2012 10:49 AM=20
To: engine-devel=20
Subject: [Engine-devel] UI Plugins: PoC patch revision 6 now available=20
Hi guys,=20
the latest revision of UI Plugins proof-of-concept patch is now available f=
or you to experiment with. You can download the patch from oVirt Gerrit at =
http://gerrit.ovirt.org/#/c/8120/2 (patch set 2).=20
Please read on to learn what's new in this revision. If you have any commen=
ts, questions or ideas, please let me know!=20
0. UI plugin path information resolved using local Engine configuration=20
Server-side UI plugin infrastructure now uses local (machine-specific) Engi=
ne configuration instead of global ( vdc_options database table) Engine con=
figuration:=20
* Previously, path information was resolved through org.ovirt.engine.co=
re.common.config.Config class - Engine configuration values were retrieved =
from vdc_options database table.=20
* Currently, path information is resolved through org.ovirt.engine.core=
.utils.LocalConfig class - Engine configuration values are retrieved from l=
ocal file system.=20
In case you're not working with oVirt Engine through RPM package system, e.=
g. you have a local development environment set up and you build and deploy=
oVirt Engine through Maven, please follow these steps:=20
a. Copy default Engine configuration into /usr/share/ ovirt-engine /conf=20
# mkdir -p /usr/share/ovirt-engine/conf=20
# cp <OVIRT_HOME>/backend/manager/conf/engine.conf.defaults /usr/share/ovir=
t-engine/conf/engine.conf.defaults=20
b. If necessary, copy UI plugin data files from /usr/share/engine/ui-plugin=
s to /usr/share/ ovirt-engine /ui-plugins=20
c. If necessary, copy UI plugin config files from /etc/engine/ui-plugins to=
/etc/ ovirt-engine /ui-plugins=20
d, In case you want to override the default Engine configuration, put your =
custom property file into /etc/sysconfig/ovirt-engine=20
The reason behind this change is that path information for UI plugin data a=
nd configuration is typically machine-specific, and should be customizable =
per machine through Engine local configuration.=20
1. New plugin API function: addMainTabActionButton=20
The "addMainTabActionButton" API adds custom context-sensitive button to th=
e given main tab's data grid, along with corresponding data grid context me=
nu item.=20
addMainTabActionButton(entityTypeName, label, actionButtonInterface)=20
entityTypeName indicates which main tab's data grid the button should be ad=
ded to, according to the entity type associated with the main tab. entityTy=
peName values are strings reflecting org.ovirt.engine.ui.webadmin.plugin.en=
tityEntityType enum members. Following entityTypeName values are currently =
supported (values are case-sensitive): "DataCenter", "Cluster",
"Host", "St=
orage", "Disk", "VirtualMachine", "Template".=20
Note: "Pool" value is currently not supported, because of org.ovirt.engine.=
core.common.businessentities.vm_pools entity not implementing the BusinessE=
ntity interface, not sure why though. Maybe we should switch from BusinessE=
ntity to IVdcQueryable interface and always cast getQueryableId method resu=
lt value to Guid?=20
label is the title displayed on the button .=20
actionButtonInterface represents an object that "implements the button inte=
rface" by declaring its functions: onClick , isEnabled , isAccessible . All=
functions of actionButtonInterface receive currently selected item(s) as f=
unction arguments.=20
Let's take a closer look at the concept behind actionButtonInterface . In t=
raditional class-based object-oriented languages, such as Java, interface i=
s an abstract type that contains method declarations without an implementat=
ion. A class that implements the given interface must implement all methods=
declared by that interface (unless it's an abstract class, but this isn't =
relevant in our case).=20
In contrast with traditional class-based object-oriented languages, JavaScr=
ipt supports OOP through prototype-based programming model (
https://develo=
per.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaS=
cript ). At the same time, JavaScript language is dynamically-typed and the=
refore doesn't support traditional concept of interface in OOP, it uses "du=
ck typing" technique instead (
http://en.wikipedia.org/wiki/Duck_typing ).=
=20
The simplest way to provide an object that "implements the given interface"=
in JavaScript is to use "duck typing" technique: providing an object that =
contains well-known functions. In UI plugin infrastructure, I call this con=
cept "interface object", represented by org.ovirt.engine.ui.webadmin.plugin=
.jsni.JsInterfaceObject class. Unlike the traditional concept of interface =
abstract type in object-oriented languages, an "interface object" does not =
necessarily have to declare all functions of the given interface in order t=
o "implement" such interface. In fact, an empty object can be used as a val=
id "interface object". Missing functions will be simply treated as empty (n=
o-op) functions. Furthermore, an "interface object" can "implement"
multipl=
e interfaces by declaring functions of those interfaces (interface composit=
ion).=20
Getting back to "addMainTabActionButton" API, here's a sample code that
add=
s new button to "Host" main tab data grid, as part of UiInit event handler =
function:=20
UiInit: function () {=20
api. addMainTabActionButton ('Host', 'Single-Host Action',=20
// Action button interface object=20
// All functions receive currently selected item(s) as function arguments=
=20
{=20
// Called when the user clicks the button=20
onClick : function () {=20
// Calling 'arguments[0]' is safe, because onClick() can be called=20
// only when exactly one item is currently selected in the data grid=20
window.alert('Selected host entity ID =3D ' + arguments[0].entityId);=20
},=20
// Returning 'true' means the button is enabled (clickable)=20
// Returning 'false' means the button is disabled (non-clickable)=20
// Default value =3D 'true'=20
isEnabled : function () {=20
// Enable button only when exactly one item is selected=20
return arguments.length =3D=3D 1;=20
},=20
// Returning 'true' means the button is visible=20
// Returning 'false' means the button is hidden=20
// Default value =3D 'true'=20
isAccessible : function () {=20
// Always show the button in the corresponding data grid=20
return true ;=20
}=20
}=20
);=20
}=20
As mentioned above, all functions of an interface object are optional. For =
functions expecting return value, default value is defined by UI plugin inf=
rastructure. For example:=20
* onClick - no default value (no return value expected)=20
* isEnabled / isAccessible - default value "true" (boolean return value=
expected)=20
Note: UI plugin infrastructure checks the actual return value type, and use=
s default value in case the function returned something of wrong (unexpecte=
d) type.=20
In the example above, "currently selected item(s)" maps to JSON-like repres=
entations of business entities currently selected in the corresponding data=
grid. For now, the entity representation is quite simple and same for all =
entity types:=20
{ entityId: "[BusinessEntityGuidAsString]" }=20
In future, we will create specific JSON-like representations for specific b=
usiness entities, in compliance with Engine REST API entity structure.=20
For a more extensive example of using "addMainTabActionButton" API, please =
see the attached "addMainTabActionButton.html.example" file.=20
2. Improved plugin API function: addMainTab=20
The "addMainTab" API was improved to address following issues:=20
* "addMainTab" can now be called at any moment during UI plugin runtime=
, given that the plugin is allowed invoke plugin API functions (plugin is e=
ither INITIALIZING or IN_USE). Previously, "addMainTab" worked reliably onl=
y when called from within UiInit event handler function. Currently, it's po=
ssible to call "addMainTab" at any moment, e.g. from within some other even=
t handler function (after UiInit has completed).=20
* "addMainTab" now retains "active" tab (highlighted tab GUI).
"addMain=
Tab" works by adding new tab component (GWTP presenter proxy) and refreshin=
g main tab panel GUI by removing all related tabs and re-adding them again.=
This logic is handled by org.ovirt.engine.ui.common.presenter.DynamicTabCo=
ntainerPresenter class, which makes sure that "active" tab is retained even=
after main tab panel was refreshed.=20
Furthermore, custom main tab implementation now displays the content of the=
given URL through HTML iframe element.=20
3. Improved native JavaScript function handling (GWT JSNI)=20
This patch introduces org.ovirt.engine.ui.webadmin.plugin.jsni.JsFunction a=
nd org.ovirt.engine.ui.webadmin.plugin.jsni.JsFunctionResultHelper classes =
providing Java abstraction for invoking native JavaScript functions. These =
classes follow the general contract of "interface object" as mentioned abov=
e.=20
JsFunctionResultHelper is particularly useful when dealing with functions w=
hich are expected to return value of a certain type. Too bad standard GWT J=
SNI classes don't provide such abstraction for working with native function=
s out-of-the-box...=20
4. ActionPanel and ActionTable type hierarchy refactoring (related to "addM=
ainTabActionButton" API)=20
Previously, AbstractActionPanel and AbstractActionTable classes didn't impl=
ement any reasonable interface that would allow other components (client-si=
de UI plugin infrastructure) to depend on their functionality in a loosely-=
coupled manner. This would make code that implements "addMainTabActionButto=
n" API "ugly": main tab view interface would have to reference
AbstractActi=
onTable class directly. In MVP design pattern, view interface should avoid =
referencing specific GWT Widget classes directly.=20
This patch introduces new interfaces for ActionPanel and ActionTable compon=
ents while eliminating code redundancy (duplicate or unnecessary code).=20
5. ActionPanel type hierarchy refactoring (related to "addMainTab" API)=20
Since org.ovirt.engine.ui.common.presenter.DynamicTabContainerPresenter def=
ines new DynamicTabPanel interface that extends standard GWTP TabPanel inte=
rface, some refactoring had to be done in related ActionPanel classes.=20
This patch makes sure that both org.ovirt.engine.ui.common.widget.tab.Abstr=
actTabPanel (widget) and org.ovirt.engine.ui.common.view.AbstractTabPanelVi=
ew (view) support DynamicTabPanel interface.=20
Note that for now, only main tab panel (org.ovirt.engine.ui.webadmin.sectio=
n.main.presenter.MainTabPanelPresenter) supports dynamic tabs within its vi=
ew.=20
Where is addSubTab API function?=20
Implementing "addSubTab" API requires some more changes, and I didn't want
=
to delay this PoC patch just because of it...=20
Here's a sample code that illustrates proposed "addSubTab" API usage:=20
UiInit: function () {=20
api. addSubTab ('Host', // entityTypeName=20
'Custom Host Sub Tab', // label=20
'custom-host-sub-tab', // historyToken=20
'http://www.ovirt.org/', // contentUrl=20
// Sub tab interface object=20
// All functions receive currently selected item(s)=20
// within the main tab data grid as function arguments=20
{=20
// Returning 'true' means the sub tab is visible=20
// Returning 'false' means the sub tab is hidden=20
// Default value =3D 'true'=20
isAccessible : function () {=20
return arguments.length =3D=3D 1 && arguments[0].entityId =3D=3D
'<MyHostEn=
tityId>';=20
}=20
}=20
);=20
}=20
As part of "addSubTab" API implementation, I'll refactor custom main tab
co=
mponents, in order to use one "tab type" for both main and sub tabs.=20
Currently, we have one (and only one) "tab type" - a tab that shows content=
of the given URL through HTML iframe element.=20
We could also create new "tab types", e.g. form-based tab that shows key/va=
lue pairs (IMHO this could be quite useful for custom sub tabs).=20
Let me know what you think!=20
Cheers,=20
Vojtech=20
------=_Part_11440654_422058147.1351013711837
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<html><head><style type=3D'text/css'>p { margin: 0;
}</style></head><body><=
div style=3D'font-family: times new roman,new york,times,serif; font-size: =
12pt; color: #000000'>Hi Chris,<br><br>well, I planned to implement
simple =
"show dialog with content loaded from given URL" plugin API function some t=
ime ago, but then I thought you might be experimenting with it already :) p=
lease feel free to work on that, we can include it into PoC revision 7.<br>=
<br>Regarding planned items for revision 7, here's my current list (feel fr=
ee to add/modify things here if necessary):<br><ul><li>"add custom
sub tab"=
plugin API function, with initial sub tab implementation showing content o=
f the given URL (we can add more tab types later on, e.g. form-based or tab=
le-based tab)</li><li>"add custom task to task pane" plugin API
function, r=
equires some UiCommon integration coding (I will handle
this)<br></li><li>"=
show dialog with content loaded from given URL" plugin API function, initia=
l implementation could simply open new browser popup window using window.op=
en (but any other approach is fine as well)<br></li><li>integration with
RE=
ST API, e.g. "obtain REST API authentication token" plugin API function, ma=
ybe also some API for performing actual HTTP REST
calls?<br></li></ul><p><b=
r></p><p>As for the Engine REST API authentication token, need to learn
mor=
e about it, as WebAdmin GUI currently uses GWT RPC instead of REST API when=
communicating with the
backend.</p><p></p><p><br></p><p>You also
mentioned=
that "we can make calls from our server into the REST API" - I assume this=
will be used together with "custom content for tab/dialog" plugin API func=
tionality? (Otherwise I'd say the UI Plugin itself could make REST API call=
s on its
own..)<br></p><p><br></p><p>Regards,</p><p>Vojtech<br></p><br><br>=
<hr id=3D"zwchr"><div
style=3D"color:#000;font-weight:normal;font-style:nor=
mal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:1=
2pt;"><b>From: </b>"Christopher Morrissey"
<Christopher.Morrissey@netapp=
.com><br><b>To: </b>"Vojtech Szocs"
&lt;vszocs(a)redhat.com&gt;, "engine-d=
evel" &lt;engine-devel(a)ovirt.org&gt;<br><b>Sent:
</b>Monday, October 22, 20=
12 5:25:53 PM<br><b>Subject: </b>RE: [Engine-devel] UI Plugins: PoC
patch r=
evision 6 now available<br><br
<style><!--
@font-face
=09{font-family:Wingdings;
=09panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
=09{font-family:Wingdings;
=09panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
=09{font-family:Calibri;
=09panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
=09{font-family:Tahoma;
=09panose-1:2 11 6 4 3 5 4 4 2 4;}
p.MsoNormal, li.MsoNormal, div.MsoNormal
=09{margin:0in;
=09margin-bottom:.0001pt;
=09font-size:12.0pt;
=09font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
=09{mso-style-priority:99;
=09color:blue;
=09text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
=09{mso-style-priority:99;
=09color:purple;
=09text-decoration:underline;}
p
=09{mso-style-priority:99;
=09margin:0in;
=09margin-bottom:.0001pt;
=09font-size:12.0pt;
=09font-family:"Times New Roman","serif";}
span.EmailStyle20
=09{mso-style-type:personal-reply;
=09font-family:"Calibri","sans-serif";
=09color:#1F497D;}
.MsoChpDefault
=09{mso-style-type:export-only;
=09font-size:10.0pt;}
@page WordSection1
=09{size:8.5in 11.0in;
=09margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
=09{page:WordSection1;}
@list l0
=09{mso-list-id:430246997;
=09mso-list-template-ids:-1402284674;}
@list l0:level1
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=B7;
=09mso-level-tab-stop:.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Symbol;}
@list l0:level2
=09{mso-level-number-format:bullet;
=09mso-level-text:o;
=09mso-level-tab-stop:1.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:"Courier New";
=09mso-bidi-font-family:"Times New Roman";}
@list l0:level3
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:1.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level4
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level5
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level6
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level7
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level8
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l0:level9
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1
=09{mso-list-id:675302646;
=09mso-list-template-ids:1662667256;}
@list l1:level1
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=B7;
=09mso-level-tab-stop:.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Symbol;}
@list l1:level2
=09{mso-level-number-format:bullet;
=09mso-level-text:o;
=09mso-level-tab-stop:1.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:"Courier New";
=09mso-bidi-font-family:"Times New Roman";}
@list l1:level3
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:1.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level4
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level5
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level6
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level7
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level8
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l1:level9
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2
=09{mso-list-id:1330719658;
=09mso-list-template-ids:-1858944704;}
@list l2:level1
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=B7;
=09mso-level-tab-stop:.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Symbol;}
@list l2:level2
=09{mso-level-number-format:bullet;
=09mso-level-text:o;
=09mso-level-tab-stop:1.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:"Courier New";
=09mso-bidi-font-family:"Times New Roman";}
@list l2:level3
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:1.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level4
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level5
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level6
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level7
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level8
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l2:level9
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3
=09{mso-list-id:2009794949;
=09mso-list-template-ids:-1270830370;}
@list l3:level1
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=B7;
=09mso-level-tab-stop:.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Symbol;}
@list l3:level2
=09{mso-level-number-format:bullet;
=09mso-level-text:o;
=09mso-level-tab-stop:1.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:"Courier New";
=09mso-bidi-font-family:"Times New Roman";}
@list l3:level3
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:1.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level4
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level5
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:2.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level6
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level7
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:3.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level8
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.0in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
@list l3:level9
=09{mso-level-number-format:bullet;
=09mso-level-text:=EF=82=A7;
=09mso-level-tab-stop:4.5in;
=09mso-level-number-position:left;
=09text-indent:-.25in;
=09mso-ansi-font-size:10.0pt;
=09font-family:Wingdings;}
ol
=09{margin-bottom:0in;}
ul
=09{margin-bottom:0in;}
--></style
<div class=3D"WordSection1"
<p
class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">Hi
Vojtech,</span></p
<p
class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">Thanks again for the
deli=
very of the patch. For revision 7, do you have a list of content? I had pre=
viously indicated I could work on adding the plugin API
to launch a dialog, but hadn=E2=80=99t been able to get started on it unti=
l now. I wanted to see if you by chance were already working on it or if yo=
u were planning to deliver that yourself in the next revision?</span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">A couple of other
items w=
e are looking for are the ability to add tasks for execution and get access=
to the session ID or some kind of authentication token
so that we can make calls from our server into the REST API. I=E2=80=99m n=
ot very familiar yet with the REST API so I=E2=80=99m not sure what authent=
ication methods are available and which would be best.</span></p
<p class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<div
<p
class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D">-Chris</span></p
</div
<p
class=3D"MsoNormal"><span
style=3D"font-size:11.0pt;font-family:"Ca=
libri","sans-serif";color:#1F497D"> </span></p
<div
<div
style=3D"border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in =
0in 0in"
<p
class=3D"MsoNormal"><b><span
style=3D"font-size:10.0pt;font-family:"=
;Tahoma","sans-serif"">From:</span></b><span
style=3D"font-s=
ize:10.0pt;font-family:"Tahoma","sans-serif"">
engine-d=
evel-bounces(a)ovirt.org [mailto:engine-devel-bounces@ovirt.org]
<b>On Behalf Of </b>Vojtech Szocs<br
<b>Sent:</b> Thursday, October 18, 2012 10:49 AM<br
<b>To:</b> engine-devel<br
<b>Subject:</b> [Engine-devel] UI Plugins: PoC
patch revision 6 now availab=
le</span></p
</div
</div
<p
class=3D"MsoNormal"> </p
<div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black">Hi guys,<br
<br
the
latest revision of UI Plugins proof-of-concept patch is now available f=
or you to experiment with. You can download the patch from oVirt Gerrit at
<a
href=3D"http://gerrit.ovirt.org/#/c/8120/2"
target=3D"_blank">http://ger=
rit.ovirt.org/#/c/8120/2</a> (patch set 2).<br
<br
Please read on to learn what's
new in this revision. If you have any commen=
ts, questions or ideas, please let me know!</span></p
<div class=3D"MsoNormal"
style=3D"text-align:center" align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p
class=3D"MsoNormal"><span style=3D"color:black"><br
<strong>0. UI plugin path information resolved using
local Engine configura=
tion</strong><b><br
</b><br
Server-side UI plugin infrastructure now uses local
(machine-specific) Engi=
ne configuration instead of global (<em>vdc_options</em> database table) En=
gine configuration:</span></p
<ul
type=3D"disc"
<li class=3D"MsoNormal"
style=3D"color:black;mso-margin-top-alt:auto;mso-ma=
rgin-bottom-alt:auto;mso-list:l3 level1 lfo1"
Previously, path information was resolved through org.ovirt.engine.core.com=
mon.config.Config class - Engine configuration values were retrieved from
<i>vdc_options</i> database table.</li><li
class=3D"MsoNormal" style=3D"col=
or:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l3 lev=
el1 lfo1"
Currently, path information is
resolved through org.ovirt.engine.core.utils=
.LocalConfig class - Engine configuration values are retrieved from local f=
ile system.</li></ul
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black">In case you're not working with oVirt Engine through RPM package sys=
tem, e.g. you have a local development environment set up and you build and=
deploy oVirt Engine through Maven, please
follow these steps:<br
<br
a. Copy
default Engine configuration into /usr/share/<b>ovirt-engine</b>/co=
nf</span></p
<div
style=3D"margin-left:30.0pt"
<p
class=3D"MsoNormal"><span style=3D"font-family:"Courier
New";c=
olor:black"># mkdir -p /usr/share/ovirt-engine/conf<br
# cp
<OVIRT_HOME>/backend/manager/conf/engine.conf.defaults /usr/shar=
e/ovirt-engine/conf/engine.conf.defaults</span></p
</div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
b. If necessary, copy UI plugin data
files from /usr/share/engine/ui-plugin=
s to /usr/share/<b>ovirt-engine</b>/ui-plugins<br
<br
c. If necessary, copy UI plugin
config files from /etc/engine/ui-plugins to=
/etc/<b>ovirt-engine</b>/ui-plugins<br
<br
d, In case you want to override the
default Engine configuration, put your =
custom property file into /etc/sysconfig/ovirt-engine<br
<br
The reason behind this change is
that path information for UI plugin data a=
nd configuration is typically machine-specific, and should be customizable =
per machine through Engine local configuration.</span></p
<div class=3D"MsoNormal"
style=3D"text-align:center" align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p
class=3D"MsoNormal"><span style=3D"color:black"><br
<b>1. New plugin API function:
addMainTabActionButton<br
</b><br
The "addMainTabActionButton" API adds custom
context-sensitive button to th=
e given main tab's data grid, along with corresponding data grid context me=
nu item.<br
<br
</span><span style=3D"font-family:"Courier
New";color:black">addM=
ainTabActionButton(entityTypeName, label, actionButtonInterface)<br
</span><span
style=3D"color:black"><br
<i>entityTypeName</i> indicates which main tab's data grid the
button shoul=
d be added to, according to the entity type associated with the main tab.<i=
entityTypeName</i> values are strings reflecting
org.ovirt.engine.ui.weba=
dmin.plugin.entityEntityType enum
members. Following <i>entityTypeName</i> values are currently supported (v=
alues are case-sensitive): "DataCenter", "Cluster", "Host",
"Storage", "Dis=
k", "VirtualMachine", "Template".<br
<br
Note: "Pool" value is
currently not supported, because of org.ovirt.engine.=
core.common.businessentities.vm_pools entity not implementing the BusinessE=
ntity interface, not sure why though. Maybe we should switch from BusinessE=
ntity to IVdcQueryable interface
and always cast getQueryableId method result value to Guid?<br
<br
<i>label</i> is the
title displayed on the button<i>.<br
</i><br
<i>actionButtonInterface</i> represents an object that "implements
the butt=
on interface" by declaring its functions:
<i>onClick</i>, <i>isEnabled</i>, <i>isAccessible</i>.
All functions of <i>=
actionButtonInterface</i> receive currently selected item(s) as function ar=
guments.<br
<br
Let's
take a closer look at the concept behind <i>actionButtonInterface</i>=
. In traditional class-based object-oriented languages, such as Java, inter=
face is an abstract type that contains method declarations without an imple=
mentation. A class that implements
the given interface must implement all methods declared by that interface =
(unless it's an abstract class, but this isn't relevant in our case).<br
<br
In contrast with traditional
class-based object-oriented languages, JavaScr=
ipt supports OOP through prototype-based programming model (<a href=3D"http=
s://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Orie=
nted_JavaScript"
target=3D"_blank">https://developer.mozilla.org/en-US/docs=
/JavaScript/Introduction_to_Object-Oriented_JavaScript</a>).
At the same time, JavaScript language is dynamically-typed and therefore d=
oesn't support traditional concept of interface in OOP, it uses "duck typin=
g" technique instead (<a
href=3D"http://en.wikipedia.org/wiki/Duck_typing" =
target=3D"_blank">http://en.wikipedia.org/wiki/Duck_typing&l...
<br
The simplest way to provide an
object that "implements the given interface"=
in JavaScript is to use "duck typing" technique: providing an object that =
contains well-known functions. In UI plugin infrastructure, I call this con=
cept "interface object", represented
by org.ovirt.engine.ui.webadmin.plugin.jsni.JsInterfaceObject class. Unlik=
e the traditional concept of interface abstract type in object-oriented lan=
guages, an "interface object"
<u>does not necessarily have to declare all functions of the given interfac=
e</u> in order to "implement" such interface. In fact, an empty object can
=
be used as a valid "interface object". Missing functions will be simply tre=
ated as empty (no-op) functions.
Furthermore, an "interface object" can "implement" multiple
interfaces by =
declaring functions of those interfaces (interface composition).<br
<br
Getting back to
"addMainTabActionButton" API, here's a sample code that add=
s new button to "Host" main tab data grid, as part of UiInit event handler =
function:<br
<br
</span><span style=3D"font-family:"Courier
New";color:black">UiIn=
it: </span><b><span style=3D"font-family:"Courier
New";color:#990=
000">function</span></b><span
style=3D"font-family:"Courier New";=
color:black">() {<br
api.</span><span style=3D"font-family:"Courier New&=
quot;;color:#CC33CC">addMainTabActionButton</span><span
style=3D"font-famil=
y:"Courier New";color:black">('Host', 'Single-Host
Action',<br
<br
</span><span style=3D"font-family:"Courier
New";color:#006600">&n=
bsp; // Action button
interface object<=
br
// All
functions receive current=
ly selected item(s) as function arguments<br
</span><span style=3D"font-family:"Courier
New";color:black">&nbs=
p; {</span><span
style=3D"color:black">=
<br
<br
</span><span
style=3D"font-family:"Courier New";color:#006600">&n=
bsp; //
Called when the u=
ser clicks the button</span><span style=3D"color:#006600"><br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p;
</span><span style=3D"font-=
family:"Courier New";color:#000099">onClick</span><span
style=3D"=
font-family:"Courier New";color:black">:
</span><b><span style=3D"font-family:"Courier
New";color:#990000"=
function</span></b><span
style=3D"font-family:"Courier New";colo=
r:black">()
{<br
</span><span
style=3D"font-family:"Courier New";color:#006600">&n=
bsp;
/=
/ Calling 'arguments[0]' is safe, because onClick() can be called<br
&=
nbsp; // only when exactly one item is currently selected in the data grid<=
br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p;
 =
; window.alert('Selected host entity ID =3D ' + arguments[0].entityId);<br
},</span><span style=3D=
"color:black"><br
<br
</span><span style=3D"font-family:"Courier
New";color:#006600">&n=
bsp; // Returning
'true' means=
the button is enabled (clickable)</span><span
style=3D"color:#006600"><br
</span><span style=3D"font-family:"Courier
New";color:#006600">&n=
bsp; // Returning
'false' mean=
s the button is disabled (non-clickable)<br
// Defau=
lt value =3D 'true'<br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p;
</span><span style=3D"font-=
family:"Courier
New";color:#000099">isEnabled</span><span style=
=3D"font-family:"Courier New";color:black">:
</span><b><span style=3D"font-family:"Courier
New";color:#990000"=
function</span></b><span
style=3D"font-family:"Courier New";colo=
r:black">()
{<br
</span><span
style=3D"font-family:"Courier New";color:#006600">&n=
bsp;
&nb=
sp; // Enable button only when exactly one item is selected<br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p;
 =
; </span
<b><span
style=3D"font-family:"Courier New";color:#990000">return=
</span></b><span style=3D"font-family:"Courier
New";color:black">=
arguments.length =3D=3D 1;<br
},</span><span style=3D"colo=
r:black"><br
<br
</span><span style=3D"font-family:"Courier
New";color:#006600">&n=
bsp; // Returning
'true' means=
the button is visible<br
// Retur=
ning 'false' means the button is hidden<br
// Default value =3D 't=
rue'<br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p; </span><span
style=3D"font-famil=
y:"Courier New";color:#000099">isAccessible</span><span
style=3D"=
font-family:"Courier New";color:black">:
</span><b><span style=3D"font-family:"Courier
New";color:#990000"=
function</span></b><span
style=3D"font-family:"Courier New";colo=
r:black">()
{</span><span style=3D"color:black"><br
</span><span
style=3D"font-family:"Courier New";color:#006600">&n=
bsp;
/=
/ Always show the button in the corresponding data grid<br
</span><span style=3D"font-family:"Courier
New";color:black">&nbs=
p;
 =
; </span
<b><span
style=3D"font-family:"Courier New";color:#990000">return=
</span></b><span style=3D"font-family:"Courier
New";color:black"
</span><b><span
style=3D"font-family:"Courier New";color:#990000"=
true</span></b><span
style=3D"font-family:"Courier New";color:bl=
ack">;<br
}</span><span=
style=3D"color:black"><br
</span><span style=3D"font-family:"Courier
New";color:black"><br
}<br
<br
);<br
}</span><span
style=3D"color:black"><br
<br
As mentioned above, all functions of
an interface object are optional. For =
functions expecting return value, default value is defined by UI plugin inf=
rastructure. For example:</span></p
<ul
type=3D"disc"
<li class=3D"MsoNormal"
style=3D"color:black;mso-margin-top-alt:auto;mso-ma=
rgin-bottom-alt:auto;mso-list:l2 level1 lfo2"
onClick -
no default value (no return value expected)</li><li class=3D"MsoN=
ormal" style=3D"color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:a=
uto;mso-list:l2 level1 lfo2"
isEnabled / isAccessible - default
value "true" (boolean return value expec=
ted)</li></ul
<p><span
style=3D"color:black">Note: UI plugin infrastructure checks the ac=
tual return value type, and uses default value in case the function returne=
d something of wrong (unexpected) type.</span></p
<p
class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span
style=3D"color:=
black"><br
In the example above,
"currently selected item(s)" maps to JSON-like repres=
entations of business entities currently selected in the corresponding data=
grid. For now, the entity representation is quite simple and same for all =
entity types:<br
<br
</span><span style=3D"font-family:"Courier
New";color:black">{ en=
tityId: "[BusinessEntityGuidAsString]" }<br
</span><span style=3D"color:black"><br
In future, we will create specific JSON-like representations
for specific b=
usiness entities, in compliance with Engine REST API entity structure.<br
<br
For a more extensive example of
using "addMainTabActionButton" API, please =
see the attached "addMainTabActionButton.html.example"
file.</span></p
<div
class=3D"MsoNormal" style=3D"text-align:center"
align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p
class=3D"MsoNormal"><span style=3D"color:black"><br
<b>2. Improved plugin API function: addMainTab<br
</b><br
The
"addMainTab" API was improved to address following
issues:</span></p
<ul type=3D"disc"
<li class=3D"MsoNormal"
style=3D"color:black;mso-margin-top-alt:auto;mso-ma=
rgin-bottom-alt:auto;mso-list:l1 level1 lfo3"
"addMainTab" can now be called at any moment during UI plugin runtime,
give=
n that the plugin is allowed invoke plugin API functions (plugin is either =
INITIALIZING or IN_USE).<br
Previously, "addMainTab"
worked reliably only when called from within UiIni=
t event handler function.<br
Currently, it's possible to call
"addMainTab" at any moment, e.g. from with=
in some other event handler function (after UiInit has completed).</li></ul=
<ul type=3D"disc"
<li
class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma=
rgin-bottom-alt:auto;mso-list:l0 level1 lfo4"
"addMainTab" now retains "active" tab (highlighted tab
GUI).<br
"addMainTab" works by
adding new tab component (GWTP presenter proxy) and r=
efreshing main tab panel GUI by removing all related tabs and re-adding the=
m again.<br
This logic is handled by
org.ovirt.engine.ui.common.presenter.DynamicTabCon=
tainerPresenter class, which makes sure that "active" tab is retained even =
after main tab panel was refreshed.</li></ul
<p
class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span
style=3D"color:=
black">Furthermore, custom main tab implementation now displays the content=
of the given URL through HTML iframe element.</span></p
<div class=3D"MsoNormal"
style=3D"text-align:center" align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
<b>3. Improved native
JavaScript function handling</b> (GWT JSNI)<br
<br
This patch introduces
org.ovirt.engine.ui.webadmin.plugin.jsni.JsFunction a=
nd org.ovirt.engine.ui.webadmin.plugin.jsni.JsFunctionResultHelper classes =
providing Java abstraction for invoking native JavaScript functions. These =
classes follow the general contract
of "interface object" as mentioned above.<br
<br
JsFunctionResultHelper is
particularly useful when dealing with functions w=
hich are expected to return value of a certain type. Too bad standard GWT J=
SNI classes don't provide such abstraction for working with native function=
s out-of-the-box...</span></p
<div
class=3D"MsoNormal" style=3D"text-align:center"
align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
<b>4. ActionPanel and
ActionTable type hierarchy refactoring</b> (related t=
o "addMainTabActionButton" API)<b><br
</b><br
Previously, AbstractActionPanel and
AbstractActionTable classes didn't impl=
ement any reasonable interface that would allow other components (client-si=
de UI plugin infrastructure) to depend on their functionality in a loosely-=
coupled manner. This would make
code that implements "addMainTabActionButton" API "ugly": main tab
view in=
terface would have to reference AbstractActionTable class directly. In MVP =
design pattern, view interface should avoid referencing specific GWT Widget=
classes directly.<br
<br
This
patch introduces new interfaces for ActionPanel and ActionTable compon=
ents while eliminating code redundancy (duplicate or unnecessary code).</sp=
an></p
<div
class=3D"MsoNormal" style=3D"text-align:center"
align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
<b>5. ActionPanel type
hierarchy refactoring</b> (related to "addMainTab" A=
PI)<br
<br
Since
org.ovirt.engine.ui.common.presenter.DynamicTabContainerPresenter def=
ines new DynamicTabPanel interface that extends standard GWTP TabPanel inte=
rface, some refactoring had to be done in related ActionPanel classes.<br
<br
This patch makes sure that both
org.ovirt.engine.ui.common.widget.tab.Abstr=
actTabPanel (widget) and org.ovirt.engine.ui.common.view.AbstractTabPanelVi=
ew (view) support DynamicTabPanel interface.<br
<br
Note that for now, only main tab
panel (org.ovirt.engine.ui.webadmin.sectio=
n.main.presenter.MainTabPanelPresenter) supports dynamic tabs within its vi=
ew.</span></p
<div
class=3D"MsoNormal" style=3D"text-align:center"
align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
<b>Where is addSubTab API
function?</b><br
<br
Implementing "addSubTab" API requires some more changes, and I didn't
want =
to delay this PoC patch just because of it...<br
<br
Here's a sample code that
illustrates proposed "addSubTab" API usage:<br
<br
</span><span
style=3D"font-family:"Courier New";color:black">UiIn=
it: </span><b><span style=3D"font-family:"Courier
New";color:#990=
000">function</span></b><span
style=3D"font-family:"Courier New";=
color:black">() {<br
api.</span><span style=3D"font-family:"Courier New&=
quot;;color:#CC33CC">addSubTab</span><span
style=3D"font-family:"Couri=
er
New";color:black">('Host',
</span><span style=3D"font-family:"Courier
New";color:#006600">//=
entityTypeName</span><span style=3D"font-family:"Courier
New";co=
lor:black"><br
'Custom
Host Sub Tab', &nbs=
p; </span><span style=3D"font-family:"Courier
New";color:#006600"=
// label</span><span
style=3D"font-family:"Courier New";color:bl=
ack"><br
'custom-host-sub-tab', </=
span><span style=3D"font-family:"Courier
New";color:#006600">// h=
istoryToken</span><span style=3D"font-family:"Courier
New";color:=
black"><br
'http://www.ovirt.org/', </span>=
<span style=3D"font-family:"Courier
New";color:#006600">// conten=
tUrl<br
<br
</span><span style=3D"font-family:"Courier
New";color:black">&nbs=
p; </span><span
style=3D"font-family:&q=
uot;Courier New";color:#006600;background:white">// Sub tab interface =
object<br
//
</span><span style=3D"font-fa=
mily:"Courier New";color:#006600">All functions receive
currently=
selected item(s)<br
// within the
main tab data grid=
as function arguments</span><span
style=3D"color:#006600"><br
</span><span style=3D"font-family:"Courier
New";color:black">&nbs=
p; {</span><span
style=3D"color:black">=
<br
<br
</span><span
style=3D"font-family:"Courier New";color:#006600">&n=
bsp; // Returning
'true' means=
the sub tab is visible<br
// Retur=
ning 'false' means the sub tab is hidden<br
// Default value =3D 't=
rue'<br
</span><span
style=3D"font-family:"Courier New";color:black">&nbs=
p; </span><span
style=3D"font-famil=
y:"Courier New";color:#000099">isAccessible</span><span
style=3D"=
font-family:"Courier New";color:black">:
</span><b><span style=3D"font-family:"Courier
New";color:#990000"=
function</span></b><span
style=3D"font-family:"Courier New";colo=
r:black">()
{<br
&=
nbsp; </span><b><span style=3D"font-family:"Courier
New";color:#9=
90000">return</span></b><span
style=3D"font-family:"Courier New";=
color:black"> arguments.length =3D=3D 1 && arguments[0].entityId
=
=3D=3D '<MyHostEntityId>';<br
}</span><span=
style=3D"color:black"><br
</span><span style=3D"font-family:"Courier
New";color:black"><br
}<br
<br
);<br
}</span><span
style=3D"color:black"><br
<br
As part of "addSubTab" API
implementation, I'll refactor custom main tab co=
mponents, in order to use one "tab type" for both main and sub tabs.<br
<br
Currently, we have one (and only
one) "tab type" - a tab that shows content=
of the given URL through HTML iframe element.<br
<br
We could also create new "tab
types", e.g. form-based tab that shows key/va=
lue pairs (IMHO this could be quite useful for custom sub tabs).</span></p
<div class=3D"MsoNormal"
style=3D"text-align:center" align=3D"center"><span=
style=3D"color:black"
<hr align=3D"center"
size=3D"2" width=3D"100%"
</span></div
<p class=3D"MsoNormal"
style=3D"margin-bottom:12.0pt"><span style=3D"color:=
black"><br
Let me know what you
think!<br
<br
Cheers,<br
Vojtech</span></p
</div
</div
</div><br></div></body></html
------=_Part_11440654_422058147.1351013711837--