Merge remote-tracking branch 'origin/support/2.7' into develop

This commit is contained in:
Pierre Goiffon
2020-04-20 16:08:15 +02:00
54 changed files with 302 additions and 104 deletions

View File

@@ -52,7 +52,7 @@ iTop also offers mass import tools and web services to integrate with your IT
## Last releases
### Versions 2.7.*
- 2.7.0-beta2 published on January 29, 2020
- 2.7.0-1 published on April 8, 2020
- [Changes since the previous version][62]
- [New features][63]
- [Migration notes][64]

View File

@@ -2148,20 +2148,30 @@ EOF
$iMaxFileSize = utils::ConvertToBytes(ini_get('upload_max_filesize'));
$sHTMLValue = "<div class=\"field_input_zone field_input_document\">\n";
$sHTMLValue .= "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"$iMaxFileSize\" />\n";
$sHTMLValue .= "<input type=\"hidden\" id=\"do_remove_{$iId}\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[remove]\" value=\"0\"/>\n";
$sHTMLValue .= "<input name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[filename]\" type=\"hidden\" id=\"$iId\" \" value=\"".htmlentities($sFileName,
ENT_QUOTES, 'UTF-8')."\"/>\n";
$sHTMLValue .= "<span id=\"name_$iInputId\"'>".htmlentities($sFileName, ENT_QUOTES,
'UTF-8')."</span><br/>\n";
$sHTMLValue .= "<span id=\"name_$iInputId\"' >".htmlentities($sFileName, ENT_QUOTES,
'UTF-8')."</span>&#160;&#160;";
$sHTMLValue .= "<div title=\"".htmlentities(Dict::S('UI:Button:RemoveDocument'), ENT_QUOTES, 'UTF-8'). "\" id=\"remove_attr_$iId\" class=\"button\" onClick=\"$('#file_$iId').val('');UpdateFileName('$iId', '');\" style=\"display: contents;\">";
$sHTMLValue .= "<div class=\"ui-icon ui-icon-trash\"></div></div>";
$sHTMLValue .= "</div>";
$sHTMLValue .= "<br/>\n";
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[fcontents]\" type=\"file\" id=\"file_$iId\" onChange=\"UpdateFileName('$iId', this.value)\"/>\n";
$sHTMLValue .= "</div>\n";
$sHTMLValue .= "{$sValidationSpan}{$sReloadSpan}\n";
if ($sFileName == '')
{
$oPage->add_ready_script("$('#remove_attr_{$iId}').hide();");
}
break;
case 'Image':
$aEventsList[] = 'validate';
$aEventsList[] = 'change';
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/edit_image.js');
$oDocument = $value; // Value is an ormDocument object
$oDocument = $value; // Value is an ormDocument objectm
$sDefaultUrl = $oAttDef->Get('default_image');
if (is_object($oDocument) && !$oDocument->IsEmpty())
{
@@ -3175,11 +3185,18 @@ EOF
if ($oAttDef->GetEditClass() == 'Document')
{
$oDocument = $this->Get($sAttCode);
$sDisplayValue = $this->GetAsHTML($sAttCode);
$sDisplayValue .= "<br/>".Dict::Format('UI:OpenDocumentInNewWindow_',
$oDocument->GetDisplayLink(get_class($this), $this->GetKey(), $sAttCode)).", \n";
$sDisplayValue .= "<br/>".Dict::Format('UI:DownloadDocument_',
$oDocument->GetDownloadLink(get_class($this), $this->GetKey(), $sAttCode)).", \n";
if (!$oDocument->IsEmpty())
{
$sDisplayValue = $this->GetAsHTML($sAttCode);
$sDisplayValue .= "<br/>".Dict::Format('UI:OpenDocumentInNewWindow_',
$oDocument->GetDisplayLink(get_class($this), $this->GetKey(), $sAttCode)).", \n";
$sDisplayValue .= "<br/>".Dict::Format('UI:DownloadDocument_',
$oDocument->GetDownloadLink(get_class($this), $this->GetKey(), $sAttCode)).", \n";
}
else
{
$sDisplayValue ='';
}
}
elseif ($oAttDef instanceof AttributeDashboard)
{
@@ -3518,14 +3535,6 @@ EOF
switch ($oAttDef->GetEditClass())
{
case 'Document':
// There should be an uploaded file with the named attr_<attCode>
$oDocument = $value['fcontents'];
if (!$oDocument->IsEmpty())
{
// A new file has been uploaded
$this->Set($sAttCode, $oDocument);
}
break;
case 'Image':
// There should be an uploaded file with the named attr_<attCode>
if ($value['remove'])
@@ -3751,7 +3760,8 @@ EOF
switch ($oAttDef->GetEditClass())
{
case 'Document':
$value = array('fcontents' => utils::ReadPostedDocument("attr_{$sFormPrefix}{$sAttCode}", 'fcontents'));
$aOtherData = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null, 'raw_data');
$value = array('fcontents' => utils::ReadPostedDocument("attr_{$sFormPrefix}{$sAttCode}", 'fcontents'), 'remove' => $aOtherData['remove']);
break;
case 'Image':

View File

@@ -837,7 +837,8 @@ class DisplayBlock
foreach($aStates as $sStateValue)
{
$aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8');
$sHtmlValue=$aGroupBy['group1']->MakeValueLabel($this->m_oFilter, $sStateValue, $sStateValue);
$aStateLabels[$sStateValue] = html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8');
$aCounts[$sStateValue] = (array_key_exists($sStateValue, $aCountsQueryResults))
? $aCountsQueryResults[$sStateValue]
@@ -946,7 +947,7 @@ class DisplayBlock
$iChartCounter++;
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
$sTitle = isset($aExtraParams['chart_title']) ? '<h1 style="text-align:center">'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1>' : '';
$sTitle = isset($aExtraParams['chart_title']) ? '<div class="main_header"><h1>&#160;'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1></div>' : '';
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" class=\"dashboard_chart\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : '';

View File

@@ -491,6 +491,18 @@ class utils
// Paginated selection
$aSelectedIds = utils::ReadParam('storedSelection', array());
$aSelectedObjIds = utils::ReadParam('selectObject', array());
//it means that the user has selected all the results of the search query
if (count($aSelectedObjIds) > 0 )
{
$sFilter=utils::ReadParam("sFilter",'',false,'raw_data');
if ($sFilter!='')
{
$oFullSetFilter=DBSearch::unserialize($sFilter);
}
}
if (count($aSelectedIds) > 0 )
{
if ($sSelectionMode == 'positive')

View File

@@ -1584,7 +1584,7 @@ EOF
$sTabs .= "<div class=\"printable-tab\" id=\"$sTabId\"><h2 class=\"printable-tab-title\">$sTabTitleForHtml</h2><div class=\"printable-tab-content\">".$sTabHtml."</div></div>\n";
$oPage->add_ready_script(
<<< EOF
oHiddeableChapters['$sTabId'] = '$sTabCodeForJs';
oHiddeableChapters['$sTabId'] = '$sTabTitleForHtml';
EOF
);
$i++;

View File

@@ -7706,10 +7706,17 @@ class AttributeBlob extends AttributeDefinition
// (temporary tables created on disk)
// We will have to remove the blobs from the list of attributes when doing the select
// then the use of Get() should finalize the load
if ($value instanceOf ormDocument && !$value->IsEmpty())
if ($value instanceOf ormDocument)
{
$aValues = array();
$aValues[$this->GetCode().'_data'] = $value->GetData();
if (!$value->IsEmpty())
{
$aValues[$this->GetCode().'_data'] = $value->GetData();
}
else
{
$aValues[$this->GetCode().'_data'] = '';
}
$aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
$aValues[$this->GetCode().'_filename'] = $value->GetFileName();
}

View File

@@ -3851,7 +3851,32 @@ abstract class DBObject implements iDisplay
*/
public function Copy($sDestAttCode, $sSourceAttCode)
{
$this->Set($sDestAttCode, $this->Get($sSourceAttCode));
$oTypeValueToCopy = MetaModel::GetAttributeDef(get_class($this), $sSourceAttCode);
$oTypeValueDest = MetaModel::GetAttributeDef(get_class($this), $sDestAttCode);
if ($oTypeValueToCopy instanceof AttributeText && $oTypeValueDest instanceof AttributeText)
{
if ($oTypeValueToCopy->GetFormat() == $oTypeValueDest->GetFormat())
{
$sValueToCopy = $this->Get($sSourceAttCode);
}
else
{
if ($oTypeValueToCopy->GetFormat() == 'text')// and $oTypeValueDest->GetFormat()=='HTML'
{
$sValueToCopy = $this->GetAsHTML($sSourceAttCode);
}
else
{// $oTypeValueToCopy->GetFormat() == 'HTML' and $oTypeValueDest->GetFormat()=='Text'
$sValueToCopy = utils::HtmlToText($this->Get($sSourceAttCode));
}
}
}
else
{
$sValueToCopy = $this->Get($sSourceAttCode);
}
$this->Set($sDestAttCode, $sValueToCopy);
return true;
}

View File

@@ -553,14 +553,12 @@ JS
/**
* Garbage collector for cleaning "old" temporary InlineImages (and Attachments).
* This background process runs every hour and deletes all temporary InlineImages and Attachments
* whic are are older than one hour.
*/
class InlineImageGC implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 1; // Runs every 8 hours
return 1;
}
/**
@@ -593,6 +591,9 @@ class InlineImageGC implements iBackgroundProcess
}
/**
* Remove $sClass instance based on their `expire` field value.
* This `expire` field contains current time + draft_attachments_lifetime config parameter, it is initialized on object creation.
*
* @param string $sClass
* @param int $iTimeLimit
* @param string $sDateLimit

View File

@@ -131,7 +131,7 @@ class SQLUnionQuery extends SQLQuery
if ($bGetCount)
{
$sSelects = "({$sLimitStart}".implode(" {$sLimit}{$sLimitEnd}{$sLineSep} UNION{$sLineSep} {$sLimitStart}", $aSelects)." {$sLimit}{$sLimitEnd})";
$sSelects = "{$sLimitStart}".implode(" {$sLimit}{$sLimitEnd}{$sLineSep} UNION{$sLineSep} {$sLimitStart}", $aSelects)." {$sLimit}{$sLimitEnd}";
$sFrom = "({$sLineSep}{$sSelects}{$sLineSep}) as __selects__";
$sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep 1 $sLineSep FROM {$sFrom}{$sLineSep}) AS _union_alderaan_";
}

View File

@@ -17,7 +17,7 @@
*/
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
$version: "v2.7.0";
$version: "v2.7.0-1";
$approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css
// Base colors

View File

@@ -2371,6 +2371,16 @@ fieldset .details>.field_container {
display: inline-block;
margin-bottom: 2px;
}
.button{
cursor: pointer;
margin-bottom: 3px;
padding: 2px;
.ui-icon {
background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_ffffff_256x240.png?v=" + $version);
background-color: $highlight-color;
}
}
}
&.field_input_image{
@@ -3547,7 +3557,7 @@ table.listResults .originColor{
background: #fdfdfd none;
border-radius: 2px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15), 0 0 1px 1px rgb(241, 241, 241, 0.7);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15), 0 0 1px 1px rgba(241, 241, 241, 0.7);
color: $gray-darker;
text-shadow: none;

View File

@@ -33,7 +33,7 @@
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
background-position: 0 50%;
}
}
@keyframes bg-pan-left {
@@ -41,7 +41,7 @@
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
background-position: 0 50%;
}
}
/* Theme */
@@ -51,7 +51,7 @@ body {
margin: 0;
padding: 0;
font-size: 10pt;
font-family: Tahoma, Verdana, Arial, Helvetica;
font-family: Tahoma, Verdana, Arial, Helvetica, serif;
overflow-y: auto;
}
h1 {
@@ -92,9 +92,7 @@ a:hover {
margin-right: 20px;
}
#header h1 {
vertical-align: middle;
height: 54px;
noline-height: 54px;
margin: 0;
}
#setup {
@@ -153,8 +151,6 @@ td.input {
}
table.formTable {
border: 0;
cellpadding: 2px;
cellspacing: 0;
}
.wizlabel, .wizinput {
color: #000;

View File

@@ -65,7 +65,7 @@ $progress-bar-error-bg-color: #F56565 !default;
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
background-position: 0 50%;
}
}
@keyframes bg-pan-left {
@@ -73,7 +73,7 @@ $progress-bar-error-bg-color: #F56565 !default;
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
background-position: 0 50%;
}
}
@@ -84,7 +84,7 @@ body {
margin: 0;
padding: 0;
font-size: 10pt;
font-family: Tahoma, Verdana, Arial, Helvetica;
font-family: Tahoma, Verdana, Arial, Helvetica, serif;
overflow-y: auto;
}
h1 {
@@ -126,9 +126,7 @@ a{
margin-right: 20px;
}
h1 {
vertical-align: middle;
height: 54px;
noline-height: 54px;
margin: 0;
}
}
@@ -191,8 +189,6 @@ td.input {
}
table.formTable {
border: 0;
cellpadding: 2px;
cellspacing: 0;
}
.wizlabel, .wizinput {
color: #000;

View File

@@ -89,6 +89,10 @@ try
try
{
$oDoc = utils::ReadPostedDocument('file');
if ($oDoc->IsEmpty())
{
throw new FileUploadException(Dict::S('Attachments:Error:UploadedFileEmpty'));
}
/** @var Attachment $oAttachment */
$oAttachment = MetaModel::NewObject('Attachment');
$oAttachment->Set('expire', time() + MetaModel::GetConfig()->Get('draft_attachments_lifetime'));

View File

@@ -32,6 +32,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Attachments:NoAttachment' => 'No attachment. ',
'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.',
'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s',
'Attachments:Error:UploadedFileEmpty' => 'The received file is empty. Check that your server disk is not full.',
'Attachments:Render:Icons' => 'Display as icons',
'Attachments:Render:Table' => 'Display as list',
));

