mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-21 17:48:43 +02:00
N°6555 - Add class description in tooltip of Dashlet badge (#504)
This commit is contained in:
@@ -1246,6 +1246,10 @@ JS
|
||||
} else {
|
||||
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, null, null, $aRefreshParams);
|
||||
}
|
||||
$sClassDescription = MetaModel::GetClassDescription($sClass);
|
||||
if (utils::IsNotNullOrEmptyString($sClassDescription)) {
|
||||
$oBlock->SetClassDescription($sClassDescription);
|
||||
}
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
@@ -178,17 +178,18 @@ class UILinksWidget
|
||||
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
|
||||
array(
|
||||
'menu' => false,
|
||||
[
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
)));
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
'submit_on_load' => false,
|
||||
]));
|
||||
|
||||
$oBlock->AddForm();
|
||||
}
|
||||
|
||||
@@ -650,6 +650,9 @@ class ActionEmail extends ActionNotification
|
||||
$aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']';
|
||||
$aMessageContent['body'] = $sTestBody;
|
||||
$aMessageContent['to'] = $this->Get('test_recipient');
|
||||
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
|
||||
$aMessageContent['cc'] = '';
|
||||
$aMessageContent['bcc'] = '';
|
||||
}
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
|
||||
|
||||
@@ -20,6 +20,8 @@ $ibo-dashlet-badge--icon--size: 48px !default;
|
||||
|
||||
$ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default;
|
||||
|
||||
$ibo-dashlet-badge--body--tooltip-title--margin-bottom: $ibo-spacing-500 !default;
|
||||
|
||||
/* CSS variables (can be changed directly from the browser) */
|
||||
:root {
|
||||
--ibo-dashlet-badge--min-width: #{$ibo-dashlet-badge--min-width};
|
||||
@@ -74,18 +76,27 @@ $ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default;
|
||||
@extend %ibo-hyperlink-inherited-colors;
|
||||
}
|
||||
}
|
||||
.ibo-dashlet-badge--action-list-count{
|
||||
margin-right: $ibo-dashlet-badge--action-list-count--margin-right;
|
||||
@extend %ibo-font-ral-bol-450;
|
||||
|
||||
.ibo-dashlet-badge--action-list-count {
|
||||
margin-right: $ibo-dashlet-badge--action-list-count--margin-right;
|
||||
@extend %ibo-font-ral-bol-450;
|
||||
}
|
||||
.ibo-dashlet-badge--action-list-label{
|
||||
display: inline-block;
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
|
||||
.ibo-dashlet-badge--action-list-label {
|
||||
display: inline-block;
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
}
|
||||
.ibo-dashlet-badge--action-create{
|
||||
@extend %ibo-baseline-centered-content;
|
||||
@extend %ibo-font-size-150;
|
||||
|
||||
.ibo-dashlet-badge--action-create {
|
||||
@extend %ibo-baseline-centered-content;
|
||||
@extend %ibo-font-size-150;
|
||||
}
|
||||
.ibo-dashlet-badge--action-create-icon{
|
||||
margin-right: $ibo-dashlet-badge--action-icon--margin-right;
|
||||
|
||||
.ibo-dashlet-badge--action-create-icon {
|
||||
margin-right: $ibo-dashlet-badge--action-icon--margin-right;
|
||||
}
|
||||
|
||||
.ibo-dashlet-badge--body--tooltip-title {
|
||||
@extend %ibo-font-weight-600;
|
||||
margin-bottom: $ibo-dashlet-badge--body--tooltip-title--margin-bottom;
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ $(function()
|
||||
locked_by_someone_else: 'locked_by_someone_else',
|
||||
},
|
||||
},
|
||||
release_lock_promise_resolve: null, // N°4494 - Resolve callback of the Promise used for the action following the log entry send, which must be done only once the lock is released
|
||||
|
||||
// the constructor
|
||||
_create: function () {
|
||||
@@ -500,7 +501,7 @@ $(function()
|
||||
{
|
||||
// Hide all filters' options only if click wasn't on one of them
|
||||
if(($(oEvent.target).closest(this.js_selectors.activity_filter_options_toggler).length === 0)
|
||||
&& $(oEvent.target).closest(this.js_selectors.activity_filter_options).length === 0) {
|
||||
&& $(oEvent.target).closest(this.js_selectors.activity_filter_options).length === 0) {
|
||||
this._HideAllFiltersOptions();
|
||||
}
|
||||
},
|
||||
@@ -947,9 +948,9 @@ $(function()
|
||||
|
||||
// Send request to server
|
||||
$.post(
|
||||
GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
oParams,
|
||||
'json'
|
||||
GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
oParams,
|
||||
'json'
|
||||
)
|
||||
.fail(function (oXHR, sStatus, sErrorThrown) {
|
||||
CombodoModal.OpenErrorModal(sErrorThrown);
|
||||
@@ -972,12 +973,24 @@ $(function()
|
||||
|
||||
// For now, we don't hide the forms as the user may want to add something else
|
||||
me.element.find(me.js_selectors.caselog_entry_form).trigger('clear_entry.caselog_entry_form.itop');
|
||||
|
||||
// Redirect to stimulus
|
||||
// - Convert undefined, null and empty string to null
|
||||
sStimulusCode = ((sStimulusCode ?? '') === '') ? null : sStimulusCode;
|
||||
if (null !== sStimulusCode) {
|
||||
window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode;
|
||||
if (me.options.lock_enabled) {
|
||||
// Use a Promise to ensure that we redirect to the stimulus page ONLY when the lock is released, otherwise we might lock ourselves
|
||||
const oPromise = new Promise(function(resolve) {
|
||||
// Store the resolve callback so we can call it later from outside
|
||||
me.release_lock_promise_resolve = resolve;
|
||||
});
|
||||
oPromise.then(function () {
|
||||
window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode;
|
||||
// Resolve callback is reinitialized in case the redirection fails for any reason and we might need to retry
|
||||
me.release_lock_promise_resolve = null;
|
||||
});
|
||||
} else {
|
||||
window.location.href = GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=stimulus&class='+me._GetHostObjectClass()+'&id='+me._GetHostObjectID()+'&stimulus='+sStimulusCode;
|
||||
}
|
||||
}
|
||||
})
|
||||
.always(function () {
|
||||
@@ -995,7 +1008,7 @@ $(function()
|
||||
_IncreaseTabTogglerMessagesCounter: function(sCaseLogAttCode){
|
||||
let oTabTogglerCounter = this._GetTabTogglerFromCaseLogAttCode(sCaseLogAttCode).find('[data-role="ibo-activity-panel--tab-title-messages-count"]');
|
||||
let iNewCounterValue = parseInt(oTabTogglerCounter.attr('data-messages-count')) + 1;
|
||||
|
||||
|
||||
oTabTogglerCounter.attr('data-messages-count', iNewCounterValue).text(iNewCounterValue);
|
||||
},
|
||||
/**
|
||||
@@ -1143,11 +1156,10 @@ $(function()
|
||||
else {
|
||||
oParams.operation = 'check_lock_state';
|
||||
}
|
||||
|
||||
$.post(
|
||||
this.options.lock_endpoint,
|
||||
oParams,
|
||||
'json'
|
||||
this.options.lock_endpoint,
|
||||
oParams,
|
||||
'json'
|
||||
)
|
||||
.fail(function (oXHR, sStatus, sErrorThrown) {
|
||||
// In case of HTTP request failure (not lock request), put the details in the JS console
|
||||
@@ -1196,6 +1208,9 @@ $(function()
|
||||
// Tried to release our lock
|
||||
else if ('release_lock' === oParams.operation) {
|
||||
sNewLockStatus = me.enums.lock_status.unknown;
|
||||
if (me.release_lock_promise_resolve !== null) {
|
||||
me.release_lock_promise_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
// Just checked if object was locked
|
||||
@@ -1430,9 +1445,9 @@ $(function()
|
||||
limit_results_length: bLimitResultsLength,
|
||||
};
|
||||
$.post(
|
||||
this.options.load_more_entries_endpoint,
|
||||
oParams,
|
||||
'json'
|
||||
this.options.load_more_entries_endpoint,
|
||||
oParams,
|
||||
'json'
|
||||
)
|
||||
.fail(function (oXHR, sStatus, sErroThrown) {
|
||||
CombodoModal.OpenErrorModal(sErrorThrown);
|
||||
|
||||
@@ -153,16 +153,15 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
|
||||
"dataType": "html"
|
||||
})
|
||||
.done(function (data) {
|
||||
/* N°6152 - Hide during data loading and before open */
|
||||
$('#dlg_'+me.id).hide();
|
||||
$('#dlg_'+me.id).html(data);
|
||||
window[sPromiseId].then(function () {
|
||||
$('#dlg_'+me.id).dialog('open');
|
||||
me.UpdateSizes(null, null);
|
||||
if (me.bDoSearch)
|
||||
{
|
||||
if (me.bDoSearch) {
|
||||
me.SearchObjectsToAdd();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$('#count_'+me.id).change(function () {
|
||||
let c = this.value;
|
||||
me.UpdateButtons(c);
|
||||
|
||||
@@ -105,7 +105,7 @@ if ($oFilter != null)
|
||||
$aExtraParams['action'] = utils::GetAbsoluteUrlAppRoot().'pages/UniversalSearch.php';
|
||||
$aExtraParams['table_id'] = '1';
|
||||
$aExtraParams['search_header_force_dropdown'] = $sSearchHeaderForceDropdown;
|
||||
//$aExtraParams['class'] = $sClassName;
|
||||
$aExtraParams['submit_on_load'] = false;
|
||||
$oBlock->Display($oP, 0, $aExtraParams);
|
||||
|
||||
// Search results
|
||||
|
||||
@@ -109,6 +109,7 @@ try
|
||||
$aExtraParams['action'] = utils::GetAbsoluteUrlAppRoot().'pages/tagadmin.php';
|
||||
$aExtraParams['table_id'] = '1';
|
||||
$aExtraParams['search_header_force_dropdown'] = $sSearchHeaderForceDropdown;
|
||||
$aExtraParams['submit_on_load'] = false;
|
||||
$oBlock->Display($oP, 0, $aExtraParams);
|
||||
|
||||
// Search results
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Combodo\iTop\Application\UI\Base\Component\Dashlet;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\tJSRefreshCallback;
|
||||
use utils;
|
||||
|
||||
class DashletBadge extends DashletContainer
|
||||
{
|
||||
@@ -29,6 +30,11 @@ class DashletBadge extends DashletContainer
|
||||
protected $iCount;
|
||||
/** @var string */
|
||||
protected $sClassLabel;
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.1 3.2.0
|
||||
*/
|
||||
protected $sClassDescription;
|
||||
|
||||
/** @var string */
|
||||
protected $sCreateActionUrl;
|
||||
@@ -62,6 +68,7 @@ class DashletBadge extends DashletContainer
|
||||
$this->sCreateActionUrl = $sCreateActionUrl;
|
||||
$this->sCreateActionLabel = $sCreateActionLabel;
|
||||
$this->aRefreshParams = $aRefreshParams;
|
||||
$this->sClassDescription = '';
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +192,37 @@ class DashletBadge extends DashletContainer
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 3.1.1 3.2.0
|
||||
*/
|
||||
public function GetClassDescription(): string
|
||||
{
|
||||
return $this->sClassDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClassDescription
|
||||
*
|
||||
* @return DashletBadge
|
||||
* @since 3.1.1 3.2.0
|
||||
*/
|
||||
public function SetClassDescription(string $sClassDescription)
|
||||
{
|
||||
$this->sClassDescription = $sClassDescription;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public function HasClassDescription(): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($this->sClassDescription);
|
||||
}
|
||||
|
||||
public function GetJSRefresh(): string
|
||||
{
|
||||
return "$('#".$this->sId."').block();
|
||||
|
||||
@@ -3,7 +3,16 @@
|
||||
{% apply spaceless %}
|
||||
<div class="ibo-dashlet-badge--body{% if oUIBlock.IsHidden() %} ibo-is-hidden{% endif %}" id="{{ oUIBlock.GetId() }}"
|
||||
data-role="ibo-dashlet-badge--body"
|
||||
data-tooltip-content="{{ oUIBlock.GetClassLabel() }}">
|
||||
{% if oUIBlock.HasClassDescription() %}
|
||||
{# Display both class name and description as the name could be truncated if too long #}
|
||||
data-tooltip-content="{{ '<div class="ibo-dashlet-badge--body--tooltip-title">'|escape }}{{ oUIBlock.GetClassLabel() }}{{ '</div><div class="ibo-dashlet-badge--body--tooltip-description">'|escape }}{{ oUIBlock.GetClassDescription() }}{{ '</div>'|escape }}"
|
||||
data-tooltip-html-enabled="true"
|
||||
{% else %}
|
||||
{# Display only class name as it could be truncated if too long #}
|
||||
data-tooltip-content="{{ oUIBlock.GetClassLabel() }}"
|
||||
{% endif %}
|
||||
{# Delay display to avoid having all tooltips appearing when mouse is just passing through the tabs #}
|
||||
data-tooltip-show-delay="300">
|
||||
<div class="ibo-dashlet-badge--icon-container">
|
||||
{# Mind the empty "alt" attribute https://www.w3.org/WAI/tutorials/images/decorative/ #}
|
||||
<img class="ibo-dashlet-badge--icon" src="{{ oUIBlock.GetClassIconUrl() }}" alt="">
|
||||
|
||||
@@ -33,7 +33,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
$aParameters = $oExpression->GetParameters($sParentFilter);
|
||||
sort($aExpectedParameters);
|
||||
sort($aParameters);
|
||||
static::assertEquals($aExpectedParameters, $aParameters);
|
||||
$this->assertEquals($aExpectedParameters, $aParameters);
|
||||
}
|
||||
|
||||
public function GetParametersProvider()
|
||||
@@ -81,7 +81,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
{
|
||||
$oExpression = Expression::FromOQL($sExpression);
|
||||
$value = $oExpression->Evaluate(array());
|
||||
static::assertEquals($expectedValue, $value);
|
||||
$this->assertEquals($expectedValue, $value);
|
||||
}
|
||||
|
||||
public function VariousExpressionsProvider()
|
||||
@@ -220,7 +220,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
$sNewExpression = "return $sExpression;";
|
||||
$oExpression = eval($sNewExpression);
|
||||
$res = $oExpression->Evaluate(array());
|
||||
static::assertEquals($expectedValue, $res);
|
||||
$this->assertEquals($expectedValue, $res);
|
||||
}
|
||||
|
||||
public function NotYetParsableExpressionsProvider()
|
||||
@@ -282,7 +282,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
$value = $aResults[0]["test_$i"];
|
||||
$expectedValue = $aTest[1];
|
||||
$this->debug("Test #$i: {$aTests[$i][0]} => ".var_export($value, true));
|
||||
static::assertEquals($expectedValue, $value);
|
||||
$this->assertEquals($expectedValue, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
|
||||
$res = $oObject->EvaluateExpression($oExpression);
|
||||
|
||||
static::assertEquals($expected, $res);
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
|
||||
public function ExpressionsWithObjectFieldsProvider()
|
||||
@@ -335,12 +335,18 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
{
|
||||
$oExpression = Expression::FromOQL($sExpression);
|
||||
$res = $oExpression->Evaluate($aParameters);
|
||||
static::assertEquals($expected, $res);
|
||||
$this->assertEquals($expected, $res);
|
||||
}
|
||||
|
||||
public function ExpressionWithParametersProvider()
|
||||
{
|
||||
return array(
|
||||
['`DBVariables["analyze_sample_percentage"]` > 10', ['DBVariables["analyze_sample_percentage"]' => 20], true],
|
||||
['`DataBase["DBDataSize"]`', ['DataBase["DBDataSize"]' => 4096], 4096],
|
||||
['`FileSystem["ItopInstallationIntegrity"]`', ['FileSystem["ItopInstallationIntegrity"]' => 'not_conform'], 'not_conform'],
|
||||
['`DBTablesInfo["attachment"].DataSize` > 100', ['DBTablesInfo["attachment"].DataSize' => 200], true],
|
||||
['`DBTablesInfo[].DataSize` > 100', ['DBTablesInfo[].DataSize' => 50], false],
|
||||
['(`DBTablesInfo[].DataSize` > 100) AND (`DBTablesInfo[].DataFree` * 100 / (`DBTablesInfo[].DataSize` + `DBTablesInfo[].IndexSize` + `DBTablesInfo[].DataFree`) > 10)', ['DBTablesInfo[].DataSize' => 200, 'DBTablesInfo[].DataFree' => 100, 'DBTablesInfo[].IndexSize' => 10], true],
|
||||
array('CONCAT(SUBSTR(name, 4), " cause")', array('name' => 'noble'), 'le cause'),
|
||||
);
|
||||
}
|
||||
@@ -364,11 +370,11 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
$res = $oExpression->IsTrue();
|
||||
if ($bExpectTrue)
|
||||
{
|
||||
static::assertTrue($res, 'arg: '.$sExpression);
|
||||
$this->assertTrue($res, 'arg: '.$sExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
static::assertFalse($res, 'arg: '.$sExpression);
|
||||
$this->assertFalse($res, 'arg: '.$sExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,10 +415,10 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
if ($bProcessed)
|
||||
{
|
||||
$sqlValue = CMDBSource::QueryToScalar("SELECT DATE_FORMAT('$sDate', '%$sFormat')");
|
||||
static::assertEquals($sqlValue, $sValueOrException, 'Check test against MySQL');
|
||||
$this->assertEquals($sqlValue, $sValueOrException, 'Check test against MySQL');
|
||||
|
||||
$res = $oExpression->Evaluate(array());
|
||||
static::assertEquals($sValueOrException, $res, 'Check evaluation');
|
||||
$this->assertEquals($sValueOrException, $res, 'Check evaluation');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -505,7 +511,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
{
|
||||
$oExpression = new FunctionExpression('DATE_FORMAT', array(new ScalarExpression($sDate), new ScalarExpression("%$sFormat")));
|
||||
$itopExpressionResult = $oExpression->Evaluate(array());
|
||||
static::assertSame($aMysqlDateFormatRsultsForAllFormats[$sFormat], $itopExpressionResult, "Format %$sFormat not matching MySQL for '$sDate'");
|
||||
$this->assertSame($aMysqlDateFormatRsultsForAllFormats[$sFormat], $itopExpressionResult, "Format %$sFormat not matching MySQL for '$sDate'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user