Recommendations
This article describes how to maintain interface integrity both for end-users and developers.
XML
All functions of a control panel work with the XML document, which forms replies for users (this XML is the only data source to form a reply). XML requirements:
- the root element should be named doc
- avoid using XPath starting with "//" - you may find more nodes than you needed.
General notes
- Make sure that a user knows what actions he should perform to resolve an issue if any. If additional operations are required, he should know those operations are and where to perform them. Ideally, the system should redirect him to configuration and get him back automatically. Should he has any questions about the system, he can find answers in the Documentation (or in a hint).
- The system should try to resolve issues automatically. For example, if some data do not match, the system should resolve this issue ("rotate" already exists). If a required directory or file is not present, and we know their permissions, and default file's content, we need to automatically create them, etc.
- In case of warnings, write the corresponding notification into a log file, and show banners to users.
- Allow users with higher privileges to drill down to accounts of users with lower privileges.
- All sections on the Dashboard should be arranged into columns.
- Your code should be multi-threaded.
- Temporary query data should be stored in the XML session.
- Isolate the panel's functions.
- Different functionality should be located in different files.
- Use unnamed namespace to hide module data structure.
- Functions that are used for values check (check in metadata) should allow for an empty value of a parameter.
- You can specify the required attribute to forbid empty values.
- A value may become empty due to internal modifications. In this case, it should be considered valid.
- Group operations (deletion, activation, suspension, etc.) are called for each element. If an operation cannot be performed, an exception should be generated. The operation will be performed for other elements. In case of errors, a user will see the list of elements for which the operation could not be performed.
- Ignore attempts to delete objects that don't exist (do not generate exceptions).
- Avoid code duplication.
- Avoid situations when several functions perform the same operations. Such operations should be grouped into separate functions and called by InternalCall to centrally change system behavior.
- Functions that create any objects, should return their identifier in the elid tag. If several objects are created, several elid tags are returned.
Forms
For more information about XML documents, refer to the article Description of forms.
- Edit/Create functions should return a new element identifier in the id node, and a new name, if it differs from the identifier in the name node.
- The confirm parameter (password confirmation) is not processed in the code, thus it may not be specified in API calls.
- All fields with validators (specific requirements to values) should have placeholder
- If an unlimited value can be specified in the form, it should have a placeholder with an "unlimited" message, handle an empty value, and set a large value automatically.
- If element access is checked through Get, you may not check it through Set (Get is always called before Set).
- Parameters checks should be specified in XML (@check and @checkargs). Values for slider, checkbox and select fields are checked automatically. During Set requests, the corresponding get request is also made.
- slider - an integer from the range [min,max]. If nothing is specified - min.
- checkbox - possible values: on, off. If nothing is specified - off.
- select - one of the values in the corresponding slist. If nothing is specified - the first value from the slist is taken after sorting.
- Values that are returned in get requests should meet XML requirements.
- If a developer didn't return values for slider, checkbox and select fields in the get request, the value will be set automatically (see above).
- Parameters sent in the get request will replace values of the same-named fields, so a user will see the form with values already entered into the form fields.
- Values for input fields i new object (a query with empty elid), that are entered using setvalues, should be formed automatically during the "Get" request if they were not passed as parameters. For example, if a value into the "Email" field after changing the Name field, the code may look like something like that:
if (ses.Has("Name") && !ses.Has("Email"))
ses.NewNode("Email", ses.Param("Name") + "@host.com");
- Password fields on integration forms with external systems (other panels: ip/dnsmanager, database servers, etc.) should have the password type. When displaying the form (the get request), the current value specified in the panel should be passed.
Lists
For more information about XML documents that describe a list, please refer to the article Description of lists.
- A list heading should match the name of the list in the main menu (if a clipped word was not used)
- Use captions for props only upon agreement with a development manager.
- Statistics should show a total sum. All indicators should show both figures, e.g. "3/40" rather than "4/". The column with prop should display the total sum of the smallest object (for example, if we are talking about an object's state, "on/off").
- Do not create columns without values.
- Сomments, notes, etc. should be specified as hints to a corresponding image if the list contains prop. If prop" is not present, they should be specified in a separate column in the form of a text.
- If prop/xprop contains a "lamp" icon, it should stand first.
- The maximum number of button groups - 8.
- When describing a column <col type="msg" ... /> containing a status, a text color must be specified.
- red - error
- yellow - warning
- green - no errors
Toolbar buttons
- Status change buttons (activate/suspend). On the toolbar you should locate the buttons that will change only one state (the most important one), all other statuses can be changed via checkboxes on the element edit form.
Buttons are located on the following order (if you don't have any of them, skip the button):
- Add
- Edit. If this button is present, default="yes" should be located after it. (Users may change it in the table settings form)
- Delete
- --separator--
- Enable
- Disable
- --separator--
- any other buttons that are not described below; you may set separators between groups of buttons if needed
- --separator--
- report buttons
- --separator--
- filter buttons
- --separator--
- "Go to" buttons (e.g. to another control panel, etc.)
Databases
- Do not use database reserved words for tables and fields
- Use upper-case keywords of the SQL language
- Use the '_' symbol as a separator within words
- Tables
- Names of functions that output list contents should match table names (if possible)
- Table and field names are in lower-case
- Table names should be written in the singular (E.g. server, not servers). Otherwise, external links will be formed incorrectly (see above).
- A user table should be named as "users" (user is a reserved name in some databases)
- many2many A table name should be written in singular on the left and right from 2
- Fields
- Do not use prefixes in fields' names (indicating a type, size, etc.).
- Type boolean - StringField длины 3. Values on/off (for checkbox compatibility). Class_mgr_db::BoolField
- Do not use autoincrement fields (due to issues with MySQL data replication). Use Class_mgr_db::AutoIncrement
- A filed referring to another table should have the same name as the table being referred to (if there are many links, a table name should be used as a prefix)
- A filed containing a unique identifier, should be named id Class_mgr_db::AutoIncrement
- A filed containing a unique name of the record should be named name
- A filed containing an object's status: active/suspended, should be named active with possible values on/off. Class_mgr_db::BoolField
- A filed containing access levels, should be named level, be an integer, and have values according to Namespace_mgr_access
- Fields with passwords should have the Class_mgr_db::CryptedField type, which helps improve security (including SQL injections).
SQLite
- Databases are stored in etc
- The file name extension for a database is .db
Menu modules
Menu modules are located in the following order:
- Product's sections
- System state
- Integrations
- Settings
- Help. The "Help" module should stand first on the list.
Text messages
- Make sure the interface messages
- Use upper-case hints without a dot at the end
- Use messages from the common section for captions
- Unique identifiers should be written as "Id"
- Short descriptions to buttons - ideally, their size should match the button's width. The maximum size is 1.5 of the button's width. You may use clipped words with a dot at the end. A hint should show detailed information about a toolbar button.
- IP-addresses and other addresses should be written as follows:"IP-address" "MAC-address". Upper-case abbreviation with a hyphen
- Module name. A module name should fit a raw in the left-side menu. The maximum length of the name depends on the toolbar length, both the name and the toolbar should fit 1280px screen.
- A hint should contain a detailed description. For example, if the checkbox reads "Enable Spamassassin for domain" , the hind should read the following: "Allow spam filtering using Spamassassin for the selected domain name". If a user is not familiar with Spamassassin, he can read about it in the hint.
Resource limits
- An empty value is used for unlimited values. 0 - a resource cannot be used (it is not the same as an unlimited value). Use a placeholder to show clients that they can enter an unlimited value. Example:
<field name="domainlimit">
<input type="text" name="domainlimit" check="int" unlimit="" checkargs="0,"/>
</field>
...
<msg name="placeholder_domainlimit">не ограничено</msg>
- If 0 cannot be used as a resource limit, validators can be used (the minimum value - 1) helping users avoid misunderstanding.
- Reducing limits. If a user consumed more resources that you want to allow, cancel this operation and generate an error message.
- Overselling is allowed by default meaning that a reseller can allocate more resources to his users that he is allowed by his provider. When allocating a resource to a user, both user and reseller's limits should be checked (you need to sum up resource consumption by all users of that reseller).
- If the limit is not specified, forbid users to use the resource.
New features of COREmanager that you can use in control panels
- Notification bar (notifications are now displayed in the upper left corner of the web interface). For more details please refer to this article.
- Navigation from lists (nestedlist). You can specify what list and filter will open when clicking a certain element in the table. More information can be found here.
- Restart the web-interface after the menu has been changed.
- "New" buttons on the Dashboard
- Hints to buttons that are displayed when a user logins to the control panel for the first time. They help him to get acquitted with the control panel. More information can be found here
System boot
- handlers for basic functions are created
- CORE basic functions, incoming connections' handlers, and functions forming output threads are created and registered in the system
- additional library <panel name>.so / <panel name>.dll is uploaded
The library should register all the required components during upload, and add additional libraries if needed. If the process fails, all the components will be automatically deleted from the system.
Process handling
You can add custom handlers to every stage of query processing:
- getting a request, reading and analyzing its parameters
GET and POST data are processed. Internal data representation is generated for quick access
- user authentication (an attempt to define a name of the user who made a request, and his user role)
- search a function by name (a function name is taken from the func parameter; if the parameter is not present, it is considered desktop)
- user authentication
- session xml is created (lang, func, binary, host)
- global event handlers are called (associated with action "*") before="yes"
- event handlers for the before="yes" are called
- function event handler is called
- event handlers for the after="yes" function are called
- global event handlers are called (associated with action "*") after="yes"
- completing the transaction (recording files, deleting temporary data, calling commit for databases)
- generating a reply in a required format (the format is specified in the out request)
User authentication
On this step, the system is trying to define a name of the user who has made a request, and his user role. The authenticate basic function is responsible for user authentication. This operation is performed to check whether a certain user exists or not.
- COOKIE is checked (<panel name> + "5")
COOKIE must contain the following fields colon separated: theme name, language abbreviation, session id.
- saved sessions are uploaded from the var/<panel name>.ses file (if it has not been uploaded yet)
This file is specified every time the session id is created if the panel unexpectedly fails.
- user check (authenticate.<authentication method name> is called)
- saved sessions are uploaded from the var/<panel name>.ses file (if it has not been uploaded yet)
- User authentication based on data received from the client (authenticate is called)
- IP authentication
In this case, we already know the username (it is specified in the configuration file), but we still need to call authenticate to define additional parameters.
- Trusted access authentication
Similar to the previous step, but the username is the name of a local administrator.
If all the attempts fail, the session will be assigned the access level 0.