XML description of pages
As mentioned earlier, plugin handlers return XML of three types: page descriptions, errors, and success results. In turn, pages in ispmanager are divided into the following types, each of which has a different XML structure:
- Dashboard
- Form
- List (table)
- Report
- Help board
The XML structure for form and list pages is described in more detail below.
Dashboard and reports have corresponding articles in General specifications: Main page (Dashboard) description, Description of reports.
At the top level, XML page descriptions of all types of pages are similar; their structure can be summed up as follows:
<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[function]">
<metadata type="page type">
<!-- ...metadata, different for different page types -->
</metadata>
<messages>
<msg name="string_name">Text</msg>
<!-- ... strings <msg> ... -->
</messages>
</doc>
- The func attribute of the doc tag should specify the function that corresponds to the given page. If a handler serves several functions, the function to be processed can be obtained from the PARAM_func environment variable.
- The type attribute of the <metadata> tag takes one of five values that correspond to the types of pages: dashboard, form, list, report, and help board.
- Unlike the plugin's XML description, the <lang> tag is not used here to specify the language for the displayed strings. If you want to display the plugin in different languages, this can be done via the plugin's XML description (see the relevant section below) using the <lang> tag. Strings in <messages> are mapped to UI elements using the name attribute.
Creation of XML page descriptions by analogy with existing ones
When creating XML descriptions of pages returned by plugin handlers, it is often convenient to use the XML description of an existing page as a starting point, or to create your own XML description by analogy with an existing one. To do this, simply use the mgrctl utility with the -o devel option, for example, to get XML for the site creation form:
/usr/local/mgr5/sbin/mgrctl -m ispmgr webdomain.edit -o devel
The output of this command may contain a number of elements outside of <metadata> and <messages>, some of which will have no effect when used in a plugin, so it is better to start with the contents of the <metadata> and <messages> elements.
XML description of a form
The form page consists of a header, followed by a column of fields that can be grouped into collapsible sections, followed by horizontal buttons. The XML description of a form can be summarized as follows
<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[function]">
<metadata type="form">
<form>
<field name="field_name">
<!-- elements <input>,
<select>, <textdata> и т.п.
-->
</field>
<!-- ... elements <field> ... -->
<buttons>
<button name="button_name" type="button_type">
</buttons>
</form>
</metadata>
<messages>
<msg name="field_name">Field_signature</msg>
<msg name="button_name">Button text</msg>
<msg name="title">Form header</msg>
<!-- ... strings <msg> ... -->
</messages>
<field_name>Field value</field_name>
</doc>
In case the form fields are grouped into sections, the structure inside the <form> element will look like this:
<form>
<page name="page name">
<field name="field name">
<!-- elements <input>,
<select>, <textdata> и т.п.
-->
</field>
<!-- ... elements <field> ... -->
</page>
<!-- ... elements <page> ... -->
<buttons>
<button name="button name" type="button type">
</buttons>
</form>
Some clarifications:
- The value of the name="title" attribute on the <msg> element is reserved to convey the page title.
- The caption for a field is set at the <field> element level, except for checkbox groups, for each of which a caption is set by its name attribute, in addition to the caption for the entire group.
- Within one<field> there is usually one <input>, <select>, <textdata>, <textarea>, etc., but there are exceptions, one of them is a group of checkboxes.
- If it is necessary to pass initial values for form fields, this is done using XML elements of the form <field_name>. where field_name corresponds to the value of the name attribute on the element inside the <field> element, i.e., when it is necessary to set a value for the input field: <field name="fieldname"><input name="inputname" /></field>, it is done like this: <inputname>field value</inputname>.
You can read more about XML form descriptions, input field and button types, and element attributes in the help article.
XML description of lists (tables)
The list page consists of a header, a toolbar (row of buttons) and a table. The table can be searched by row, sorted and filtered (except for columns for which filtering is prohibited by the column metadata). If no rows are received to display in the table, taking into account the filters and search string, the message "The list is empty" is displayed.
The XML description of a list can be summarized as follows:
<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[function]">
<metadata type="form"
key="string_id_field"
keyname="string_name_field">
<toolbar>
<toolgrp name="update">
<toolbtn name="button_name"
func="function_called_by_key"
type="key type"
default="yes"/>
<!-- ... elements <toolbtn> ... -->
</toolgrp>
<!-- ... elements <toolgrp> ... -->
</toolbar>
<coldata>
<col name="column_name"
type="column_type"
sort="sort_type" />
<!-- ... elements <col> ... -->
</coldata>
</metadata>
<messages>
<msg name="column_name">Column_header</msg>
<msg name="button_name">Button text</msg>
<msg name="title">List header</msg>
<!-- ... строки <msg> ... -->
</messages>
<elem>
<column_name>Cell Value</column_name>
<!-- ... elements of the type
<column1 name />
<column2 name /> и т.д... -->
</elem>
<!-- ... elements <elem> ... -->
</doc>
Comments on the code above:
- The UI behavior after clicking a button can vary greatly depending on the type of button specified by the type attribute of the <toolbtn> element.
- The default="yes" attribute of the <toolbtn> element allows you to specify a button whose behavior is triggered when a table row is double-clicked.
- As with the form, the <msg name="title"> element allows you to specify a title for the entire page.
- The sort attribute of the <col> element specifies the type of sorting that will be applied to the column when the title is clicked; examples of values are "alpha" - alphabetical sorting, "digit" - numerical sorting, etc. All variants are described in the reference article about XML lists at the link in the last paragraph.
- For ease of explanation, the generalized code structure does not include a number of elements and attributes that describe important UI list functionality. (For more information, see the reference article on XML description of lists.
For example:
- Pagination
- Filtering
- Button icons
- Display buttons by condition
XML description of errors and action success messages
Buttons and other UI elements of forms and lists result in the execution of plugin handlers and/or requests to the standard ispmanager API. The ispmanager UI receives feedback about the result of such actions via one of three message types:
- XML description of the page — in this case, a new page will be opened instead of the current page or in a new tab, depending on the button type;
- XML description of the result of successful execution of the action — when receiving such a message, the current tab may be closed or saved, or a redirect to another page may occur, depending on the button type and the message content;
- XML description of the error — in this case, the error message is displayed as a notification (when acting on a list button), as a message next to a form field, or as a banner above form buttons.
Notification of successful completion of an action
The following is a generalized structure of an action success message:
<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[called_function]">
<ok>
<!-- The <ok> element can be empty or it can include
redirect information -->
</ok>
<!-- there may be other elements besides <ok>,
but when <ok> is present, they will be ignored for the most part. -->
</doc>
In this structure, the content of the <ok> element is important; you can read about the available options in the forms section of the help article. In the most common and simple case, if the UI is required to stay on the same list or close the form, <ok> will be empty.
Error message
A generalized error message structure:
<?xml version="1.0" encoding="UTF-8"?>
<doc lang="ru" func="[called_function]">
<error type="error_type" object="element_UI_name">
<msg>Error message text</msg>
<!-- other error information items -->
</error>
</doc>
Для возврата сообщений об ошибках в плагинах достаточно такой упрощенной структуры, однако у элемента <error> возможны и другие атрибуты и дочерние элементы, пример можно найти здесь.
The response of the ispmanager UI to the received error message depends on the type of page on which the action was performed, as well as the type of button or other UI element used to initiate the action. In the case of a form, the object attribute may contain the name of the field where invalid information was entered, in which case the error is displayed next to that field.
XML description of plugins
Plugin handlers return XML page descriptions, success or error messages, and this always happens during a request to a function (func).
Binding the handler to the function is done through the plugin's XML description, in addition the plugin's XML description specifies localization strings for different languages and configures some important aspects of handler invocation.
XML plugin description files are placed in the /usr/local/mgr5/etc/xml folder and must have a name like ispmgr_mod_[plugin_name].xml, for example: ispmgr_mod_helloworld.xml.
How to apply changes to the XML description of a plugin
To start a new plugin for which an XML description has just been added, or to apply changes to an existing plugin's XML description, you must restart the panel with the following shell command:
pkill core
Note that this command only restarts the ispmanager panel, not the entire server.
Structure of plugin XML description
A generalized structure of the XML description of a plugin:
<?xml version="1.0" encoding="UTF-8"?>
<!-- The mgrdata tag must always be at the top level of each plugin.-->
<mgrdata>
<mainmenu>
<modernmenu>
<node name="group_name">
<node name="menu_item_name"/>
</node>
</modernmenu>
</mainmenu>
<handler name="handler_file_name" type="xml">
<func name="function_name" />
<event name="function_name" after="yes"/>
<!-- ... elements <func> and <event> -->
</handler>
<lang name="ru">
<messages name="desktop">
<msg name="modernmenu_menu_item_name">
Menu item text
</msg>
<!-- elements <msg> -->
</messages>
<!-- elements <messages> -->
</lang>
</mgrdata>
A plugin's XML description consists of a <mgrdata> element, within which there may be any number of <mainmenu>, <handler>, and <lang> elements. A plugin's XML description can have any number of <mainmenu>, <handler>, and <lang> elements within the <mgrdata> element, and any of these three elements can be missing. More about each of these elements below.
Element <handler>
<handler> binds the handler and the function to be processed. The path to the handler executable is specified by the name attribute, and is a relative path from the /usr/local/mgr5/addon folder.
There are two ways to bind a handler to a function:
- Handling a function with binding using the <func> element: this handler becomes the main handler for that function. The name of the function is specified in the name attribute.
- Execute the handler before or after the main handler, binding using the <event> element. The name of the function is specified in the name attribute; if the handler is to be executed before the main handler, the before="yes" attribute is used; if it is to be executed after the main handler, the after="yes" attribute is used.
There can be any number of <func> and <event> elements within a <handler> element, meaning that a single handler can handle any number of functions in each of these two roles. The name of the function to be processed in the handler code can be obtained from the PARAM_func environment variable.
Add additional UI elements to standard pages
Binding a handler to a function using the <event> element allows additional functionality to be added to standard ispmanager pages. When the after="yes" attribute is used, the plugin handler is executed after the default handler of the built-in ispmanager function and receives the XML description of the page generated by the default handler in STDIN.
In this XML description, the plugin handler can add its own UI elements, change the logic of existing ones, or, if necessary, create its own XML description to replace the one received from the default handler. As usual, the plugin handler should pass the final XML description to STDOUT, which is then used by ispmanager to create the page.
An example of how to use this feature is given in How to add a quick action to the dashboard article.
Element <mainmenu>
<mainmenu> allows you to add items to the ispmanager navigation menu. The level attribute of this element specifies the access level at which the items defined within it are displayed: 30 — root, 29 — administrator, 16 — normal user, 9 — mailbox user.
The path to each menu item has two levels, both defined by <node> elements: the top level - menu groups, the second level - menu items themselves, which are links to the corresponding pages:
<mainmenu>
<node name="group_name">
<node name="menu_item_name"/>
</node>
</mainmenu>
The code above describes the structure of the added menu items for ispmanager Business, while in ispmanager Lite (Pro, Host) the top-level <node> items are placed in an intermediate <modernmenu> item:
<mainmenu>
<modernmenu>
<node name="group_name">
<node name="menu_item_name"/>
</node>
</modernmenu>
</mainmenu>
The name attribute of the second-level <node> element specifies the function (func) to be executed when the corresponding menu item is clicked. In addition, the name attribute on both levels of the <node> element binds it to the corresponding <msg> element to specify the displayed text of the group/menu item (using the appropriate prefix — see the section on the <lang> element).
If you want to add a menu item to an existing group, the top-level <node> is set to the name attribute corresponding to the existing group; for example, the code below shows how to add a menu item to the "Settings" group (name="set") in ispmanager:
<mainmenu>
<modernmenu>
<node name="set">
<node name="myfunc"/>
</node>
</modernmenu>
</mainmenu>
If it is necessary to display a menu item without a group, to the top-level <node> element, the attribute type=“noname” is added (see the example in the article)
There may be only one <mainmenu> element in the plugin's XML description, or it may be missing.
Element <lang>
The <lang> element specifies a set of localization strings for a language (the language code is specified by the name attribute, e.g. <lang name="ru">).
Inside the <lang> element there can be any number of <messages> elements, each of which specifies a group of localization strings for one function (the name of the function is specified by the name attribute). Each localization string inside <messages> is specified by the <msg> element with the name of the corresponding UI element in the name attribute, sometimes with a prefix, e.g. <msg name=“myfield”> for a form field with name=“myfield” or <msg name=“modernmenu_myfunc”> for a menu item in ispmanager Lite with name=“myfunc”.
Some prefixes used are:
- menu_ — for menu items in ispmanager Business
- modernmenu_ — for menu items in ispmanager Lite (Pro, Host)
- msg_— for buttons
When specifying localization strings for the navigation menu, you should use <messages name="desktop">.
There can be any number of <lang> elements in the plugin's XML description, one for each language for which localization strings are specified. An example of such a group:
<lang name="ru">
<messages name="desktop">
<msg name="modernmenu_writetosupport">Sending message to support</msg>
</messages>
<messages name="writetosupport">
<msg name="messagetext">Enter text:</msg>
<msg name="msg_send">Send</msg>
<msg name="title">Sending message to support</msg>
</messages>
</lang>