View File

@@ -31,6 +31,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Attachments:NoAttachment' => 'Aucune pièce jointe.',
'Attachments:PreviewNotAvailable' => 'Pas d\'aperçu pour ce type de pièce jointe.',
'Attachments:Error:FileTooLarge' => 'Le fichier est trop gros pour être chargé. %1$s',
'Attachments:Error:UploadedFileEmpty' => 'Le fichier téléchargé est vide. Vérifiez qu\'il reste de la place disque disponible sur le serveur',
'Attachments:Render:Icons' => 'Affichage en icônes',
'Attachments:Render:Table' => 'Affichage en liste',
));

View File

@@ -173,7 +173,7 @@ abstract class AbstractAttachmentsRenderer
$(sContentNode).html(data);
$(sContentNode).unblock();
}
);
)
}
$('#file').fileupload({
@@ -181,8 +181,20 @@ abstract class AbstractAttachmentsRenderer
formData: { operation: 'add', temp_id: '$this->sTransactionId', obj_class: '$sClass' },
dataType: 'json',
pasteZone: null, // Don't accept files via Chrome's copy/paste
done: RefreshAttachmentsDisplay,
send: function(e, data){
done: function (e, data) {
if(typeof(data.result.error) != 'undefined')
{
if(data.result.error !== '')
{
alert(data.result.error);
}
else
{
RefreshAttachmentsDisplay();
}
}
},
send: function(e, data){
// Don't send attachment if size is greater than PHP post_max_size, otherwise it will break the request and all its parameters (\$_REQUEST, \$_POST, ...)
// Note: We loop on the files as the data structures is an array but in this case, we only upload 1 file at a time.
var iTotalSizeInBytes = 0;

View File

@@ -23,7 +23,7 @@
// Developer's notes:
// Duplicated code: sys_get_temp_dir, the computation of the target filename, etc.
// Recommended usage in CRON
// Recommended usage in cron
// /usr/bin/php -q /var/www/combodo/modules/itop-backup/check-backup.php --backup_file=/home/backups/combodo-crm-%Y-%m-%d
// Do not forget to set the 'itop_backup_incident' configuration file parameter !

View File

@@ -639,14 +639,8 @@ class ObjectController extends BrickController
$oSet = new DBObjectSet($oSearch, array(), array('this' => $oHostObject, 'ac_query' => '%'.$sQuery.'%'));
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array('friendlyname')));
// Note : This limit is also used in the field renderer by typeahead to determine how many suggestions to display
if ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
$oSet->SetLimit(static::DEFAULT_LIST_LENGTH);
}
else
{
$oSet->SetLimit($oTargetAttDef->GetMaximumComboLength()); // TODO : Is this the right limit value ? We might want to use another parameter
}
$oSet->SetLimit(MetaModel::GetConfig()->Get('max_display_limit'));
// - Retrieving objects
while ($oItem = $oSet->Fetch())
{

View File

@@ -1136,7 +1136,15 @@ class ObjectFormManager extends FormManager
if ($bWasModified)
{
$aData['messages']['success'] += array('_main' => array(Dict::Format('Brick:Portal:Object:Form:Message:ObjectSaved', $this->oObject->GetName())));
//=if (isNew) because $bActivateTriggers = (!$this->oObject->IsNew() && $this->oObject->IsModified())
if(!$bActivateTriggers)
{
$aData['messages']['success'] += array( '_main' => array(Dict::Format('UI:Title:Object_Of_Class_Created', $this->oObject->GetName(),MetaModel::GetName(get_class($this->oObject)))));
}
else
{
$aData['messages']['success'] += array('_main' => array(Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($this->oObject)), $this->oObject->GetName())));
}
}
}
catch (Exception $e)

