mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
N°3649 - Activity panel: Add notifications
This commit is contained in:
@@ -755,34 +755,23 @@ HTML
|
||||
}
|
||||
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->OnDisplayRelations($this, $oPage, $bEditMode);
|
||||
}
|
||||
|
||||
$oPage->SetCurrentTab('');
|
||||
|
||||
|
||||
// Look for any trigger that considers this object as "In Scope"
|
||||
// If any trigger has been found then display a tab with notifications
|
||||
//
|
||||
$oTriggerSet = new CMDBObjectSet(new DBObjectSearch('Trigger'));
|
||||
$aTriggers = array();
|
||||
while ($oTrigger = $oTriggerSet->Fetch())
|
||||
{
|
||||
if ($oTrigger->IsInScope($this))
|
||||
{
|
||||
$aTriggers[] = $oTrigger->GetKey();
|
||||
}
|
||||
}
|
||||
if (count($aTriggers) > 0)
|
||||
{
|
||||
$aTriggers = $this->GetRelatedTriggersIDs();
|
||||
if (count($aTriggers) > 0) {
|
||||
$iId = $this->GetKey();
|
||||
$aParams = array('triggers' => $aTriggers, 'id' => $iId);
|
||||
$aNotifSearches = array();
|
||||
$iNotifsCount = 0;
|
||||
$aNotificationClasses = MetaModel::EnumChildClasses('EventNotification', ENUM_CHILD_CLASSES_EXCLUDETOP);
|
||||
foreach($aNotificationClasses as $sNotifClass)
|
||||
{
|
||||
foreach ($aNotificationClasses as $sNotifClass) {
|
||||
$aNotifSearches[$sNotifClass] = DBObjectSearch::FromOQL("SELECT $sNotifClass AS Ev JOIN Trigger AS T ON Ev.trigger_id = T.id WHERE T.id IN (:triggers) AND Ev.object_id = :id");
|
||||
$aNotifSearches[$sNotifClass]->SetInternalParams($aParams);
|
||||
$oNotifSet = new DBObjectSet($aNotifSearches[$sNotifClass], array());
|
||||
@@ -792,18 +781,37 @@ HTML
|
||||
$sCount = ($iNotifsCount > 0) ? ' ('.$iNotifsCount.')' : '';
|
||||
$oPage->SetCurrentTab('UI:NotificationsTab', Dict::S('UI:NotificationsTab').$sCount);
|
||||
|
||||
foreach($aNotificationClasses as $sNotifClass)
|
||||
{
|
||||
foreach($aNotificationClasses as $sNotifClass) {
|
||||
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($sNotifClass, false));
|
||||
$oClassIcon->SetDescription(MetaModel::GetName($sNotifClass))->AddCSSClass('ibo-blocklist--medallion');
|
||||
$oPage->AddUiBlock($oClassIcon);
|
||||
|
||||
|
||||
$oBlock = new DisplayBlock($aNotifSearches[$sNotifClass], 'list', false);
|
||||
$oBlock->Display($oPage, 'notifications_'.$sNotifClass, array('menu' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] IDs of the triggers that consider this object as "In Scope"
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetRelatedTriggersIDs(): array
|
||||
{
|
||||
$oTriggerSet = new CMDBObjectSet(new DBObjectSearch('Trigger'));
|
||||
$aTriggers = [];
|
||||
while ($oTrigger = $oTriggerSet->Fetch()) {
|
||||
if ($oTrigger->IsInScope($this)) {
|
||||
$aTriggers[] = $oTrigger->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
return $aTriggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
interface iCMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
* Describe (as an HTML string) the modifications corresponding to this change
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -98,16 +98,16 @@ class Event extends DBObject implements iDisplay
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
if ($bEditMode) return array(); // Not editable
|
||||
|
||||
|
||||
$aDetails = array();
|
||||
$sClass = get_class($this);
|
||||
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
|
||||
foreach( $aZList as $sAttCode)
|
||||
{
|
||||
$sDisplayValue = $this->GetAsHTML($sAttCode);
|
||||
foreach ($aZList as $sAttCode) {
|
||||
$sDisplayValue = $this->GetAsHTML($sAttCode);
|
||||
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
|
||||
}
|
||||
$oPage->Details($aDetails);
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -134,8 +134,8 @@ class EventNotification extends Event
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "jointype"=> "", "allowed_values"=>null, "sql"=>"trigger_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "jointype"=> "", "allowed_values"=>null, "sql"=>"action_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => "", "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values" => null, "sql" => "object_id", "default_value" => 0, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
|
||||
@@ -144,7 +144,6 @@ class EventNotification extends Event
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EventNotificationEmail extends EventNotification
|
||||
@@ -181,7 +180,6 @@ class EventNotificationEmail extends EventNotification
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EventIssue extends Event
|
||||
|
||||
@@ -26,10 +26,5 @@
|
||||
@import "dashboard/all";
|
||||
@import "wizard-container/wizard-container";
|
||||
@import "object/object-details";
|
||||
@import "activity-panel/activity-panel";
|
||||
@import "activity-panel/activity-entry";
|
||||
@import "activity-panel/caselog-entry";
|
||||
@import "activity-panel/edits-entry";
|
||||
@import "activity-panel/transition-entry";
|
||||
@import "activity-panel/caselog-entry-form";
|
||||
@import "activity-panel/all";
|
||||
@import "blocks-integrations/all";
|
||||
|
||||
12
css/backoffice/layout/activity-panel/_all.scss
Normal file
12
css/backoffice/layout/activity-panel/_all.scss
Normal file
@@ -0,0 +1,12 @@
|
||||
/*!
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "activity-panel";
|
||||
@import "caselog-entry-form";
|
||||
@import "activity-entry";
|
||||
@import "caselog-entry";
|
||||
@import "transition-entry";
|
||||
@import "edits-entry";
|
||||
@import "notification-entry";
|
||||
@@ -0,0 +1,35 @@
|
||||
/*!
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-notification-entry--short-description--text-color: inherit !default;
|
||||
$ibo-notification-entry--long-description-toggler-icon--margin-left: 12px !default;
|
||||
$ibo-notification-entry--long-description--margin-top: 8px !default;
|
||||
|
||||
/* CSS rules */
|
||||
/* - Long description */
|
||||
a.ibo-notification-entry--short-description {
|
||||
color: $ibo-notification-entry--short-description--text-color;
|
||||
}
|
||||
.ibo-notification-entry--long-description-toggler-icon{
|
||||
margin-left: $ibo-notification-entry--long-description-toggler-icon--margin-left;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.ibo-notification-entry--long-description{
|
||||
display: none;
|
||||
margin-top: $ibo-notification-entry--long-description--margin-top;
|
||||
list-style: inside;
|
||||
}
|
||||
/* - Long desc. opened */
|
||||
.ibo-notification-entry{
|
||||
&.ibo-is-opened{
|
||||
.ibo-notification-entry--long-description-toggler-icon{
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
.ibo-notification-entry--long-description{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Layout:ActivityPanel:MultipleEntriesSaveConfirmation:Title' => 'Multiple logs save',
|
||||
'UI:Layout:ActivityPanel:MultipleEntriesSaveConfirmation:Explanation' => 'By pressing the "save" button, you will submit entries for all the edited logs at once.',
|
||||
|
||||
// Notification entry
|
||||
'UI:Layout:ActivityPanel:NotificationEntry:MessageLink:Tooltip' => 'Click to open the notifications tab and get more information',
|
||||
|
||||
// Placeholder
|
||||
'UI:Layout:ActivityPanel:NoEntry:Placeholder:Hint' => 'It\'s calm up here, no activity yet',
|
||||
|
||||
|
||||
1
images/icons/icons8-music-robot.svg
Normal file
1
images/icons/icons8-music-robot.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="240px" height="240px"><path fill="#3d98a8" d="M45,27.9h-6.632c0-7.885-6.446-14.3-14.368-14.3S9.632,20.015,9.632,27.9H3 C3,16.376,12.421,7,24,7S45,16.376,45,27.9z"/><path fill="#266165" d="M43,33h-2.5V22H43c1.657,0,3,1.343,3,3v5C46,31.657,44.657,33,43,33z"/><path fill="#266165" d="M5,33h2.5V22H5c-1.657,0-3,1.343-3,3v5C2,31.657,3.343,33,5,33z"/><path fill="#fff176" d="M24,10c-9.941,0-18,8.059-18,18h36C42,18.059,33.941,10,24,10z"/><path fill="#263238" d="M31.1,38.9H16.9C11.432,38.9,7,34.468,7,29v0c0-5.468,4.432-9.9,9.9-9.9h14.2 c5.468,0,9.9,4.432,9.9,9.9v0C41,34.468,36.568,38.9,31.1,38.9z"/><path fill="#ffd54f" d="M31.05,40h-14.1C10.912,40,6,35.088,6,29.05V28.95C6,22.912,10.912,18,16.95,18h14.1 C37.088,18,42,22.912,42,28.95v0.101C42,35.088,37.088,40,31.05,40z M16.95,20C12.015,20,8,24.015,8,28.95v0.101 C8,33.985,12.015,38,16.95,38h14.1c4.936,0,8.95-4.015,8.95-8.95V28.95c0-4.935-4.015-8.95-8.95-8.95H16.95z"/><path fill="#b2ebf2" d="M22,29.778C22,30,20,26.972,17,27s-5,3-5,2.778C12,27.139,14.239,25,17,25S22,27.139,22,29.778z"/><path fill="#b2ebf2" d="M36,29.778C36,30,34,26.972,31,27s-5,3-5,2.778C26,27.139,28.239,25,31,25S36,27.139,36,29.778z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -82,6 +82,8 @@ $(function()
|
||||
entry_datetime: '[data-role="ibo-activity-entry--datetime"]',
|
||||
edits_entry_long_description: '[data-role="ibo-edits-entry--long-description"]',
|
||||
edits_entry_long_description_toggler: '[data-role="ibo-edits-entry--long-description-toggler"]',
|
||||
notification_entry_long_description: '[data-role="ibo-notification-entry--long-description"]',
|
||||
notification_entry_long_description_toggler: '[data-role="ibo-notification-entry--long-description-toggler"]',
|
||||
},
|
||||
enums: {
|
||||
tab_types: {
|
||||
@@ -206,7 +208,11 @@ $(function()
|
||||
});
|
||||
// - Click on an edits entry's long description toggler
|
||||
this.element.find(this.js_selectors.edits_entry_long_description_toggler).on('click', function (oEvent) {
|
||||
me._onEditsLongDescriptionTogglerClick(oEvent, $(this).closest(me.js_selectors.entry));
|
||||
me._onEntryLongDescriptionTogglerClick(oEvent, $(this).closest(me.js_selectors.entry));
|
||||
});
|
||||
// - Click on an notification entry's long description toggler
|
||||
this.element.find(this.js_selectors.notification_entry_long_description_toggler).on('click', function (oEvent) {
|
||||
me._onEntryLongDescriptionTogglerClick(oEvent, $(this).closest(me.js_selectors.entry));
|
||||
});
|
||||
|
||||
// Page exit
|
||||
@@ -390,12 +396,10 @@ $(function()
|
||||
this._SendEntriesToServer();
|
||||
}
|
||||
},
|
||||
_onCaseLogClosedMessageClick: function(oEntryElem)
|
||||
{
|
||||
_onCaseLogClosedMessageClick: function (oEntryElem) {
|
||||
this._OpenMessage(oEntryElem);
|
||||
},
|
||||
_onEditsLongDescriptionTogglerClick: function(oEvent, oEntryElem)
|
||||
{
|
||||
_onEntryLongDescriptionTogglerClick: function (oEvent, oEntryElem) {
|
||||
// Avoid anchor glitch
|
||||
oEvent.preventDefault();
|
||||
|
||||
|
||||
@@ -233,6 +233,9 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpSetAttributeScalarFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpSetAttributeScalarFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CaseLogEntry' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/CaseLogEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EditsEntry' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EditsEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EventNotification\\EventNotificationEmailFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EventNotification/EventNotificationEmailFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EventNotification\\EventNotificationFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EventNotification/EventNotificationFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\NotificationEntry' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/NotificationEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanel' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelFactory' => $baseDir . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelFactory.php',
|
||||
|
||||
@@ -463,6 +463,9 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CMDBChangeOp\\CMDBChangeOpSetAttributeScalarFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/CMDBChangeOp/CMDBChangeOpSetAttributeScalarFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\CaseLogEntry' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/CaseLogEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EditsEntry' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EditsEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EventNotification\\EventNotificationEmailFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EventNotification/EventNotificationEmailFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\EventNotification\\EventNotificationFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/EventNotification/EventNotificationFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\NotificationEntry' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/NotificationEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanel' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\ActivityPanelFactory' => __DIR__ . '/../..' . '/sources/application/UI/Base/Layout/ActivityPanel/ActivityPanelFactory.php',
|
||||
|
||||
@@ -24,6 +24,7 @@ use AttributeDateTime;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use DateTime;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class ActivityEntry
|
||||
@@ -46,6 +47,8 @@ class ActivityEntry extends UIBlock
|
||||
public const DEFAULT_TYPE = 'generic';
|
||||
/** @var string DEFAULT_DECORATION_CLASSES */
|
||||
public const DEFAULT_DECORATION_CLASSES = 'fas fa-fw fa-mortar-pestle';
|
||||
/** @var string Relative URL (from the app. root) to the default author picture URL */
|
||||
public const DEFAULT_AUTHOR_PICTURE_REL_URL = 'images/icons/icons8-music-robot.svg';
|
||||
|
||||
/** @var string $sType Type of entry, used for filtering (eg. case log, edits, transition, ...) */
|
||||
protected $sType;
|
||||
@@ -209,17 +212,20 @@ class ActivityEntry extends UIBlock
|
||||
|
||||
// Set friendlyname to whatever we have in case $sAuthorLogin is not a valid login (deleted user, cron, ...)
|
||||
$iAuthorId = UserRights::GetUserId($this->sAuthorLogin);
|
||||
if(empty($iAuthorId) === true)
|
||||
{
|
||||
// - Friendlyname
|
||||
if (true === empty($iAuthorId)) {
|
||||
$this->sAuthorFriendlyname = $this->sAuthorLogin;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO 3.0.0: Check that this does not return '' when author is the CRON or an extension.
|
||||
} else {
|
||||
$this->sAuthorFriendlyname = UserRights::GetUserFriendlyName($this->sAuthorLogin);
|
||||
}
|
||||
// - Initials
|
||||
$this->sAuthorInitials = UserRights::GetUserInitials($this->sAuthorLogin);
|
||||
// - Picture
|
||||
$this->sAuthorPictureAbsUrl = UserRights::GetContactPictureAbsUrl($this->sAuthorLogin, false);
|
||||
if ((null === $this->sAuthorPictureAbsUrl) && (ITOP_APPLICATION_SHORT === $this->sAuthorLogin)) {
|
||||
$this->sAuthorPictureAbsUrl = utils::GetAbsoluteUrlAppRoot().static::DEFAULT_AUTHOR_PICTURE_REL_URL;
|
||||
}
|
||||
|
||||
$this->bIsFromCurrentUser = UserRights::GetUserId($this->sAuthorLogin) === UserRights::GetUserId();
|
||||
|
||||
return $this;
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry;
|
||||
use AttributeDateTime;
|
||||
use CMDBChangeOp;
|
||||
use DateTime;
|
||||
use DBObject;
|
||||
use EventNotification;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use ReflectionClass;
|
||||
@@ -47,11 +49,10 @@ class ActivityEntryFactory
|
||||
*/
|
||||
public static function MakeFromCmdbChangeOp(CMDBChangeOp $oChangeOp)
|
||||
{
|
||||
$sFactoryFqcn = static::GetCmdbChangeOpFactoryClass($oChangeOp);
|
||||
$sFactoryFqcn = static::GetFactoryClass($oChangeOp, 'CMDBChangeOp');
|
||||
|
||||
// If no factory found, throw an exception as the developer most likely forgot to create it
|
||||
if(empty($sFactoryFqcn))
|
||||
{
|
||||
if (empty($sFactoryFqcn)) {
|
||||
throw new Exception('No factory found for '.get_class($oChangeOp).', did you forgot to create one?');
|
||||
}
|
||||
|
||||
@@ -89,36 +90,57 @@ class ActivityEntryFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FQCN of the best fitted factory for the $oChangeOp. If none found, null will be returned.
|
||||
* Make an ActivityEntry entry (for ActivityPanel) based on the $oEvent
|
||||
*
|
||||
* @param \CMDBChangeOp $oChangeOp
|
||||
* @param \EventNotification $oEvent
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\ActivityEntry
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function MakeFromEventNotification(EventNotification $oEvent)
|
||||
{
|
||||
$sFactoryFqcn = static::GetFactoryClass($oEvent, 'EventNotification');
|
||||
|
||||
// If no factory found, throw an exception as the developer most likely forgot to create it
|
||||
if (empty($sFactoryFqcn)) {
|
||||
throw new Exception('No factory found for '.get_class($oEvent).', did you forgot to create one?');
|
||||
}
|
||||
|
||||
/** @var \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\NotificationEntry $oEntry */
|
||||
/** @noinspection PhpUndefinedMethodInspection Call static method from the $sFactoryFqcn class */
|
||||
$oEntry = $sFactoryFqcn::MakeFromEventNotification($oEvent);
|
||||
|
||||
return $oEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FQCN of the best fitted factory for the $oObject / $sObjectType tuple. If none found, null will be returned.
|
||||
*
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected static function GetCmdbChangeOpFactoryClass(CMDBChangeOp $oChangeOp)
|
||||
protected static function GetFactoryClass(DBObject $oObject, string $sObjectType)
|
||||
{
|
||||
// Classes to search a factory for
|
||||
$aClassesTree = [get_class($oChangeOp)];
|
||||
$aClassesTree = [get_class($oObject)];
|
||||
|
||||
// Add parent classes to tree if not a root class
|
||||
$aParentClasses = class_parents($oChangeOp);
|
||||
if(is_array($aParentClasses))
|
||||
{
|
||||
$aParentClasses = class_parents($oObject);
|
||||
if (is_array($aParentClasses)) {
|
||||
$aClassesTree = array_merge($aClassesTree, array_values($aParentClasses));
|
||||
}
|
||||
|
||||
$sFactoryFqcn = null;
|
||||
foreach($aClassesTree as $sClass)
|
||||
{
|
||||
// Warning: This will replace all occurrences of 'CMDBChangeOp' which can be an issue on classes using this
|
||||
foreach ($aClassesTree as $sClass) {
|
||||
// Warning: This will replace all occurrences of $sObjectType (eg. 'CMDBChangeOp', 'EventNotification', ...) which can be an issue on classes using this
|
||||
// We used the case sensitive search to limit this issue.
|
||||
$sSimplifiedClass = (new ReflectionClass($sClass))->getShortName();
|
||||
$sFactoryFqcnToTry = __NAMESPACE__ . '\\CMDBChangeOp\\' . $sSimplifiedClass . 'Factory';
|
||||
$sFactoryFqcnToTry = __NAMESPACE__.'\\'.$sObjectType.'\\'.$sSimplifiedClass.'Factory';
|
||||
|
||||
// Stop at the first factory found
|
||||
if(class_exists($sFactoryFqcnToTry))
|
||||
{
|
||||
if (class_exists($sFactoryFqcnToTry)) {
|
||||
$sFactoryFqcn = $sFactoryFqcnToTry;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\EventNotification;
|
||||
|
||||
|
||||
/**
|
||||
* Class EventNotificationEmailFactory
|
||||
*
|
||||
* Factory for EventNotificationEmail events
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\EventNotification
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class EventNotificationEmailFactory extends EventNotificationFactory
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public const DEFAULT_DECORATION_CLASSES = 'fas fa-fw fa-envelope';
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\EventNotification;
|
||||
|
||||
|
||||
use AttributeDateTime;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\NotificationEntry;
|
||||
use DateTime;
|
||||
use EventNotification;
|
||||
|
||||
/**
|
||||
* Class EventNotificationFactory
|
||||
*
|
||||
* Default factory for EventNotification events
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\EventNotification
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class EventNotificationFactory
|
||||
{
|
||||
/** @var string Used to overload the type from the NotificationEntry */
|
||||
public const DEFAULT_TYPE = NotificationEntry::DEFAULT_TYPE;
|
||||
/** @var string Used to overload the decoration classes from the NotificationEntry */
|
||||
public const DEFAULT_DECORATION_CLASSES = NotificationEntry::DEFAULT_DECORATION_CLASSES;
|
||||
|
||||
/**
|
||||
* Make an ActivityEntry from the iEventNotification $oEvent
|
||||
*
|
||||
* @param \EventNotification $oEvent
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry\NotificationEntry
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function MakeFromEventNotification(EventNotification $oEvent)
|
||||
{
|
||||
$oDateTime = DateTime::createFromFormat(AttributeDateTime::GetInternalFormat(), $oEvent->Get('date'));
|
||||
|
||||
// Author login is hardcoded:
|
||||
// - Adding a user_id column to the event tables like for the CMDBChangeOp could be erro prone during migration as those tables are huge.
|
||||
// - Marking events as created by the app. is good enough as the user triggering it as no power over it, it cannot avoid it.
|
||||
$sAuthorLogin = ITOP_APPLICATION_SHORT;
|
||||
|
||||
$oEntry = new NotificationEntry($oDateTime, $sAuthorLogin, $oEvent->Get('action_id_friendlyname'), $oEvent->Get('message'));
|
||||
$oEntry->SetType(static::DEFAULT_TYPE)
|
||||
->SetDecorationClasses(static::DEFAULT_DECORATION_CLASSES);
|
||||
|
||||
return $oEntry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry;
|
||||
|
||||
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Class NotificationEntry
|
||||
*
|
||||
* @internal
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityEntry
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class NotificationEntry extends ActivityEntry
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-notification-entry';
|
||||
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/layouts/activity-panel/activity-entry/notification-entry';
|
||||
|
||||
public const DEFAULT_TYPE = 'edits';
|
||||
public const DEFAULT_DECORATION_CLASSES = 'fas fa-fw fa-bell';
|
||||
|
||||
/** @var string Title of the entry, usually the linked action title */
|
||||
protected $sTitle;
|
||||
/** @var string Message of the entry, usually it's status */
|
||||
protected $sMessage;
|
||||
|
||||
/**
|
||||
* NotificationEntry constructor.
|
||||
*
|
||||
* @param \DateTime $oDateTime
|
||||
* @param string $sAuthorLogin
|
||||
* @param string $sTitle
|
||||
* @param string $sMessage
|
||||
* @param string|null $sId
|
||||
*
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function __construct(DateTime $oDateTime, string $sAuthorLogin, string $sTitle, string $sMessage, ?string $sId = null)
|
||||
{
|
||||
parent::__construct($oDateTime, $sAuthorLogin, null, $sId);
|
||||
|
||||
$this->SetTitle($sTitle);
|
||||
$this->SetMessage($sMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::$sTitle
|
||||
*
|
||||
* @param string $sTitle
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetTitle(string $sTitle)
|
||||
{
|
||||
$this->sTitle = $sTitle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::$sTitle
|
||||
* @return string
|
||||
*/
|
||||
public function GetTitle(): string
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::$sMessage
|
||||
*
|
||||
* @param string $sMessage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetMessage(string $sMessage)
|
||||
{
|
||||
$this->sMessage = $sMessage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::$sMessage
|
||||
* @return string
|
||||
*/
|
||||
public function GetMessage(): string
|
||||
{
|
||||
return $this->sMessage;
|
||||
}
|
||||
}
|
||||
@@ -45,11 +45,11 @@ class ActivityPanelFactory
|
||||
/**
|
||||
* Make an activity panel for an object details layout, meaning that it should contain the case logs and the activity.
|
||||
*
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sMode Mode the object is being displayed (view, edit, create, ...), default is view.
|
||||
*
|
||||
* @see cmdbAbstractObject::ENUM_OBJECT_MODE_XXX
|
||||
*
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sMode Mode the object is being displayed (view, edit, create, ...), default is view.
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\ActivityPanel\ActivityPanel
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -124,14 +124,41 @@ class ActivityPanelFactory
|
||||
$oActivityPanel->AddEntry($oEntry);
|
||||
|
||||
// Set previous edits entry
|
||||
if($oEntry instanceof EditsEntry)
|
||||
{
|
||||
if ($oEntry instanceof EditsEntry) {
|
||||
$oPreviousEditsEntry = $oEntry;
|
||||
}
|
||||
}
|
||||
|
||||
$iPreviousChangeId = $iChangeId;
|
||||
}
|
||||
unset($oChangesSet);
|
||||
|
||||
// Retrieving notification events for cmdbAbstractObject only
|
||||
if ($oObject instanceof cmdbAbstractObject) {
|
||||
$aRelatedTriggersIDs = $oObject->GetRelatedTriggersIDs();
|
||||
|
||||
// Protection for classes which have no related trigger
|
||||
if (false === empty($aRelatedTriggersIDs)) {
|
||||
// - Prepare query to retrieve events
|
||||
$oNotifEventsSearch = DBObjectSearch::FromOQL('SELECT EN FROM EventNotification AS EN JOIN Action AS A ON EN.action_id = A.id WHERE EN.trigger_id IN (:triggers_ids) AND EN.object_id = :object_id');
|
||||
$oNotifEventsSet = new DBObjectSet($oNotifEventsSearch, ['id' => false], ['triggers_ids' => $aRelatedTriggersIDs, 'object_id' => $iObjId]);
|
||||
$oNotifEventsSet->SetLimit(MetaModel::GetConfig()->Get('max_history_length'));
|
||||
|
||||
/** @var \EventNotification $oNotifEvent */
|
||||
while ($oNotifEvent = $oNotifEventsSet->Fetch()) {
|
||||
try {
|
||||
$oEntry = ActivityEntryFactory::MakeFromEventNotification($oNotifEvent);
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
IssueLog::Debug(static::class.': Could not create entry from EventNotification: '.$oException->getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
$oActivityPanel->AddEntry($oEntry);
|
||||
}
|
||||
unset($oNotifEventsSet);
|
||||
}
|
||||
}
|
||||
|
||||
return $oActivityPanel;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{% extends 'base/layouts/activity-panel/activity-entry/layout.html.twig' %}
|
||||
|
||||
{% block iboActivityEntryExtraClasses %}ibo-notification-entry{% endblock %}
|
||||
|
||||
{% block iboActivityEntryMainInformationContent %}
|
||||
<a href="#" class="ibo-notification-entry--short-description" data-role="ibo-notification-entry--long-description-toggler">
|
||||
{{ oUIBlock.GetTitle() }}
|
||||
<span class="ibo-notification-entry--long-description-toggler-icon fa fa-caret-down"></span>
|
||||
</a>
|
||||
<div class="ibo-notification-entry--long-description" data-role="ibo-notification-entry--long-description">
|
||||
{# Note: The #tab_UINotificationsTab is hardcoded for now but we should find a way to make the connection with how it is prepared in the object's details #}
|
||||
<a href="#tab_UINotificationsTab" data-tooltip-content="{{ 'UI:Layout:ActivityPanel:NotificationEntry:MessageLink:Tooltip'|dict_s }}">{{ oUIBlock.GetMessage() }}</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user