My first control panel
Introduction
COREmanager delivers a wide range of features that you can use to create any control panel you like. The following example will show how you can create a panel displaying patients.
Getting started
Download and install the latest version of COREmanager. It will be accessed at https://ip-address:1500/core. By default, COREmanager is installed into the /usr/local/mgr5/ directory. All other paths will be relative to this directory.
We'll create our panel in the src/ directory.
Notes:
For process automation we recommend placing all COREmanager-based projects into the src/ directory.
Create the mypanel directory.
Create a standard Makefile that will look like the following:
LIB += mypanel
LANGS += ru en
mypanel_SOURCES = mypanel.cpp
mypanel_LDADD = -lbase
include ../isp.mk
Please refer to the article How to build custom components for more details.
Create the mypanel.cpp file in this directory:
#include <api/module.h>
using namespace isp_api;
MODULE_INIT(mypanel,"") {
}
In the console execute the command make install. Once completed, the mypanel.so file will be created in /usr/local/mgr5/lib.
Go to the /usr/local/mgr5 root directory and execute the bin/core mypanel install command to install our panel.
You have successfully created and installed your control panel. Now you can open it in your favorite browser (e.g. FireFox)
https://ip-address:1500/mypanel
Adding functions to your control panel
Complete the following steps to add new functions into your control panel:
1. Describe the menu and interface settings (the mypanel.xml file ).
2. Translate the menu (mypanel_msg_ru.xml).
3. Implement Events and Actions in the code.
Describing the menu and interface settings
Please refer to the article XML for more information about menu description.
The control panel normally uses the default menu described in core.xml, and its own menu. To describe the interface and menu, create the mypanel.xml and mypanel_msg_ru.xml files in the etc/xml directory. The mypanel.xmlfile describes the logical structure of the interface; the mypanel_msg_ru.xml file stores information in Russian.
Notes: You may use any names you like, but we recommend creating files with the following names panelname.xml and panelname_msg_language.xml
Add the "Queue" menu and submenu into your newly created control panel: List of patients (the list will display all the patients, who arranged a visit to a doctor), Last (the list will display the form with the name of the last patient).
The mypanel.xml file will look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<mainmenu level="registered" name="">
<node name="Stack" first="yes">
<node name="pacientlist"/>
<node name="showlast"/>
<node name="myreport"/>
</node>
</mainmenu>
<metadata name="showlast" type="form">
<form title="LastPacient">
<field name="LastPacient">
<input type="text" name="lastpacient" readonly="yes"/>
</field>
</form>
</metadata>
<metadata name="pacientlist" type="list" key="index" keyname="index">
<toolbar>
<toolbtn func="pacientlist.edit" type="new" default="yes" img="t-new" name="new"/>
<toolbtn func="pacientlist.edit" type="edit" img="t-edit" name="edit"/>
<toolbtn func="pacientlist.delete" type="group" img="t-delete" name="delete"/>
</toolbar>
<coldata>
<col name="index" type="data" sort="alpha" sorted="desc" hide ="yes" />
<col name="date" type="data" sort="alpha" sorted="desc"/>
<col name="pacientname" type="data" sort="alpha"/>
</coldata>
</metadata>
<metadata name="pacientlist.edit" type="form">
<form title="addPacient">
<field name="uname">
<input type="text" name="uname"/>
</field>
<field name="ulastname">
<input type="text" name="ulastname"/>
</field>
<field name="rdate">
<input type="text" name="rdate" date="text"/>
</field>
</form>
</metadata>
<metadata name="myreport" type="report" level="registered" firstrun="yes">
<text name="title"/>
<band name="report" headcolor="#f4d0bc">
<diagram label="report" data="count" type="pie"/>
<col name="uname" type="data" total="count" sort="alpha" link="no"/>
</band>
</metadata>
</mgrdata>
Text messages
Be sure to create and add contents to the mypanel_msg_en.xml file, otherwise you menu won't have any menu items.
Example of mypanel_msg_en.xml :
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<lang name="en">
<messages name="desktop">
<msg name="menu_showlast">Last</msg>
<msg name="menu_Stack">Queue</msg>
<msg name="menu_pacientlist">List of patients</msg>
<msg name="menu_myreport">Report</msg>
</messages>
<messages name="showlast">
<msg name="title">Last patient</msg>
<msg name="LastPacient">Name of the last patient.</msg>
<msg name="Last">Version</msg>
</messages>
<messages name="pacientlist">
<msg name="title">List of patients</msg>
<msg name="date">Date and time</msg>
<msg name="pacientname">Patient name</msg>
<msg name="short_new">Add</msg>
<msg name="short_delete">Delete</msg>
<msg name="short_edit">Edit</msg>
</messages>
<messages name="pacientlist.edit">
<msg name="title">Add</msg>
<msg name="uname">Patient name</msg>
<msg name="ulastname">Patient name</msg>
<msg name="rdate">Appointment date</msg>
</messages>
<messages name="myreport">
<msg name="title">Report</msg>
<msg name="uname">Patient name</msg>
<msg name="ulastname">Patient surname</msg>
<msg name="rdate">Appointment date</msg>
</messages>
</lang>
</mgrdata>
If a menu module is not displayed, please make sure the translation file is correct.
Events and Actions
COREmanager uses a number of classes that simplifies events processing. In our example the following classes will be used:
- FormAction
- StdListAction
For more information about Actions and Events in name spaces, please refer to the article Namespace isp api
COREmanager provides several ready-to-use classes to help you manage lists, e.g. StdListAction. In this call the ActionName.delete action is automatically created, which can be used only after you have described the corresponding function in the XML file. Please note: this action should be called for the selected group of elements in sequence.
Example: you have created the "Delete" button in the control pane to call the "pacientlist.delete" function. The code doesn't contain a separate action to handle this button, as the "ActionPacientList" class automatically creates the pacientlist.delete action. You only need to redefine the method "Del(Session &ses, const string &elid)", and clicking the Delete button will automatically call the "pacientlist.delete" action. The key field for the list is an index in array, the elid variable will contain the index of the element you want to delete. Selecting two rows in the list and clicking "Delete" will call the Del() method for each element in turn.
The pacientlist.edit action will be crated automatically as well . The same action will be called both for Add and Delete. Clicking Edit or Add will call the Get(Session &ses, const string &elid) method. If you clickEdit, elid will contain a parameter of the key field of the selected row. In this case, this is the index of the array element. If you click Add, elid = ""; this attribute can be used to define further actions that should be performed when filling out the form.
Clicking Ok, Edit or Add will call the Set(Session &ses, const string &elid) or New(Session &ses) method.
The following is the code of our class:
#include <api/action.h>
#include <classes.h>
#include <mgr/mgrdate.h>
#include <mgr/mgrstr.h>
class ActionPacientList : public StdListAction {
public:
ActionPacientList() : StdListAction("pacientlist", MinLevel(lvRegistered)) {}
void Get(Session &ses, const string &elid) const {
if (elid=="") {
DateTime date;
ses.NewNode("rdate",date.AsDate());
} else {
ses.NewNode("rdate",_users::Instance().userAt(str::Int(elid))->date().AsDate());
ses.NewNode("uname",_users::Instance().userAt(str::Int(elid))->name());
ses.NewNode("ulastname",_users::Instance().userAt(str::Int(elid))->LastName());
}
}
void Set(Session &ses, const string &elid) const {
user * new_user = _users::Instance().userAt(str::Int(elid));
new_user->setLastName(ses.Param("ulastname"));
new_user->setName(ses.Param("uname"));
new_user->setDateTime(DateTime(ses.Param("rdate")+" 00:00:00"));
_users::Instance().save();
}
void New(Session &ses) const {
user * new_user = new user;
new_user->setName(ses.Param("uname"));
new_user->setLastName(ses.Param("ulastname"));
new_user->setDateTime(DateTime(ses.Param("rdate")+" 00:00:00"));
_users::Instance().AddUser(new_user);
}
void Del(Session &ses, const string &elid) const {
_users::Instance().RemoveUser(str::Int(elid));
}
void List(Session& ses) const {
for (int i = 0; i < _users::Instance().count(); ++i) {
ses.NewElem();
ses.AddChildNode("index",str::Str(i));
ses.AddChildNode("pacientname", _users::Instance().userAt(i)->name()+" "+_users::Instance().userAt(i)->LastName());
ses.AddChildNode("date", _users::Instance().userAt(i)->date().AsDate());
}
}
};
The Last menu item will be described as a form. Create the corresponding action. Our handler will look something like the following:
class ActionShowLast : public FormAction {
public:
ActionShowLast() : FormAction("showlast", MinLevel(lvRegistered)) {}
//Event handling for form display
void Get(Session &ses, const string &elid) const {
int index = _users::Instance().count()-1;
std::string lastName = _users::Instance().userAt(index)->name() + " "+_users::Instance().userAt(index)->LastName();
ses.NewTag("lastpacient",lastName);
}
};