Доброго времени суток!
-
Какие настройки управляют показом тех или иных кнопок( например, “назначить” “переназначить”)
-
Хочу нарисовать кнопку “взять в работу”. не смог разобраться, где лежит код уже существующих кнопок.
Доброго времени суток!
Какие настройки управляют показом тех или иных кнопок( например, “назначить” “переназначить”)
Хочу нарисовать кнопку “взять в работу”. не смог разобраться, где лежит код уже существующих кнопок.
Настройки жизненного цикла объекта (<lifecycle>
), роли и права пользователей.
iTop это своего рода фреймворк. Есть один код, который рисует абстрактные кнопки, есть другой код который вызывает первый с определенными параметрам и получает конкретные кнопки, есть третий код, который использует два предыдущих и размещает кнопки на странице. И всё это ещё зависит от ролей пользователя и жизненного цикла объекта.
Что должна делать кнопка “взять в работу”? То же что и “назначить”, но сразу на того, кто нажимает?
Вот ещё по кастомизации выпадающих меню:
С lifecycle вроде разобрался.
Не могу понять, где лежит код самой кнопки.
Да, кнопка “взять в работу” должна делать тоже что и “назначить”, но сразу на того, кто нажимает.
А можно ли настроить так, чтобы переназначить можно было только через кнопку, а сами поля отображались как “read only”?
Нет кода “самой кнопки”. Есть функции “рисования” кнопок, которые запускаются с разными параметрами для разных кнопок.
Если хочешь изменить надпись, сделай это через перевод.
Думаю, нужно делать новый стимул (что-то типа <stimulus id="ev_assign_to_me" xsi:type="StimulusUserAction"/>
), править под него <lifecycle>
и делать отдельный <method>
для заполнения полей агент и команда. При этом в флагах <state id="assigned">
для всех атрибутов нужно убрать <must_prompt/>
.
Дополнительно нужно предусмотреть вариант, когда пользователь не имеет права принимать тикет в работу. Как скрывать от него кнопку стандартными средствами, пока не знаю. Тут нужно проверять, есть ли он и его команда в списке доступных для конкретного тикета, а стандартное разделение прав работает на уровне классов КЕ, а не их содержимого.
Не совсем понял. Доступность полей тикета определяется флагами <flags>
в <lifecycle>
на уровне статусов <state>
.
Владимир, может быть встречались с задачей: нужно написать функцию, которая вызывает страницу создания запроса. Подозреваю, что в itop уже есть такая функция. Как бы найти название этой функции.
Куда вызывает? Кнопку какую-то сделать хотите?
Идея такая- сделать stimuli, который создает дочерний инцидент и добавить свою обработку( например автозаполнение полей).
Кнопку я уже нарисовал. По нажатию кнопки будет вызываться мой метод - тоже сделал. В методе должен вызываться метод отрисовки окна создания дочернего инцидента.
Как на счет такого варианта:
/pages/UI.php?operation=new&class=UserRequest&c[menu]=NewUserRequest&default[org_id]=3&default[parent_request_id]=8
?
Делаем обычную кнопку в меню Действия, используя iPopupMenuExtension (вот пример). В качестве одного из аргументов URLPopupMenuItem передаём вышеуказанную ссылку. В ссылке через параметры default[код_атрибута]=значение
задаём значения по умолчанию для создаваемого тикета. Получаем кнопку, которая открывает форму создания тикета и заполняет нужные поля (в т.ч. parent_request_id). Никаких стимулов и переделки модели данных не требуется.
Владимир, может приходилось работать с параметром $oPage $oP?
Нашел несколько функций, которые отображают различный функционал на странице. Все они в качестве параметров требуют задания текущей страницы( $oPage $oP). Как мне в своей функции(методе) получить в переменную $oPage текущую страницу?
К сожалению, предложенная реализация с ссылкой не получилась:
$sStartPage = “./UI.php?operation=new&class=UserRequest&c[menu]=NewUserRequest&default[org_id]=3?”;
header(“Location: $sStartPage”);
Новый объект создается, а вот сделать привязку к дочернему не получилось(после создания нового родительского нужно обновить дочерний и отследить, что родительский создался)
хочу использовать кусок кода для своей обработки
// ui.extkeywidget
case 'objectCreationForm':
$oPage->SetContentType('text/html');
$sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
$iInputId = utils::ReadParam('iInputId', '');
$sAttCode = utils::ReadParam('sAttCode', '');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
$sJson = utils::ReadParam('json', '', false, 'raw_data');
if (!empty($sJson))
{
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
}
else
{
// Search form: no current object
$oObj = null;
}
$oWidget->GetObjectCreationForm($oPage, $oObj);
break;
Так что вы все таки создаёте? Дочерний из родительского или родительский из дочернего?
В интерфейсах iApplicationUIExtension и iPageUIExtension есть методы, позволяющие взаимодействовать со страницей.
Посмотрите методы ResolveChildTickets и UpdateChildRequestLog в модели данных datamodel.itop-incident-mgmt-itil.xml. Оба метода изменяют дочерние тикеты.
От функционала создания дочерних объектов отказались, осталась задача создания родительских объектов из дочерних
Нужно на кнопку ev_my_new_chld_ur повесить функционал создания родительской проблемы(аналогично нажатию “+”) с возможностью автоматического предзаполнения полей.
Сложность в том, что header(“Location: $sStartPage”) перекидывает на новую страницу без возможности отследить был создан родительский объект или нет, а редактирование дочернего объекта прекращается.
о ResolveChildTickets думал, методы выполняются без интерфейса, надо придумать как подставлять id созданной родительской проблемы в дочерний инцидент и возвращаться в редактирование.
…попробую iPageUIExtension
Добрый день.
Требуется переместить в модуле request кнопку “назначить” из меню “другие действия” на место где кнопки: обновить, “новый”, “изменить”.
Подскажите в какую сторону копать, в каком модуле делать изменения?
Добрый день.
Т.к. я совсем не программист, но все равно интересует тема с JSON (https://www.itophub.io/wiki/page?id=2_4_0%3Aadvancedtopics%3Arest_json), в документации нет примера как это сделать, поэтому, если у кого найдется время прошу подсказать или привести свой пример.
Не понимаю, как передать в функции данные через json.
Добавил кнопочку (https://www.itophub.io/wiki/page?id=2_4_0%3Acustomization%3Aadd-menu-sample), в service request, кнопка Custom JS Function, при нажатии которой вызывается функция MyCustomJSFunction
// Sample JS function to be called from a custom menu item
function MyCustomJSFunction(sName)
{
// nothing fancy here, just popup an alert
alert(sName);
}
Как мне в этой функции передать ну вот эти параметры к примеру?
{
"operation": "core/apply_stimulus",
"comment": "Synchronization from blah...",
"class": "UserRequest",
"key": 15,
"stimulus": "ev_assign",
"output_fields": "friendlyname, title, status, contact_list",
"fields":
{
"team_id": 18,
"agent_id": 57
}
}
Отвечаю сам себе:
Взял за основу кнопку из примера: https://www.itophub.io/wiki/page?id=2_4_0%3Acustomization%3Aadd-menu-sample и код с примера json отсюда:https://www.itophub.io/wiki/page?id=2_4_0%3Aadvancedtopics%3Arest_json_playground
Получилось сделать кнопку “взять в работу”, но которая назначает на определенного агента.
Кусок кода из
main.assign-to-me.php:
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
// Only for UserRequest
if ($param instanceof UserRequest)
{
// add a separator
$aResult[] = new SeparatorPopupMenuItem(); // Note: separator does not work in iTop 2.0 due to Trac #698, fixed in 2.0.1
// Add a new menu item that triggers a custom JS function defined in our own javascript file: js/sample.js
$sModuleDir = basename(dirname(__FILE__));
$sJSFileUrl = utils::GetAbsoluteUrlModulesRoot().$sModuleDir.'/js/assign-to-me.js';
$aResult[] = new JSPopupMenuItem('_Custom_JS_', 'Assign to me...', "AssignToMe('".addslashes($param->GetName())."')", array($sJSFileUrl));
}
break;
И код скрипта:
function DoXSS(oJSON)
{
var sURL = "http://<директория itop>/itop-beta/webservices/rest.php?version=1.3";
var sDataType = 'json';
$.ajax({
type: "POST",
url: sURL,
dataType: sDataType,
data: { json_data: JSON.stringify(oJSON) },
});
location.reload();
return false;
}
function AssignToMe(sName)
{
var Ticket = sName;
var oJSON = {
"operation": "core/apply_stimulus",
"comment": "Assign process...",
"key": "SELECT UserRequest WHERE ref LIKE \"" + Ticket + "\"",
"class": "UserRequest",
"stimulus": "ev_assign",
"fields":
{
"team_id": 728,
"agent_id": 3
}
};
DoXSS(oJSON);
}
Код может быть кривой или где-то неправильный, но тут как смог.
Теперь вопрос, каким образом определять текущего агента, т.е. agent_id?
А ну да, ведь так работает:
"agent_id": "SELECT Person WHERE id = :current_contact_id"
C team_id можно сделать тоже самое, только тогда агент должен быть только в одной команде…
Т.е. fields будут выглядеть так:
"fields":
{
"team_id": "SELECT Team AS t JOIN lnkPersonToTeam AS lnk ON lnk.team_id = t.id WHERE lnk.person_id = :current_contact_id",
"agent_id": "SELECT Person WHERE id = :current_contact_id"
}
Теперь у меня загвостка, как поднять эту кнопку повыше и главное, сделать ее видимой, только, если userrequest в state new?
Или я вобще пошел не по тому пути создания кнопки…
Все никак не могу победить кнопку “взять в работу”, которая бы назначала на текущего агента.
Сделал в xml:
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<classes>
<class id="UserRequest" _delta="must_exist">
<fields>
<field id="status" xsi:type="AttributeEnum" _delta="redefine">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="new">new</value>
<value id="waiting_for_approval">waiting_for_approval</value>
<value id="approved">approved</value>
<value id="rejected">rejected</value>
<value id="assigned_to_me">assigned_to_me</value>
<value id="assigned">assigned</value>
<value id="pending">pending</value>
<value id="escalated_tto">escalated_tto</value>
<value id="escalated_ttr">escalated_ttr</value>
<value id="resolved">resolved</value>
<value id="closed">closed</value>
</values>
<sql>status</sql>
<default_value>new</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
<lifecycle>
<stimuli>
<stimulus id="ev_assign_to_me" xsi:type="StimulusUserAction" _delta="define"/>
</stimuli>
<states>
<state id="new" _delta="must_exist">
<transitions>
<transition id="ev_assign_to_me" _delta="define">
<target>assigned_to_me</target>
<actions>
<action>
<verb>AssignMe</verb>
</action>
</actions>
</transition>
</transitions>
</state>
<state id="assigned_to_me" _delta="define">
<inherit_flags_from>new</inherit_flags_from>
<flags>
<attribute id="team_id">
<read_only/>
</attribute>
<attribute id="agent_id">
<read_only/>
</attribute>
</flags>
<transitions>
<transition id="ev_pending">
<target>pending</target>
<actions>
<action>
<verb>SetCurrentDate</verb>
<params>
<param xsi:type="attcode">last_pending_date</param>
</params>
</action>
</actions>
</transition>
<transition id="ev_resolve">
<target>resolved</target>
<actions>
<action>
<verb>SetCurrentDate</verb>
<params>
<param xsi:type="attcode">resolution_date</param>
</params>
</action>
<action>
<verb>SetElapsedTime</verb>
<params>
<param xsi:type="attcode">time_spent</param>
<param xsi:type="attcode">start_date</param>
<param xsi:type="string">DefaultWorkingTimeComputer</param>
</params>
</action>
<action>
<verb>ResolveChildTickets</verb>
<params/>
</action>
</actions>
</transition>
<transition id="ev_reassign">
<target>assigned</target>
<actions/>
<flags>
<attribute id="agent_id">
<must_change/>
</attribute>
<attribute id="team_id">
<must_prompt/>
</attribute>
</flags>
</transition>
<transition id="ev_timeout">
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_autoresolve">
<target>resolved</target>
<actions>
<action>
<verb>SetCurrentDate</verb>
<params>
<param xsi:type="attcode">resolution_date</param>
</params>
</action>
<action>
<verb>SetElapsedTime</verb>
<params>
<param xsi:type="attcode">time_spent</param>
<param xsi:type="attcode">start_date</param>
<param xsi:type="string">DefaultWorkingTimeComputer</param>
</params>
</action>
<action>
<verb>ResolveChildTickets</verb>
<params/>
</action>
</actions>
</transition>
</transitions>
</state>
</states>
</lifecycle>
<methods>
<method id="AssignMe" _delta="define">
<comment><![CDATA[/**
* To be deprecated: use Reset(agent_id) instead
*/]]></comment>
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
<code><![CDATA[ public function AssignMe($sStimulusCode)
{
$this->set('team_id', 728);
$this->set('agent_id', 3);
}]]></code>
</method>
</methods>
</class>
</classes>
<menus>
</menus>
<user_rights>
<profiles>
<profile id="4" _delta="must_exist">
<groups>
<group id="UserRequest" _delta="must_exist">
<actions>
<action id="stimulus:ev_assign_to_me" _delta="define">allow</action>
</actions>
</group>
</groups>
</profile>
<profile id="5" _delta="must_exist">
<groups>
<group id="UserRequest" _delta="must_exist">
<actions>
<action id="stimulus:ev_assign_to_me" _delta="define">allow</action>
</actions>
</group>
</groups>
</profile>
</profiles>
</user_rights>
</itop_design>
Добавил новый статус, новый стимулус, метод.
Нашел, что текущего пользователя в method можно определять так:
$iContactId = UserRights::GetContactId();
И затем указать:
$this->Set('agent_id',$iContactId);
Но вот как определять team_id?
Выбрать все lnkPersonToTeam, где person_id = $iContactId. $lnkPersonToTeam->Get('team_id')
будет содержать id команды.