View File

@@ -210,7 +210,7 @@ Operátory:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -208,7 +208,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -207,7 +207,7 @@ Operatoren:<br/>
'Core:Context=Synchro' => 'Synchro',
'Core:Context=Setup' => 'Setup',
'Core:Context=GUI:Console' => 'Konsole',
'Core:Context=CRON' => 'CRON',
'Core:Context=CRON' => 'cron',
'Core:Context=GUI:Portal' => 'Portal',
));

View File

@@ -208,7 +208,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro',
'Core:Context=Setup' => 'Setup',
'Core:Context=GUI:Console' => 'Console',
'Core:Context=CRON' => 'CRON',
'Core:Context=CRON' => 'cron',
'Core:Context=GUI:Portal' => 'Portal',
));

View File

@@ -422,6 +422,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Button:Insert' => 'Insert',
'UI:Button:More' => 'More',
'UI:Button:Less' => 'Less',
'UI:Button:Wait' => 'Please wait while updating fields',
'UI:SearchToggle' => 'Search',
'UI:ClickToCreateNew' => 'Create a new %1$s',
@@ -1447,6 +1448,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:Button:RemoveImage' => 'Remove the image',
'UI:UploadNotSupportedInThisMode' => 'The modification of images or files is not supported in this mode.',
'UI:Button:RemoveDocument' => 'Remove the document',
// Search form
'UI:Search:Toggle' => 'Minimize / Expand',
'UI:Search:AutoSubmit:DisabledHint' => '<i class="fas fa-sync fa-1x"></i> Auto submit has been disabled for this class',

