Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
The Alfresco repository comes with a set of predefined rule definitions for automating the flow of content in the repository. Such definitions are rule types, rule conditions and rule actions. When an item is 'created or moved into a folder', 'updated' or 'deleted or moved out from a folder' (each one being a 'rule type') it is tested against certain 'rule conditions' (such as if its name property contains a certain value or if it is of a specific MIME type) and if all those conditions are true a number of 'rule actions' can be performed against the content. Examples of such actions can be to add a specific aspect or move the content to a another folder.
Even though the rule definitions shipped with Alfresco shall cover the basic needs and more, there might be a situation where you want to add a new type of condition to match the content against or a new action to perform if all conditions are true. That is when you need to define a custom rule definition.
To learn more about how to define your own rule condition and actions in the Alfresco Repository, please visit Custom Actions.
To customise the Alfresco Explorer UI, please visit Custom Action UI.
To learn how to setup a custom Alfresco Share UI for rules, please continue to read below.
By default Share gives the user a fully working UI even for custom rule types, definitions and actions. This means that if you define a new rule action in the repository a UI will be presented to the user with labels and UI controls of different type depending on which type the parameter has. For example if a parameter is of type d:int a text field that only accepts numbers will be created and if it is of type d:nodeRef another textfield will be rendered that only accepts a string that matches the nodeRef pattern. If a constraint is given for the parameter a drop down list will be created with the values from the constraint and if the parameter ISN'T marked as mandatory an extra 'empty' option will be added as the first option in the dropdown. Depending on the amount of parameter and their types the default ui may be totally sufficient for the tasks but when a condition becomes a bit too complex a UI customisation is often prefered. Lets take a look at the following example.
Below you will find the definitions that is sent from the repo for 2 of the rule definitions that Share is using.
'in-category' from /api/actionconditiondefinitions | 'transform' from /api/actiondefinitions |
|
|
The in-category rule condition is a quite simple condition that just takes two parameters: category-value and category-aspect. However, even though category-value is defined as a mandatory parameter the value sent to the repo is actually always the same. The problem with category-aspect is that it is of type d:nodeRef requiring a nodeRef string as the value rather than the aspect name (such as 'Classifiable').
The transform rule action is quite a complex action that takes 5 parameters. Just like 'Has category' it has 2 parameters ( association-type and association-name) which are mandatory but the values sent to the server shall always be the same. It also has 1 non mandatory property overwrite-copy of type boolean, which doesn't need to be set, which is rendered as a drop down with the following options 'Yes', 'No' and <empty string>. It also has a destination-folder parameter of type d:nodeRef requiring a nodeRef, rather than a path, to the folder. A value, which of course, is impossible for a normal user to set the value for. The mimetype parameter however looks perfect but that is hardly a comfort for a user that has to set the other values.
Edit mode with customisation: | Edit mode without customisation: |
Share_Rules_With_Customisation.png | Share_Rules_Without_Customisation.png |
Text mode with customisation: | Text mode without customisation: |
Share_Rules_With_Customisation_text.png | Share_Rules_Without_Customisation_text.png |
Lets use the previous example in a walk through to gain understanding of what and how we can change the rules definition UI in text and edit mode.
First of all you will see that the configuration 'boxes' above are 3 different share components:
Each of these components has its own config.xml file in which you can do basic configurations such as:
It is also possible to do more advanced configuration that affect the UI rendering of each rule definition and its parameters but first lets explain how to customise the just mentioned alternatives alternatives.
rule-config-type.get.config.xml | rule-config-condition.get.config.xml | rule-config-action.get.config.xml |
|
|
|
Above are the parts of the config files that lets you define from which webscript url that the rule definitions shall be loaded. This is something that you most likely will NOT change. If you want to add a new rule definition (type, condition or action) you shall do that by configuring the repo's rule config files and your new definitions will automatically appear in the webscript above.
However if you want to remove a definition from the menu you can use the <remove> elements. These elements contain the name of the definitions that you do NOT want to appear in the menu.
To find the name you want to remove: run the url in the webscript attribute in your browser; take a look at the name attributes in the JSON response; add a new element inside the remove element with the name.
Note! The element names inside the remove differ in the different files. This is to make the config files easier to read. This approach is used in other parts of the config files as well. The name should correspond to the root element's (rule-config) type attribute. In other words, if you would like to remove a definition in rule-config-type.get.config.xml you should create a <type> element.
rule-config-type.get.config.xml | rule-config-condition.get.config.xml | rule-config-action.get.config.xml |
|
|
|
In this section of the config files you configure the drop down menus aligned to the left in each row. The drop down menus contains rule definitions but also special menu items in the condition and action menus. Lets start with the simplest case first: the rule-config-type.config.xml config file.
The rule-config-type.config.xml contains one group element resulting in all rule types being grouped together into a single group.
This group is made up of type elements. These elements correspond to the rule type definition elements in the JSON response from the rule definition web script (defined in the config-definitions's webscript attribute). It is possible to match the type elements against other attributes as long as they are defined in the JSON response of the referenced config-definitions web script.
The simplest version of this config file could have just contained the <type name='*'/> element, which would have resulted in the same types being displayed, but not being diplayed in the same order as above.
Note about elements with wildcards ('*'):
A <group> can contain type, conditionand action elements. These elements correspond against rule definition types. There are also <item> and <property> elements. Lets fist look at the <item> element.
To support selections other than rule definitions, <item> elements can also be used. These will appear in the menu using the label defined in the config's *.get.properties file with the key 'menu.item.<id>'. i.e. the <item id='show-more'/>in rule-config-condition.get.config.xml Displays the label using the key 'menu.item.show-more'. Custom logs may also be added, this will be discussed in further detail under the <customise> element.
The <property> element is a special element for the rule-config-condition.get component and is not supported elsewhere.
The <property> element allows you to define comparators for properties using the compare-property-value action condition definition.
In other words instead of first choosing the condition definition compare-property-value and then choosing which property, you may choose the property directly.
Just like <condition> elements are being matched against a data collection (the JSON response form the webscript url being defined in the webscript attribute in the <config-definition> element) the <property> elements are as well. However, the property data collection is a bit more complex. For example, if we were to match the menu config against the Data Dictionary in the repository, the menu would contain hundreds of values making it impossible to use. Therefore, only the properties the user has decided he wants to see are placed in the menu. For a new user the default properties are displayed until they have configured it otherwise.
This means that before the menu is created, a user specific data collection is being gathered which then is used when the <property> menu elements are used to construct the menu.
This data collection first uses the default properties (being defined in the <defaults> element) and then adds and removes properties that the user has decided that it wants to see or not to see (using the 'Show more...' menu option in Share). These properties are then loaded from the data dictionary webscripts and passed into the menu creation as a data collection of possible values to display.
Note: This means that even if a property like <property dataType='d:text' name='cm:created'/> which is being exclusively specified in the menu config might not show up because it might not be in the property data collection, since the user might have decided that it not wants to see it.
<constraints webscript='/api/actionConstraints'/>
Parameters to a rule definition might have defined a constraint attribute with a constraint name. A constraint is a collection of items that are retreived using the webscript defined in the webscript attribute in the <constraints> element and will show as a drop down in the ui. Constraints are currently used by the config for rule conditions and rules actions. It is most likely that you will never need to change this value ('/api/actionConstraints') since it is possible to modify or to configure new constraints in the repo.
rule-config-condition.get.config.xml
<property-evaluators>
...
<property type='d:text'>
<evaluator name='EQUALS'/>
<evaluator name='CONTAINS'/>
<evaluator name='BEGINS'/>
<evaluator name='ENDS'/>
</property>
...
<property type='d:date'>
<evaluator name='EQUALS'/>
<evaluator name='GREATER_THAN'/>
<evaluator name='GREATER_THAN_EQUAL'/>
<evaluator name='LESS_THAN'/>
<evaluator name='LESS_THAN_EQUAL'/>
</property>
...
<property type='d:int'>
<evaluator name='EQUALS'/>
<evaluator name='GREATER_THAN'/>
<evaluator name='GREATER_THAN_EQUAL'/>
<evaluator name='LESS_THAN'/>
<evaluator name='LESS_THAN_EQUAL'/>
</property>
...
</property-evaluators>
Properties use a constraint named ac-compare-operations which defines all evaluators needed by the compare-property-value action definition's evaluator property.
However since properties of all types (except mimetype) may be used with the compare-property-value condition definition we need to make sure we aren't using invalid combinations of evaluators and property types.
I.e. we can't compare a property value of type d:date using 'begins with' (BEGINS), which is an evaluator intended to be used on strings (i.e. d:text).
To define which property evaluators to use for a type visit the <property-evaluators> element in rule-config-condition.get.config.xml
After you have created a rule it is possible to view a text description of it on the folder's rule page where all the folder's rules are listed to the left and the selected rule is displayed in detail to the right.
The detailed display is also using the config components to display the rule config definitions. If you don't want to use the default text ui, with all parameter labels and values listed after each other, you can modify the text being displayed by simply editing the config component's .get.properties-file. If you look below you can see how this is done for the rule config condition component:
rule-config-condition.get.properties
customise.compare-property-value.text={name} {param.operation} {param.value}
...
customise.is-subtype.text=Is of type (or sub type) '{param.type}'
customise.has-tag.text=Is tagged with '{param.tag}'
customise.in-category.text=Is in category '{param.category-value}'
...
Looking above you can see that it follows the following pattern: customise.<rule-definition-name>.text=<custom text message goes here>
Lets walk through the examples:
This is all that you need to do to display parameters of these simple types, where the value has a constraint or can be displayed directly because it is a value of a simple type such as d:int or d:text.
But what about nodeRef's that shall be resolved to paths or category display names? Well that will require you to 'hook in' some javascript code, which you can read about in the next section.
But the configuration needed in the .get.properties-files are just like for a regular tt>d:int</tt> or d:text.
Take a look at category for example, it's parameter category-value contains a nodeRef to the selected category, but to display it you will continue and use the exact same syntax as before:
Note that in this case Javascript code is needed to first resolve the nodeRef to the category display name. This is exactly what has been done for the link-category action definition in the example in the section below.
Up until now all the changes has been done using the .get.config.xml or .get.properties-files for each component, requiring no coding. However to go further and add custom ui controls beyond the default ui (such as file-, tag- or category-pickers, hide default values in edit mode etc) you will need to hook in JavaScript code. To do that follow these steps which assumes you want to override the link-category rule action definition:
Now you have made your own javascript class being loaded and acting as the client side controller for the config component. You have also told it that there is a customisation named LinkCategory, which isn't yet true. So go on and add the following code so your rule-config-action-custom.js looks like this:
rule-config-action-custom.js
/**
* RuleConfigActionCustom.
*
* @namespace YourCompany
* @class YourCompany.RuleConfigActionCustom
*/
(function()
{
Alfresco.RuleConfigActionCustom = function(htmlId)
{
Alfresco.RuleConfigActionCustom.superclass.constructor.call(this, htmlId);
// Re-register with our own name
this.name = 'YourCompany.RuleConfigActionCustom';
Alfresco.util.ComponentManager.reregister(this);
// Instance variables
this.customisations = YAHOO.lang.merge(this.customisations, Alfresco.RuleConfigActionCustom.superclass.customisations);
this.renderers = YAHOO.lang.merge(this.renderers, Alfresco.RuleConfigActionCustom.superclass.renderers);
return this;
};
YAHOO.extend(Alfresco.RuleConfigActionCustom, Alfresco.RuleConfigAction,
{
/**
* CUSTOMISATIONS
*/
customisations:
{
LinkCategory:
{
text: function(configDef, ruleConfig, configEl)
{
// Setting _type to 'category' will make the nodeRef get resolved to the category's name
this._getParamDef(configDef, 'category-value')._type = 'category';
return configDef;
},
edit: function(configDef, ruleConfig, configEl)
{
// Hide all parameters
this._hideParameters(configDef.parameterDefinitions);
// ...and add a new parameter who's type will match the category picker renderer defined below
configDef.parameterDefinitions.push(
{
type: 'arca:category-picker'
});
return configDef;
}
}
},
/**
* RENDERERS
*/
renderers:
{
'arca:category-picker':
{
/* Mark this renderer as 'manual' in edit mode so no default ui handling is done */
manual:
{
edit: true
},
/* Object to save values in */
currentCtx: {},
edit: function (containerEl, configDef, paramDef, ruleConfig, value)
{
// Save variables from the last click in the currentCtx object
this.renderers['arca:category-picker'].currentCtx =
{
configDef: configDef,
ruleConfig: ruleConfig,
paramDef: paramDef
};
// Create a category picker
var picker = new Alfresco.module.ControlWrapper(Alfresco.util.generateDomId());
picker.setOptions(
{
type: 'category',
container: containerEl,
value: (ruleConfig.parameterValues ? ruleConfig.parameterValues['category-value'] : null),
controlParams:
{
multipleSelectMode: false
},
fnValueChanged:
{
fn: function(obj)
{
// When picker is closed make sure we save the values from the picker in the hidden form fields
var ctx = this.renderers['arca:category-picker'].currentCtx;
this._setHiddenParameter(ctx.configDef, ctx.ruleConfig, 'category-aspect', 'cm:generalclassifiable');
this._setHiddenParameter(ctx.configDef, ctx.ruleConfig, 'category-value', obj.selectedItems[0]);
// Re run validations for the form connected to the config component
this._updateSubmitElements(ctx.configDef);
},
scope: this
}
});
picker.show();
}
}
}
});
})();
There are hook points in which you get your custom code runned:
Note that these methods very well may me be used in text mode as well, but then make sure to place them inside the text mode name space instead of edit.
To go further than this please investigate the source code.