BackOffice NG
BackOffice NG
BackOffice NG
The Backoffice is the Landscape where all Backend business tools would reside in the future.
The Backoffice Framework provides UI building components called Widgets which you can
wire together to build your own Cockpit.
Q: How to generate your own backoffice-based extension to add new cockpit functionality?
Ans: - ybackoffice template is used to generate your own back office extension
✓Step 2 = Choose Template for generation = ybackoffice (type ybackoffice) and hit enter.
This means that you can design a Backoffice application that shows a different application mash-up
to different business users, depending on their business role.
The wizard Create New Backoffice Role pops up and you can create the new role here:
c. After creating the role you need to edit it in the Administration tab. You can add relevant
authorities there.
2. Once you have done this, your new group is available in the Application Orchestrator. You can
choose the group you want to design your Backoffice application for.
You can create a backoffice role using impex also. Sample impex scripts are provided below. You can
make use of it.
b) Create a new UserGroup member of the new BackofficeRole group and employeegroup group
INSERT_UPDATE UserGroup ; uid[unique=true]; locname[lang=en]
; demogroup ; "Demo User Group"
INSERT_UPDATE PrincipalGroupRelation ; source(uid)[unique=true] ; target(uid)[unique=true]
; demogroup ; employeegroup ;
; demogroup ; demouserrole ;
Update your backoffice configuration, add a new perspective by configuring principal attribute of
contexts to your new backoffice role.
Goto * C:\develop\projects\Demo\hybris\bin\custom\demobackoffice\resources\demobackoffice-
backoffice-config.xml file.
Insert the following complete code block in place of the comment section above (remove all the
existing code inside the <config> tags)
<config xmlns="http://www.hybris.com/cockpit/config">
<context component="perspective-chooser" principal="demouserrole">
<y:perspective-chooser xmlns:y="http://www.hybris.com
/cockpitng/config/perspectiveChooser">
<y:authority name="demouserrole">
<y:perspective id="demobackoffice-perspective"/>
</y:authority>
</y:perspective-chooser>
</context>
</config>
Goto * C:\develop\projects\Demo\hybris\bin\custom\demobackoffice\resources\demobackoffice-
backoffice-widgets.xml file.
Add Border Layout widget for your new perspective inside <widgets> tag.
<widget-extension widgetId="backofficeMainSlot">
<widget id="demobackoffice-perspective"
widgetDefinitionId="com.hybris.cockpitng.borderlayout" template="false"
slotId="perspectives" title="demo.perspective.name” access="demouserrole">
</widget>
</widget-extension>
To see new backoffice perspective, do above changes and call ant clean all and start hybris
server using hybrisserver.bat command for windows. Once server is up then update system
by selecting new backoffice(demobackoffice) extension.
Define Node Structure & Layout
To define the node structure & layout of screen in “demobackoffice-backoffice-config.xml” file. Add
the xml configuration (define the node and columns).
<context component="explorer-tree" merge-by="module">
<n:explorer-tree xmlns:n="http://www.hybris.com/cockpitng/config/explorertree">
<n:navigation-node id="demoProduct">
</n:navigation-node>
</n:explorer-tree>
</context>
a) C:\develop\projects\Demo\hybris\bin\platform>setantenv.bat
b) C:\develop\projects\Demo\hybris\bin\platform>ant clean all
c) C:\develop\projects\Demo\hybris\bin\platform>hybrisserver.bat
d) Perform update - https://localhost:9002 -> platform -> update
e) Goto https://localhost:9002/backoffice and see the results
Note = (1) You can also create the configuration directly using the Application Orchestrator without
having to write it in the demobackoffice-backoffice-config.xml file. To do this, open the editor using
Show cockpit-config.xml and hit the Store button after changing the configuration. However, if you
hit Reset to Defaults again, your dynamic configuration will be lost. To persist it permanently, it is
recommended to create the configuration in your custom extension.
(2) To view these UI changes made in demobackoffice-backoffice-config.xml without having
to do a rebuild or restart follow the below steps.
b. Click the Hybris logo in the upper right corner of the screen and select the Reset to Defaults
option under Show cockpit-config.xml
c. After the page reloads, press F4 again to exit Application Orchestrator mode
Add a new field / new attribute in the back office to the existing node:
It means that, find configuration for context="explorer-tree" from another module, and merge with
it.
✓ Step 1 = Goto demobackoffice\resources\demobackoffice-backoffice-config.xml file and add
the new attribute in the xml config file and save the changes
✓ Step 2 = Goto https://localhost:9002/backoffice and follow these steps to see the new field
(a) Switch to the Application Orchestrator mode by pressing F4 (you'll need to be logged in as
an administrator).
(b) Click the Hybris logo in the upper right corner of the screen and select the Reset to
Defaults option under Show cockpit-config.xml
(c) After the page reloads, press F4 again to exit Application Orchestrator mode
If we want to configure explorer tree specific to perspective. Each perspective can have different
explorer tree.
Consider one perspective is having 2 nodes in explorer tree and another perspective is having 3
nodes, when user changes perspective it should display corresponding explorer tree.
as described here you can use the explorerTreeConfigCtx to define another component to
look up
you can declare additional context attribute called module which should be equal to
the id of the perspective (the root widget's id of the perpective); in this case you may
use the same component
Editors
Editors are special components provided by the Backoffice Framework that you can use inside
your widgets in order to edit and manipulate data.
The Backoffice Framework comes with list of standard editors. Here we will see how
Extendedmultireferenceeditor can be used to select multiple references of another type. For
that, we need to define the editor id for a qualifier you want to be displayed as the default extended
multi reference editor, and you need to define the parameter listConfigContext and its value to
InlineEditing - Allows for inline editing of the displayed values. Default value: false
As we have changed the list view context in above example, you need to set it in parameter
colConfigCtxCode for collection browser widget inside demobackoffice-backoffice-widgets.xml
Perform below steps: -
a) C:\develop\projects\Demo\hybris\bin\platform >setantenv.bat
b) C:\develop\projects\Demo\hybris\bin\platform >ant clean all
c) C:\develop\projects\Demo\hybris\bin\platform >hybrisserver.bat
d) Perform update - https://localhost:9002 -> platform -> update
e) Goto https://localhost:9002/backoffice and see the results
Result:
Inline Editing:
There are some other commonly used editors provided by backoffice framework.
Example:
ID - com.hybris.cockpitng.editor.boolean.checkbox
Description - Can be used to change the value of a Boolean property. If the box is checked, the
value is true, otherwise it is false.
Preview -
ID - com.hybris.cockpitng.editor.defaultdate
Description - Can be used to change the value of a Date property. To change the value a calendar
pop-up is opened.
Preview -
Editor - Default Enum Editor
ID - com.hybris.cockpitng.editor.defaultenum
Description - An editor that can handle enumeration values. It covers java.lang.Enum values as well
as any other class that has an EnumValueResolver implementation, for example values of
type HybrisEnumValue.
Preview -
Editor - WYSIWYG Editor
ID - com.hybris.cockpitng.editor.wysiwyg
Description - Rich text editor (What You See Is What You Get).
Preview -
Creating an Editor
It is possible to create your custom editor. Creating a custom editor is similar to creating a
custom widget. You need to create an editor definition and java class implementation. The renderer
class of the editor is responsible for creation of the actual view. It is also responsible for setting up the
communication of value changes back to the widget using the EditorListener.
Requirement:
Create Custom drop down, display all OPEN status orders placed by specific user till current time.
Pre-Condition:
Steps:
definition.xml
2.1) View of our custom editor is a ComboBox component. So, Create combobox and set it to parent.
3) Get List of Bookings which are open status as per requirement above, set that into Comboitem
and then append that Comboitem as child to ComboBox.
4) Add ZK listeners to the editor view (ComboBox) to catch the ON_CHANGE, which are triggered
when the value changes.
In the above example, the widget will be notified that the value has changed through EditorListener.
5) We need to define the editor id for a qualifier you want to be displayed as custom drop down
editor like below.
Note: We can define custom editors for different components like editor-area, create-wizard etc.,
Here I have used it in create-wizard component.
Result:
It is possible to create an editor that uses a ZUL file to define the view, therefore does not require a
custom renderer class at all.
boolEditor.zul
If you do not have a custom renderer class defined, then by default an implicit renderer of
type DefaultZulCockpitEditorRenderer is used.
Localizing Editors
These properties files are the place to specify your localized keys:
To use an editor in a widget, you need to add it to the widget view. It should have some id and you
also need to define its type.
widgetid.zul
</widget>
Every time a user changes the value in the editor, meaning every time the event
called onValueChanged is triggered, the doThings() method, of the mywidgetController is invoked.
Widgets
We will see, how to open up a popup widget immediately after clicking the node in the explore tree
hierarchy. The behaviour should be similar to the '+' button that performs the create action in
backoffice. Do not want any editorarea/listview, just a simple create wizard pop up should be shown
on click.
2) You need to add ConditionEvaluator widget to your configuration and configure expression for it.
The expression should be evaluated to true when your custom node is selected. For example, if your
node has id 'my_custom_node' then expression should look like: " #root.id EQ 'my_custom_node' ".
In above scenario, node id is ‘Customer’. You need to add conditionevaluator widget and configure
expression with the following script :
#root.id EQ ‘Customer’
3) Then propextractor widget would be helpful. The complete widget configuration looks like this.
Result:
<NAME_OF_EXTENSION>/backoffice/resources/widgets/actions/<NAME_OF_ACTIO
N>.
Example:
<action-definition
id="com.hybris.cockpitng.action.disabledUserEmail"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.hybris.com/schema/cockpitng/action-
definition.xsd">
<actionClassName>nz.govt.aucklandcouncil.demobackoffice.action.DisabledUserEmailAct
ion</actionClassName>
<iconUri>icons/mail_disabled.png</iconUri>
<iconHoverUri>icons/mail_active.png</iconHoverUri>
<iconDisabledUri>icons/mail_disabled.png</iconDisabledUri>
<inputType>de.hybris.platform.core.model.user.CustomerModel</inputType>
<outputType>java.lang.Object</outputType>
<sockets>
<output id="disabledUserContext"/>
</sockets>
</action-definition>
The above example is for an action named disabledUserEmail whose implementation class is
nz.govt.aucklandcouncil.demobackoffice.action.DisabledUserEmailAction. The images that are
defined must be stored in the following directory:
myextension/backoffice/resources/widgets/actions/myaction.
2) Creating the Action Implementation Class
In the following code example, the perform() method is the action callback method, invoked
when an action is executed. The canPerform() method determines the state in which the action will
be rendered.
@Override
public boolean canPerform(final ActionContext<CustomerModel> ctx)
{
final CustomerModel customer = ctx.getData();
if (customer != null)
{
boolean canPerform = false;
if (customer.isLoginDisabled())
{
canPerform = true;
}
return canPerform;
}
return false;
}
@Override
public ActionResult<Object> perform(final ActionContext<CustomerModel> ctx)
{
final CustomerModel customer = ctx.getData();
this.sendOutput(SOCKET_OUT_CONTEXT, customer);
return new ActionResult(ActionResult.SUCCESS);
}
}
Configuring Action:
You need to configure your action id where it should be displayed. As per above requirement, this
action should be configured in customer editor area action section.
Action Result:
Creating widget:
Create a definition.xml file and add information about disabled user email.
Definition.xml
xsi:noNamespaceSchemaLocation="http://www.hybris.com/schema/cockpitng/widget-
definition.xsd">
<sockets>
<input type="de.hybris.platform.core.model.user.CustomerModel" id="inputObject"/>
<output type="java.lang.String" id="send"/>
<output id="cancel" type="java.lang.String"/>
</sockets>
<controller
class="nz.govt.aucklandcouncil.demobackoffice.controllers.NotifyDisabledUserWidgetControl
ler"/>
</widget-definition>
The view of this widget is defined in a ZK ZUL file, named after the last part of the widget ID as
specified in the definition.xml(in this case notifyDisabledUserWidget.zul ). Add the
text box and button components, providing an ID for each, along with a button label.
<widget xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.zkoss.org/2005/zul">
<style src="${wr}/default.css"/>
<div>
<hlayout>
<label zclass="label-email" value="${labels.demobackoffice.
notifyDisablesUserWidget.emailInput}" width="100%"/>
<textbox id="emailInput" zclass="emailInput"/>
</hlayout>
<button id="sendBtn" sclass="y-btn-primary sendBtn" label="Send"/>
<button id="cancelBtn" sclass="y-btn-primary cancelBtn" label="Cancel"/>
</div>
</widget>
Creating a Controller
NotifyDisabledUserWidgetController.java
package nz.govt.aucklandcouncil.demobackoffice.controllers;
import de.hybris.platform.core.model.user.CustomerModel;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;
import com.hybris.cockpitng.annotations.SocketEvent;
import com.hybris.cockpitng.annotations.ViewEvent;
import com.hybris.cockpitng.util.DefaultWidgetController;
public class NotifyDisabledUserWidgetController extends DefaultWidgetController
{
private Textbox emailInput;
@SocketEvent(socketId = "inputObject")
public void initEmailInput(final CustomerModel customer)
{
if (null != customer)
{
this.emailInput.setValue(customer.getUid());
}
}
<widget id="disabledUserPopup"
widgetDefinitionId="com.hybris.cockpitng.widget.notifyDisabledUserWidget"
slotId="cockpitWidgetChildrenInvisible"
title="disabledUser.sendMail.widget.title" template="true">
<instance-settings socketEventRoutingMode="LAST_USED">
<create onInit="false" reuseExisting="true">
<all-incoming-events/>
</create>
<close>
<all-outgoing-events/>
</close>
<select onInit="false">
<all-incoming-events/>
</select>
</instance-settings>
<setting key="widgetStyleClass" type="String"></setting>
<setting key="widgetStyleAttribute" type="String"></setting>
<setting key="_width" type="String">400px</setting>
<setting key="_height" type="String">250px</setting>
<virtual-sockets />
</widget>
Then make a connection between your action and widgets in same file below.
<widget-connection sourceWidgetId="STUB_com.hybris.cockpitng.action.disabledUserEmail"
outputId="disabledUserContext" targetWidgetId="disabledUserPopup" inputId="inputObject"/>
By using @SocketEvent, widgets communicates each other. So, we can pass data between widgets.
Result:
Note:
You can change behavior of the framework, to make it easier to prototype a widget:
To make changes in ZUL files visible after page refresh, including changes to custom CSS files:
Change the following properties, then restart the server:
local.properties
backoffice.cockpitng.additionalResourceLoader.enabled=true
backoffice.cockpitng.uifactory.cache.enabled=false
backoffice.cockpitng.widgetclassloader.resourcecache.enabled=false
backoffice.cockpitng.resourceloader.resourcecache.enabled=false
Updates to labels.properties files are not affected and require the extension to be rebuilt.