View File

@@ -208,7 +208,7 @@ Operadores:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -206,7 +206,7 @@ Opérateurs :<br/>
'Core:Context=Synchro' => 'Synchro',
'Core:Context=Setup' => 'Setup',
'Core:Context=GUI:Console' => 'Console',
'Core:Context=CRON' => 'CRON',
'Core:Context=CRON' => 'cron',
'Core:Context=GUI:Portal' => 'Portal',
));
@@ -1051,6 +1051,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Core:Context=Synchro+' => 'Synchro',
'Core:Context=Setup+' => 'Setup',
'Core:Context=GUI:Console+' => 'GUI:Console',
'Core:Context=CRON+' => 'CRON',
'Core:Context=CRON+' => 'cron',
'Core:Context=GUI:Portal+' => 'GUI:Portal',
));

View File

@@ -405,6 +405,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Button:Insert' => 'Insérer',
'UI:Button:More' => 'Plus',
'UI:Button:Less' => 'Moins',
'UI:Button:Wait' => 'Patientez pendant la mise à jour des champs',
'UI:SearchToggle' => 'Recherche',
'UI:ClickToCreateNew' => 'Créer un nouvel objet de type %1$s',
@@ -1427,6 +1428,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:Button:RemoveImage' => 'Supprimer l\'image',
'UI:UploadNotSupportedInThisMode' => 'La modification d\'images ou de fichiers n\'est pas supportée dans ce mode.',
'UI:Button:RemoveDocument' => 'Supprimer le document',
// Search form
'UI:Search:Toggle' => 'Réduire / Ouvrir',
'UI:Search:AutoSubmit:DisabledHint' => '<i class="fas fa-sync fa-1x"></i> La soumission automatique a été desactivée pour cette classe',

View File

@@ -206,7 +206,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -208,7 +208,7 @@ Operatori:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -206,7 +206,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -214,7 +214,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro',
'Core:Context=Setup' => 'Setup',
'Core:Context=GUI:Console' => 'Console',
'Core:Context=CRON' => 'CRON',
'Core:Context=CRON' => 'cron',
'Core:Context=GUI:Portal' => 'Portaal',
));

View File

@@ -208,7 +208,7 @@ Operadores:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -195,7 +195,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -205,7 +205,7 @@ Operatori:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -216,7 +216,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -207,7 +207,7 @@ Operators:<br/>
'Core:Context=Synchro' => 'Synchro~~',
'Core:Context=Setup' => 'Setup~~',
'Core:Context=GUI:Console' => 'Console~~',
'Core:Context=CRON' => 'CRON~~',
'Core:Context=CRON' => 'cron~~',
'Core:Context=GUI:Portal' => 'Portal~~',
));

View File

@@ -91,7 +91,7 @@ In order to ease the installation, all the background tasks have been grouped to
<li>Edit the file <b>cron.params</b> to set the credentials used for cronified tasks</li>
<li>Edit the file <em>&lt;itop root&gt</em>/webservices/<b>cron.cmd</b>, and set the relevant path for your installation of PHP.</li>
<li>Schedule the execution of cron.cmd:
<pre>schtasks.exe /create /tn "iTop CRON" /sc minute /mo 1 /tr "\"<em>&lt;itop root&gt</em>/webservices/cron.cmd\""</pre>
<pre>schtasks.exe /create /tn "iTop Cron" /sc minute /mo 1 /tr "\"<em>&lt;itop root&gt</em>/webservices/cron.cmd\""</pre>
</li>
</ol>

View File

@@ -143,6 +143,13 @@ var oFormErrors = { err_form0: 0 };
function CheckFields(sFormId, bDisplayAlert)
{
// if some fields are in wait, no submit is allowed
if ($('#'+sFormId+' .blockMsg').length>0)
{
alert(Dict.S('UI:Button:Wait'));
return false;
}
$('#'+sFormId+' :submit').prop('disable', true);
$('#'+sFormId+' :button[type=submit]').prop('disable', true);
firstErrorId = '';
@@ -171,6 +178,7 @@ function CheckFields(sFormId, bDisplayAlert)
$('#'+oFormErrors['input_'+sFormId]).focus();
}
}
return (oFormErrors['err_'+sFormId] == 0); // If no error, submit the form
}

View File

@@ -185,15 +185,7 @@ $(function()
.trigger('itop.search.criteria_enum.autocomplete.submit');
});
// - Check / Uncheck all toggler
oTogglerElem.on('click', function(oEvent){
// Check / uncheck all allowed values
var bChecked = $(this).closest('.sfc_opc_mc_toggler').find('input:checkbox').prop('checked');
oOpContentElem.find('.sfc_opc_mc_item:visible input:checkbox').prop('checked', bChecked);
// Apply criteria
//me._apply();
});
if(this._hasAutocompleteAllowedValues())
{
@@ -208,12 +200,21 @@ $(function()
{
var me = this;
var oOpContentElem = oOpElem.find('.sfc_opc_multichoices');
var oTogglerElem = oOpContentElem.find('.sfc_opc_mc_toggler');
var oFilterElem = oOpContentElem.find('.sf_filter');
var oAllowedValuesElem = oOpContentElem.find('.sfc_opc_mc_items');
var oDynamicListElem = oOpContentElem.find('.sfc_opc_mc_items_dynamic');
// - Check / Uncheck all toggler
oTogglerElem.on('click', function(oEvent){
// Check / uncheck all allowed values
var bChecked = $(this).closest('.sfc_opc_mc_toggler').find('input:checkbox').prop('checked');
oOpContentElem.find('.sfc_opc_mc_item:visible input:checkbox').prop('checked', bChecked);
});
// DOM elements
// - Filter
oFilterElem.find('.sff_input_wrapper')
@@ -295,9 +296,62 @@ $(function()
var oValuesWrapperElem = oOpContentElem.find('.sfc_opc_mc_items_wrapper');
var oAllowedValuesElem = oValuesWrapperElem.find('.sfc_opc_mc_items');
// - Check / Uncheck all toggler
oTogglerElem.on('click', function(oEvent){
// Check / uncheck all allowed values
var bChecked = $(this).closest('.sfc_opc_mc_toggler').find('input:checkbox').prop('checked');
if(bChecked)
{
// - Apply on check
oAllowedValuesElem.find('.sfc_opc_mc_item input').each(function(){
if(!$(this).find("input[type=\"checkbox\"]").is(":checked"))
{
var oItemElem = $(this).closest('.sfc_opc_mc_item');
// Hide item
oItemElem.hide();
// Copy item to selected items list
var oValues = {};
oValues[oItemElem.find('input:checkbox').val()] = oItemElem.text();
me._addSelectedValues(oValues);
}
});
}
else
{
// - Apply on uncheck
oAllowedValuesElem.find('.sfc_opc_mc_item').each(function(){
if(!$(this).is(":visible"))
{
// Show item among allowed values (if still there, could have been removed by another search needle)
var oAllowedValueElem = oAllowedValuesElem.find('.sfc_opc_mc_item[data-value-code="'+$(this).attr('data-value-code')+'"]');
if (oAllowedValueElem.length > 0)
{
oAllowedValuesElem.find('.sfc_opc_mc_item[data-value-code="'+$(this).attr('data-value-code')+'"]')
.show()
.find('input:checkbox')
.prop('checked', false);
}
// Remove item from selected values
$(this).closest(".sfc_opc_mc_items_wrapper").find('.sfc_opc_mc_items_selected').find('.sfc_opc_mc_item[data-value-code="'+$(this).attr('data-value-code')+'"]').remove();
}
});
oAllowedValuesElem.closest(".sfc_opc_mc_items_wrapper").find('.sfc_opc_mc_items_selected').find('.sfc_opc_mc_item').each(function(){
//$(this).add(oAllowedValuesElem);
$(this).remove();
});
me._refreshSelectedValues();
}
});
// DOM
// - Hide toggler for now
oTogglerElem.hide();
//but when there are values under the search, this checkbox must come back
// - Set typing hint
this._setACTypingHint();
@@ -379,7 +433,6 @@ $(function()
.done(function(oResponse, sStatus, oXHR){
me._onACSearchSuccess(oResponse);
if (Object.keys(oResponse).length >= 150)
{
me._emptyACTempHint();
@@ -406,16 +459,26 @@ $(function()
});
me._onACSearchContainsSuccess(oResponseContains);
});
})
.fail(function(oResponse, sStatus, oXHR){ me._onACSearchFail(oResponse, sStatus); })
.always(function(oResponse, sStatus, oXHR){ me._onACSearchAlways(); });
.always(function(oResponse, sStatus, oXHR){
me._onACSearchAlways();
if (me.element.find('.sfc_opc_mc_item').length>0)
{
oTogglerElem.show();
}
else
{
oTogglerElem.hide();
}
});
oFilterElem.find('.sff_reset').show();
}, me.options.autocomplete.xhr_throttle);
}
me._updateTogglerLabel();
});
// - Apply on check
@@ -464,6 +527,11 @@ $(function()
oFilterElem.find('.sff_search_dialog').on('click', function(){
oForeignKeysWidgetCurrent.ShowModalSearchForeignKeys();
});
var oTogglerTextElem = this.element.find('.sfc_opc_mc_toggler label span');
var sFilterVal = this.element.find('.sf_filter input[type="text"]').val();
oTogglerTextElem.text( oTogglerTextElem.attr('data-label-filtered'));
},
_computeTitle: function(sTitle)
{
@@ -794,6 +862,15 @@ $(function()
oSelectedValuesElem.hide();
}
var oTogglerElem= this.element.find('.sfc_opc_multichoices').find('.sfc_opc_mc_toggler');
if (this.element.find('.sfc_opc_mc_item').length>0)
{
oTogglerElem.show();
}
else
{
oTogglerElem.hide();
}
// TODO: Reorder
// oSelectedValuesElem.html('');
// var aSortedValues = this._sortValuesByLabel(this.options.values);

View File

@@ -47,7 +47,6 @@ function SearchFormForeignKeys(id, sTargetClass, sAttCode, oSearchWidgetElmt, sF
$('#linkedset_'+this.id+' .selection').each( function() { this.checked = false; });
$('#'+this.id+'_btnRemove').prop('disabled', false);
$('<div id="dlg_'+me.id+'"></div>').appendTo(document.body);
// me.trace(dialog);
@@ -169,7 +168,7 @@ function SearchFormForeignKeys(id, sTargetClass, sAttCode, oSearchWidgetElmt, sF
var theMap = {
sTargetClass: me.sTargetClass,
iInputId: me.id,
sFilter: me.sFilter
sFilter: me.sfilter,
// bSearchMode: me.bSearchMode
};
@@ -262,6 +261,7 @@ function SearchFormForeignKeys(id, sTargetClass, sAttCode, oSearchWidgetElmt, sF
$(this).parents('tr:first').remove(); // Remove the whole line, so that, next time the dialog gets displayed it's no longer there
}
);
theMap["sFilter"] = $('#datatable_ResultsToAdd_'+me.id).data().itopDatatable.options.sFilter;
theMap["class"] = me.sTargetClass;
theMap['operation'] = 'GetFullListForeignKeysFromSelection';
$('#busy_'+me.iInputId).html('&nbsp;<img src="../images/indicator.gif"/>');

View File

@@ -244,6 +244,17 @@ function UpdateFileName(id, sNewFileName) {
$('#'+id).val(sNewFileName);
$('#'+id).trigger('validate');
$('#name_'+id).text(sNewFileName);
if(sNewFileName=='')
{
$('#do_remove_'+id).val('1');
$('#remove_attr_' + id).hide();
}
else
{
$('#do_remove_'+id).val('0');
$('#remove_attr_' + id).show();
}
return true;
}

View File

@@ -564,7 +564,7 @@ try
$sFullText = trim($aMatches[2]);
}
}
$sFullText = str_replace('_', '\_', $sFullText);
if (preg_match('/^"(.*)"$/', $sFullText, $aMatches))
{
// The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
@@ -596,7 +596,7 @@ try
break;
}
$sFullText = implode(' ', $aFullTextNeedles);
$sFullText = str_replace('\_', '_', $sFullText);
// Sanity check of the accelerators
/** @var array $aAccelerators */
$aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators');

View File

@@ -763,7 +763,6 @@ try
}
else
{
$iFlags = MetaModel::GetAttributeFlags($sClass, $oObj->GetState(), $sAttCode);
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix), false);
// Make sure that we immediately validate the field when we reload it
$oPage->add_ready_script("$('#$sId').trigger('validate');");

View File

@@ -455,7 +455,7 @@ try
// Do nothing
}
}
$sHtmlValue = $oCellStatus->GetDisplayableValue();
$sHtmlValue = utils::HtmlEntities(utils::HtmlEntityDecode($oCellStatus->GetDisplayableValue()));
switch(get_class($oCellStatus))
{
case 'CellStatus_Issue':

View File

@@ -309,12 +309,18 @@ EOF
$aRootClasses[$sClassName] = MetaModel::GetName($sClassName);
}
$sLabelClassName = MetaModel::GetName($sClassName);
//Fetch classes names for autocomplete purpose
// - Encode as JSON to escape quotes and other characters
$sClassLabelAndCodeAsJSON = json_encode("$sLabelClassName ($sClassName)");
$sClassLabelAsJSON = json_encode($sLabelClassName);
$sClassCodeAsJSON = json_encode($sClassName);
// - Push to autocomplete
$oPage->add_script(
<<<EOF
autocompleteClassLabelAndCode.push("$sLabelClassName ($sClassName)");
autocompleteClassLabel.push("$sLabelClassName");
autocompleteClassCode.push("$sClassName");
autocompleteClassLabelAndCode.push($sClassLabelAndCodeAsJSON);
autocompleteClassLabel.push($sClassLabelAsJSON);
autocompleteClassCode.push($sClassCodeAsJSON);
EOF
);
}

View File

@@ -147,6 +147,12 @@ abstract class ModuleInstallerAPI
{
$aCurrentValues = explode("','", $aMatches[1]);
}
else
{
// not an enum currently : return !
// we could update values, but a clear error message will be displayed when altering the column
return;
}
}
if (!in_array($sFrom, $aNewValues))
{

View File

@@ -113,6 +113,7 @@ class SetupUtils
'openssl' => 'Strong encryption will not be used.',
),
'ldap' => 'LDAP authentication will be disabled.',
'mbstring' => 'For CryptEngine implementations, trace in Mail to ticket automation', // N°2891
);
asort($aMandatoryExtensions); // Sort the list to look clean !

View File

@@ -658,7 +658,7 @@ EOF
if ($oMutex->IsLocked())
{
$oPage->add(<<<HTML
<div class="message">An iTop CRON process is being executed on the target database. iTop CRON process will be stopped during the setup execution.</div>
<div class="message">An iTop cron process is being executed on the target database. iTop cron process will be stopped during the setup execution.</div>
HTML
);
}

View File

@@ -123,6 +123,7 @@ class CriterionToOQL extends CriterionConversionAbstract
{
return "1";
}
$sValue = str_replace('_', '\_', $sValue);
return "({$sRef} LIKE '%{$sValue}%')";
}

View File

@@ -44,6 +44,7 @@ use MissingQueryArgument;
use TrueExpression;
use utils;
use WebPage;
use UserRights;
class SearchForm
{
@@ -131,7 +132,10 @@ class SearchForm
$aOptions[MetaModel::GetName($sRootClass)] = "<option value=\"$sRootClass\">".MetaModel::GetName($sRootClass)."</options>\n";
foreach($aSubClasses as $sSubclassName)
{
$aOptions[MetaModel::GetName($sSubclassName)] = "<option value=\"$sSubclassName\">".MetaModel::GetName($sSubclassName)."</options>\n";
if (UserRights::IsActionAllowed($sSubclassName, UR_ACTION_READ))
{
$aOptions[MetaModel::GetName($sSubclassName)] = "<option value=\"$sSubclassName\">".MetaModel::GetName($sSubclassName)."</options>\n";
}
}
$aOptions[MetaModel::GetName($sClassName)] = "<option selected value=\"$sClassName\">".MetaModel::GetName($sClassName)."</options>\n";
ksort($aOptions);

View File

@@ -176,7 +176,7 @@ EOF
// - Opening input group
$oOutput->AddHtml('<div class="input-group selectobject">');
// - Rendering autocomplete search
$oOutput->AddHtml('<input type="text" id="' . $sAutocompleteFieldId . '" name="' . $sAutocompleteFieldId . '" value="')->AddHtml($sFieldValue)->AddHtml('" data-target-id="' . $this->oField->GetGlobalId() . ' "class="form-control" />');
$oOutput->AddHtml('<input type="text" id="' . $sAutocompleteFieldId . '" name="' . $sAutocompleteFieldId . '" value="')->AddHtml($sFieldValue)->AddHtml('" data-target-id="' . $this->oField->GetGlobalId() . '" class="form-control" />');
$oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" />');
// - Rendering buttons
// - Rendering hierarchy button
@@ -207,14 +207,15 @@ EOF
// Updating autocomplete field
me.element.find('#{$this->oField->GetGlobalId()}').val(sItemId);
me.element.find('#{$sAutocompleteFieldId}').val(sItemName);
oAutocompleteSource_{$this->oField->GetId()}.index.datums[sItemId] = {id: sItemId, name: sItemName};
oAutocompleteSource_{$this->oField->GetId()}.index.datums[sItemId] = {id: sItemId, name: sItemName};
$('#$sAutocompleteFieldId').typeahead('val', sItemName);
//console.log('callback', oData);
// Triggering field change event
me.element.closest(".field_set").trigger("field_change", {
id: me.element.find('#{$this->oField->GetGlobalId()}').attr("id"),
name: me.element.find('#{$this->oField->GetGlobalId()}').attr("name"),
value: me.element.find('#{$this->oField->GetGlobalId()}').val()
});
});
}
});
EOF
@@ -426,7 +427,7 @@ JS
},
},
};
if($('.modal[data-source-element="{$sSearchButtonId}"]').length === 0)
{
oOptions['attributes'] = {'data-source-element': '{$sSearchButtonId}'};

View File

@@ -1,4 +1,4 @@
# CRON parameters file used by cron.cmd
# cron parameters file used by cron.cmd
#
# Warning: make sure that this file is NOT readable by the web server

View File

@@ -479,11 +479,11 @@ set_time_limit(0); // Some background actions may really take long to finish (li
if (utils::IsModeCLI())
{
$oP = new CLIPage("iTop - CRON");
$oP = new CLIPage("iTop - cron");
}
else
{
$oP = new WebPage("iTop - CRON");
$oP = new WebPage("iTop - cron");
}
try