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

# Conflicts:
#	application/displayblock.class.inc.php
#	core/config.class.inc.php
#	datamodels/2.x/authent-cas/module.authent-cas.php
#	datamodels/2.x/authent-external/module.authent-external.php
#	datamodels/2.x/authent-ldap/module.authent-ldap.php
#	datamodels/2.x/authent-local/module.authent-local.php
#	datamodels/2.x/combodo-backoffice-darkmoon-theme/module.combodo-backoffice-darkmoon-theme.php
#	datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php
#	datamodels/2.x/itop-attachments/module.itop-attachments.php
#	datamodels/2.x/itop-backup/module.itop-backup.php
#	datamodels/2.x/itop-bridge-cmdb-ticket/module.itop-bridge-cmdb-ticket.php
#	datamodels/2.x/itop-bridge-virtualization-storage/module.itop-bridge-virtualization-storage.php
#	datamodels/2.x/itop-change-mgmt-itil/module.itop-change-mgmt-itil.php
#	datamodels/2.x/itop-change-mgmt/module.itop-change-mgmt.php
#	datamodels/2.x/itop-config-mgmt/module.itop-config-mgmt.php
#	datamodels/2.x/itop-config/module.itop-config.php
#	datamodels/2.x/itop-core-update/module.itop-core-update.php
#	datamodels/2.x/itop-datacenter-mgmt/module.itop-datacenter-mgmt.php
#	datamodels/2.x/itop-endusers-devices/module.itop-endusers-devices.php
#	datamodels/2.x/itop-faq-light/module.itop-faq-light.php
#	datamodels/2.x/itop-files-information/module.itop-files-information.php
#	datamodels/2.x/itop-full-itil/module.itop-full-itil.php
#	datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php
#	datamodels/2.x/itop-incident-mgmt-itil/module.itop-incident-mgmt-itil.php
#	datamodels/2.x/itop-knownerror-mgmt/module.itop-knownerror-mgmt.php
#	datamodels/2.x/itop-portal-base/module.itop-portal-base.php
#	datamodels/2.x/itop-portal/module.itop-portal.php
#	datamodels/2.x/itop-problem-mgmt/module.itop-problem-mgmt.php
#	datamodels/2.x/itop-profiles-itil/module.itop-profiles-itil.php
#	datamodels/2.x/itop-request-mgmt-itil/module.itop-request-mgmt-itil.php
#	datamodels/2.x/itop-request-mgmt/module.itop-request-mgmt.php
#	datamodels/2.x/itop-service-mgmt-provider/module.itop-service-mgmt-provider.php
#	datamodels/2.x/itop-service-mgmt/module.itop-service-mgmt.php
#	datamodels/2.x/itop-sla-computation/module.itop-sla-computation.php
#	datamodels/2.x/itop-storage-mgmt/module.itop-storage-mgmt.php
#	datamodels/2.x/itop-structure/module.itop-structure.php
#	datamodels/2.x/itop-tickets/module.itop-tickets.php
#	datamodels/2.x/itop-virtualization-mgmt/module.itop-virtualization-mgmt.php
#	datamodels/2.x/itop-welcome-itil/module.itop-welcome-itil.php
#	datamodels/2.x/version.xml
This commit is contained in:
Pierre Goiffon
2022-02-08 15:43:20 +01:00
48 changed files with 294 additions and 193 deletions

View File

@@ -26,7 +26,7 @@ require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
$aFilesUpdaters = array(
new iTopVersionFileUpdater(),
new DatamodelsModulesFiles(),
new ConstantFileUpdater('ITOP_CORE_VERSION', 'core/config.class.inc.php'),
new ConstantFileUpdater('ITOP_CORE_VERSION', 'approot.inc.php'),
);
if (count($argv) === 1)

View File

@@ -391,7 +391,7 @@ JS
$oSingletonFilter = new DBObjectSearch(get_class($this));
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
$oBlock = new MenuBlock($oSingletonFilter, 'details', false);
$oActionMenuBlock = $oBlock->GetRenderContent($oPage);
$oActionMenuBlock = $oBlock->GetRenderContent($oPage, [], uniqid('', true));
$aHeaderBlocks['toolbar'][$oActionMenuBlock->GetId()] = $oActionMenuBlock;
}

View File

@@ -539,8 +539,10 @@ class DisplayBlock
* @throws DictExceptionMissingString
* @throws MySQLException
* @throws Exception
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 add type hinting to $aExtraParams
*/
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
{
$sHtml = '';
$oBlock = null;
@@ -1732,11 +1734,10 @@ class MenuBlock extends DisplayBlock
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value and add type hinting on $aExtraParams for PHP 8.0 compatibility
*/
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
{
$oRenderBlock = new UIContentBlock();

View File

@@ -61,6 +61,8 @@ class UIExtKeyWidget
protected $sAttCode;
protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
/**
* @param \WebPage $oPage
* @param string $sAttCode
@@ -80,18 +82,13 @@ class UIExtKeyWidget
* @throws \Exception
*
* @since 3.0.0 N°3750 new $sInputType parameter
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
*/
public static function DisplayFromAttCode(
$oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '',
$aArgs = [], $bSearchMode = false, &$sInputType = ''
)
{
// we will only use key & name, so let's reduce fields loaded !
$aAttToLoad = [
$sClass => [], // nothing, id and friendlyname are automatically added by the API
];
$oAllowedValues->OptimizeColumnLoad($aAttToLoad);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sTargetClass = $oAttDef->GetTargetClass();
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
@@ -776,9 +773,11 @@ JS
*
* @throws CoreException
* @throws OQLException
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
*/
public function AutoComplete(
WebPage $oP, $sFilter, $oObj = null, $sContains = '', $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
)
{
if (is_null($sFilter)) {

View File

@@ -75,9 +75,15 @@ class UILinksWidgetDirect
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (handling wrong values at method start)
*/
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
{
if (empty($aArgs)) {
$aArgs = [];
}
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
switch($oLinksetDef->GetEditMode())
{
@@ -127,8 +133,10 @@ class UILinksWidgetDirect
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param bool $bDisplayMenu
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, always called with default value)
*/
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $bDisplayMenu)
{
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sTargetClass = $oLinksetDef->GetLinkedClass();
@@ -228,8 +236,10 @@ class UILinksWidgetDirect
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param array $aButtons
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, caller already handles it)
*/
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();

View File

@@ -2394,43 +2394,19 @@ class utils
}
/**
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
* @return string eg : '2_7_0' if iTop core version is '2.7.5-2'
* @throws \ApplicationException if constant value is invalid
* @uses ITOP_CORE_VERSION
*/
public static function GetItopVersionWikiSyntax() {
$sMinorVersion = self::GetItopMinorVersion();
public static function GetCoreVersionWikiSyntax($sItopVersion = ITOP_CORE_VERSION)
{
$aExplodedVersion = explode('.', $sItopVersion);
return str_replace('.', '_', $sMinorVersion).'_0';
}
/**
* @param string $sPatchVersion if non provided, will call GetItopPatchVersion
*
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
* @throws \Exception
*/
public static function GetItopMinorVersion($sPatchVersion = null) {
if (is_null($sPatchVersion)) {
$sPatchVersion = self::GetItopPatchVersion();
}
$aExplodedVersion = explode('.', $sPatchVersion);
if (count($aExplodedVersion) < 2) {
throw new Exception('iTop version is wrongfully configured!');
}
if (($aExplodedVersion[0] == '') || ($aExplodedVersion[1] == '')) {
throw new Exception('iTop version is wrongfully configured!');
if ((false === isset($aExplodedVersion[0])) || (false === isset($aExplodedVersion[1]))) {
throw new ApplicationException('iTop version is wrongfully configured!');
}
return sprintf('%d.%d', $aExplodedVersion[0], $aExplodedVersion[1]);
}
/**
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
*/
public static function GetItopPatchVersion() {
$aExplodedVersion = explode('-', ITOP_VERSION);
return $aExplodedVersion[0];
return "{$aExplodedVersion[0]}_{$aExplodedVersion[1]}_0";
}
/**

View File

@@ -13,4 +13,16 @@ define('APPCONF', APPROOT.'conf/');
*/
define('ITOP_DESIGN_LATEST_VERSION', '3.1');
/**
* Constant containing the iTop core version, whatever application was built
*
* Note that in iTop 3.0.0 we used {@see ITOP_DESIGN_LATEST_VERSION} to get core version.
* When releasing, both constants should be updated : see `.make/release/update-versions.php` for that !
*
* @since 2.7.7 3.0.1 3.1.0 N°4714 constant creation
* @used-by utils::GetCoreVersionWikiSyntax()
* @used-by iTopModulesPhpVersionIntegrationTest
*/
define('ITOP_CORE_VERSION', '3.1.0');
require_once APPROOT.'bootstrap.inc.php';

32
composer.lock generated
View File

@@ -2221,16 +2221,16 @@
},
{
"name": "symfony/twig-bundle",
"version": "v3.4.36",
"version": "v3.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bundle.git",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9"
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/977b3096e2df96bc8a8d2329e83466cfc30c373d",
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d",
"shasum": ""
},
"require": {
@@ -2263,11 +2263,6 @@
"symfony/yaml": "~2.8|~3.0|~4.0"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Bundle\\TwigBundle\\": ""
@@ -2292,7 +2287,24 @@
],
"description": "Symfony TwigBundle",
"homepage": "https://symfony.com",
"time": "2019-10-01T15:13:36+00:00"
"support": {
"source": "https://github.com/symfony/twig-bundle/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "symfony/yaml",

View File

@@ -31,17 +31,6 @@ define('ITOP_APPLICATION_SHORT', 'iTop');
*/
define('ITOP_VERSION', '3.1.0-dev');
/**
* Constant containing the iTop core version, whatever application was built
*
* Note that in iTop 3.0.0 we used {@see ITOP_DESIGN_LATEST_VERSION} to get core version.
* When releasing, both constants should be updated : see `.make/release/update-versions.php` for that !
*
* @since 2.7.7 3.0.1 3.1.1 N°4714 constant creation
* @used-by utils::GetItopPatchVersion
*/
define('ITOP_CORE_VERSION', '3.1.0');
define('ITOP_VERSION_NAME', 'Fullmoon');
define('ITOP_REVISION', 'svn');
define('ITOP_BUILD_DATE', '$WCNOW$');

View File

@@ -1236,7 +1236,7 @@ class DBObjectSearch extends DBSearch
elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass()))
{
// Specialize $oRightFilter
$oRightFilter->ChangeClass($oLeftFilter->GetClass());
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
}
else
{

View File

@@ -655,7 +655,7 @@ abstract class MetaModel
* @param string $sRuleId
*
* @throws \CoreException
* @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
* @since 2.6.1 N°1968 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
* definition of the rule in the hierarchy
*/
private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)

View File

@@ -494,7 +494,17 @@ class SQLObjectQuery extends SQLQuery
}
}
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias = '', $aJoinData)
/**
* @param \SQLObjectQuery $oRootQuery
* @param $aFrom
* @param $sCallerAlias
* @param $aJoinData
*
* @return string
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $sCallerAlias for PHP 8.0 compat (Private method with only 2 calls in the class, both providing the optional parameter)
*/
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias, $aJoinData)
{
$aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias;
$sJoinCond = '';
@@ -613,6 +623,7 @@ class SQLObjectQuery extends SQLQuery
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
foreach ($this->m_aJoinSelects as $aJoinData)
{
/** @var \SQLObjectQuery $oRightSelect */
$oRightSelect = $aJoinData["select"];
$oRightSelect->PrepareSingleTable($oRootQuery, $aTempFrom, $this->m_sTableAlias, $aJoinData);

View File

@@ -13,14 +13,16 @@ input + label, label + input, label > input {
margin-left: $ibo-input--spacing-left--with-label;
}
label.ibo-has-description {
&::after {
content: $ibo-field--label--description--content;
padding-left: $ibo-field--label--description--padding-left;
vertical-align: top;
.ibo-input-with-label--label {
&.ibo-has-description {
&::after {
content: $ibo-field--label--description--content;
padding-left: $ibo-field--label--description--padding-left;
vertical-align: top;
cursor: pointer;
color: $ibo-field--label--description--color;
@extend %ibo-font-ral-bol-50;
cursor: pointer;
color: $ibo-field--label--description--color;
@extend %ibo-font-ral-bol-50;
}
}
}

View File

@@ -479,6 +479,22 @@ $ibo-button-colors: (
&.ibo-action-button {
float: right;
}
.ibo-button--loading-icon {
display: none;
}
&.ibo-is-loading {
.ibo-button--icon{
display: none;
}
.ibo-button--loading-icon {
display: inline-block;
&+ .ibo-button--label{
margin-left: $ibo-button--label--margin-left;
}
}
}
}
.ibo-button--label {

View File

@@ -15,6 +15,9 @@
*
* You should have received a copy of the GNU Affero General Public License
*/
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
$version: "v2.7.7";
$approot-relative: "../../../../" !default; // relative to env-***/branding/themes/***/main.css
// Base colors

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

26
js/components/button.js Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2013-2022 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
*/
;
// Apply a listener to <body> element so we don't havec to create one for every button on the page
$('body').on('enter_loading_state.button.itop', '[data-role="ibo-button"]', function(){
$(this).addClass('ibo-is-loading').prop('disabled', true);
})
.on('leave_loading_state.button.itop', '[data-role="ibo-button"]', function(){
$(this).removeClass('ibo-is-loading').prop('disabled', false);
});

View File

@@ -63,7 +63,7 @@ $(function()
});
if (this.options.post_upload_to != null)
{
this.oUploadBtn = $('<button class="icon-select icon-select-upload" type="button" title="'+this.options.labels['upload']+'"><div style="display: inline-block;position: relative;vertical-align:middle;height:48px; line-height:48px; width:16px"><span style="height:16px;display:block;position:absolute;top:50%;margin-top:-8px" class="ui-icon ui-icon-circle-plus"/></div></button>');
this.oUploadBtn = $('<button class="icon-select icon-select-upload" type="button" title="'+this.options.labels['upload']+'"><div style="display: inline-block; position: relative; height:48px; line-height:48px; width:16px"><span style="height:16px; display:block; position:absolute; top:50%; margin-top:-8px" class="ui-icon ui-icon-circle-plus"/></div></button>');
this.oUploadBtn.on('click', function() { me._upload_dlg(); } );
this.oButton.after(this.oUploadBtn);
}

View File

@@ -35,7 +35,7 @@ $(function()
{
// In case there is an hidden input having the same id (somewhere else in the page), the change event does not occur unless the input loses the focus
// To reduce the impact, let's handle keyup as well
$('#'+this.options.field_id, this.element).on('change.itop-property-field keyup.itop-property-field', function() { me._on_change(); });
$('#'+this.options.field_id, this.element).on('change.itop-property-field keyup.itop-property-field input.itop-property-field', function() { me._on_change(); });
this.value = this._get_field_value();
}
this.element.find(".prop_apply").on('click.itop-property-field', function() { me._do_apply(); });

View File

@@ -388,8 +388,8 @@ $(function()
{
oInputElem[oInputParam.x_picker]('setDate', sDate);
}
$('#ui-datepicker-div').hide();
}
$('#ui-datepicker-div').hide();
}
},

3
lib/.gitignore vendored
View File

@@ -32,4 +32,5 @@
# TWIG
/twig/twig/doc
/twig/twig/test
/twig/twig/drupal_test.sh
/twig/twig/drupal_test.sh
/symfony/twig-bundle/Tests

View File

@@ -2367,17 +2367,17 @@
},
{
"name": "symfony/twig-bundle",
"version": "v3.4.36",
"version_normalized": "3.4.36.0",
"version": "v3.4.47",
"version_normalized": "3.4.47.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bundle.git",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9"
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"reference": "d39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9",
"url": "https://api.github.com/repos/symfony/twig-bundle/zipball/977b3096e2df96bc8a8d2329e83466cfc30c373d",
"reference": "977b3096e2df96bc8a8d2329e83466cfc30c373d",
"shasum": ""
},
"require": {
@@ -2409,13 +2409,8 @@
"symfony/web-link": "~3.3|~4.0",
"symfony/yaml": "~2.8|~3.0|~4.0"
},
"time": "2019-10-01T15:13:36+00:00",
"time": "2020-10-24T10:57:07+00:00",
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
@@ -2441,6 +2436,23 @@
],
"description": "Symfony TwigBundle",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/twig-bundle/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/twig-bundle"
},
{

View File

@@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '1d28bbe3f4e8467dc8f5459f638bed79526022bc',
'reference' => '47feb7f4259aebc4e9b27cfc8a6eafbbbf0b3686',
'name' => '__root__',
'dev' => true,
),
@@ -16,7 +16,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '1d28bbe3f4e8467dc8f5459f638bed79526022bc',
'reference' => '47feb7f4259aebc4e9b27cfc8a6eafbbbf0b3686',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(
@@ -383,12 +383,12 @@
'dev_requirement' => false,
),
'symfony/twig-bundle' => array(
'pretty_version' => 'v3.4.36',
'version' => '3.4.36.0',
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/twig-bundle',
'aliases' => array(),
'reference' => 'd39ed8f5df62aeeeb27a6f3bf7f58a6c02a58ea9',
'reference' => '977b3096e2df96bc8a8d2329e83466cfc30c373d',
'dev_requirement' => false,
),
'symfony/var-dumper' => array(

View File

@@ -40,9 +40,9 @@ class TemplateCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInte
$this->container = $container;
} elseif ($container instanceof Environment) {
$this->twig = $container;
@trigger_error(sprintf('Using a "%s" as first argument of %s is deprecated since Symfony 3.4 and will be unsupported in version 4.0. Use a %s instead.', Environment::class, __CLASS__, ContainerInterface::class), E_USER_DEPRECATED);
@trigger_error(sprintf('Using a "%s" as first argument of %s is deprecated since Symfony 3.4 and will be unsupported in version 4.0. Use a %s instead.', Environment::class, __CLASS__, ContainerInterface::class), \E_USER_DEPRECATED);
} else {
throw new \InvalidArgumentException(sprintf('%s only accepts instance of Psr\Container\ContainerInterface as first argument.', __CLASS__));
throw new \InvalidArgumentException(sprintf('"%s" only accepts instance of Psr\Container\ContainerInterface as first argument.', __CLASS__));
}
$this->iterator = $iterator;

View File

@@ -11,7 +11,7 @@
namespace Symfony\Bundle\TwigBundle\Command;
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Bridge\Twig\Command\DebugCommand instead.', DebugCommand::class), E_USER_DEPRECATED);
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Bridge\Twig\Command\DebugCommand instead.', DebugCommand::class), \E_USER_DEPRECATED);
use Symfony\Bridge\Twig\Command\DebugCommand as BaseDebugCommand;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;

View File

@@ -11,7 +11,7 @@
namespace Symfony\Bundle\TwigBundle;
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Twig\RuntimeLoader\ContainerRuntimeLoader class instead.', ContainerAwareRuntimeLoader::class), E_USER_DEPRECATED);
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Twig\RuntimeLoader\ContainerRuntimeLoader class instead.', ContainerAwareRuntimeLoader::class), \E_USER_DEPRECATED);
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

View File

@@ -39,7 +39,7 @@ class TwigLoaderPass implements CompilerPassInterface
}
if (!$found) {
throw new LogicException('No twig loaders found. You need to tag at least one loader with "twig.loader"');
throw new LogicException('No twig loaders found. You need to tag at least one loader with "twig.loader".');
}
if (1 === $found) {

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2019 Fabien Potencier
Copyright (c) 2004-2020 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -32,7 +32,8 @@ class TwigBundle extends Bundle
{
parent::build($container);
$container->addCompilerPass(new ExtensionPass());
// ExtensionPass must be run before the FragmentRendererPass as it adds tags that are processed later
$container->addCompilerPass(new ExtensionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
$container->addCompilerPass(new TwigEnvironmentPass());
$container->addCompilerPass(new TwigLoaderPass());
$container->addCompilerPass(new ExceptionListenerPass());

View File

@@ -50,10 +50,5 @@
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
}
"minimum-stability": "dev"
}

View File

@@ -1338,7 +1338,7 @@ EOF
{
return null;
}
$oClassNode = self::$aLoadedClasses[$sClassName];
$oClassNode = $this->GetClass($sClassName);
/** @var \MFElement|null $oFieldNode */
$oFieldNode = $this->GetNodes("fields/field[@id='$sAttCode']", $oClassNode)->item(0);
if (($oFieldNode == null) && ($sParentClass = $oClassNode->GetChildText('parent')))
@@ -2311,6 +2311,9 @@ EOF;
* Replaces a node by another one, making sure that recursive nodes are preserved
*
* @param MFElement $oNewNode The replacement
*
* @since 2.7.7 3.0.1 3.1.0 N°3129 rename method (from `ReplaceWith` to `MFReplaceWith`) to avoid collision with parent `\DOMElement::replaceWith` method (different method modifier and parameters :
* throws fatal error in PHP 8.0)
*/
protected function ReplaceWithSingleNode($oNewNode)
{

View File

@@ -1012,7 +1012,7 @@ class SetupUtils
$oPage, $bIsItopInstall, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $bTlsEnabled, $sTlsCA,
$sNewDBName = ''
) {
$sWikiVersion = utils::GetItopVersionWikiSyntax(); //eg : '2_7_0';
$sWikiVersion = utils::GetCoreVersionWikiSyntax(); //eg : '2_7_0';
$sMysqlTlsWikiPageUrl = 'https://www.itophub.io/wiki/page?id='.$sWikiVersion.':install:php_and_mysql_tls';
$oPage->add('<fieldset><legend>Database Server Connection</legend>');
@@ -1268,7 +1268,7 @@ EOF
{
$aResult['checks'][] = new CheckResult(CheckResult::INFO, "MySQL server's max_allowed_packet ($sMaxAllowedPacketFriendly) is big enough compared to upload_max_filesize ($sMaxUploadSizeFriendly).");
} else if ($iMaxAllowedPacket < $iMaxUploadSize) {
$sWikiVersion = utils::GetItopVersionWikiSyntax(); //eg : '2_7_0';
$sWikiVersion = utils::GetCoreVersionWikiSyntax(); //eg : '2_7_0';
$sAttachmentsVarsWikiPageUrl = 'https://www.itophub.io/wiki/page?id='.$sWikiVersion
.':install:php_and_mysql_configuration#attachments_upload';

View File

@@ -448,20 +448,21 @@ abstract class Controller
/**
* Generate a page, zip it and propose the zipped file for download
*
* @param array $aParams Params used by the twig template
* @param null $sTemplateName Name of the twig template, ie MyTemplate for MyTemplate.html.twig
*
* @throws \Exception
* @api
*
* @param array $aParams Params used by the twig template
* @param string|null $sTemplateName Name of the twig template, ie MyTemplate for MyTemplate.html.twig
* @param string $sReportFileName Root name of the report file
*
* @throws \Exception
*/
public function DownloadZippedPage($aParams = array(), $sTemplateName = null)
public function DownloadZippedPage($aParams = array(), $sTemplateName = null, $sReportFileName = 'itop-system-information-report')
{
if (empty($sTemplateName)) {
$sTemplateName = $this->m_sOperation;
}
$sReportFolder = str_replace("\\", '/', APPROOT.'log/');
$sReportFile = 'itop-system-information-report-'.date('Y-m-d-H-i-s');
$sReportFile = $sReportFileName.'-'.date('Y-m-d-H-i-s');
$sHTMLReport = $sReportFolder.$sReportFile.'.html';
$sZIPReportFile = $sReportFile;

View File

@@ -35,7 +35,11 @@ class Button extends UIBlock
public const BLOCK_CODE = 'ibo-button';
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/button/layout';
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'base/components/button/layout';
public const DEFAULT_JS_FILES_REL_PATH = [
'js/components/button.js',
];
public const REQUIRES_ANCESTORS_DEFAULT_JS_FILES = true;
// Specific constants
/** @var string ENUM_ACTION_TYPE_REGULAR */
public const ENUM_ACTION_TYPE_REGULAR = 'regular';

View File

@@ -31,6 +31,7 @@ class ButtonJS extends Button
{
// Overloaded constants
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/button/buttonjs';
public const REQUIRES_ANCESTORS_DEFAULT_JS_FILES = true;
// Specific constants
/** @var string ENUM_TYPE_BUTTON */

View File

@@ -31,6 +31,7 @@ class ButtonURL extends Button
{
// Overloaded constants
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/button/buttonurl';
public const REQUIRES_ANCESTORS_DEFAULT_JS_FILES = true;
// Specific constants
/** @var string ENUM_TARGET_BLANK */

View File

@@ -26,7 +26,7 @@ class InputWithLabel extends UIBlock
/** @var bool Label before input ? */
protected $bBeforeInput;
/**
* @var string $sDescription for tooltip
* @var string|null $sDescription for tooltip
* @since 3.0.1
*/
protected $sDescription;
@@ -109,26 +109,28 @@ class InputWithLabel extends UIBlock
}
/**
* @return string|null
* @since 3.0.1
* @return mixed
*/
public function GetDescription()
public function GetDescription(): ?string
{
return $this->sDescription;
}
/**
* @param string|null $sDescription
* @return $this
* @since 3.0.1
* @param mixed $sDescription
*/
public function SetDescription($sDescription)
public function SetDescription(?string $sDescription)
{
$this->sDescription = $sDescription;
return $this;
}
/**
* @since 3.0.1
* @return bool
* @since 3.0.1
*/
public function HasDescription(): bool
{

View File

@@ -19,10 +19,10 @@ trait tInputLabel
/** @var string|null Label to display with the input (null for no label) */
protected $sLabel = null;
/**
* @var string $sDescription for tooltip
* @var string|null $sDescription for tooltip
* @since 3.0.1
*/
protected $sDescription;
protected $sDescription = null;
/**
* @return bool
@@ -88,29 +88,35 @@ trait tInputLabel
*/
public function HasLabel(): bool
{
return $this->sLabel != null;
return strlen($this->sLabel) > 0;
}
/**
* @return mixed
* @return string|null
* @since 3.0.1
*/
public function GetDescription()
public function GetDescription(): ?string
{
return $this->sDescription;
}
/**
* @param mixed $sDescription
* @param string|null $sDescription
* @return $this
* @since 3.0.1
*/
public function SetDescription($sDescription)
public function SetDescription(?string $sDescription)
{
$this->sDescription = $sDescription;
return $this;
}
/**
* @return bool
* @since 3.0.1
*/
public function HasDescription(): bool
{
return $this->sDescription != null;
return strlen($this->sDescription) > 0;
}
}

View File

@@ -253,7 +253,15 @@ class NavigationMenu extends UIBlock implements iKeyboardShortcut
*/
public function GetSubBlocks(): array
{
return [$this->oUserMenu->GetId() => $this->oUserMenu, $this->GetNewsroomMenu()->GetId() => $this->GetNewsroomMenu()];
$aSubBlocks = [
$this->oUserMenu->GetId() => $this->oUserMenu,
];
if ($this->IsNewsroomEnabled()) {
$aSubBlocks[$this->GetNewsroomMenu()->GetId()] = $this->GetNewsroomMenu();
}
return $aSubBlocks;
}
/**

View File

@@ -22,6 +22,7 @@
aria-label="{{ sAriaLabel }}"
{% endif %}
>
<span class="ibo-button--loading-icon fas fa-spinner fa-pulse"></span>
{% if oUIBlock.GetIconClass() is not empty %}
<span class="ibo-button--icon {{ oUIBlock.GetIconClass() }}"></span>
{% endif %}

View File

@@ -20,6 +20,7 @@
aria-label="{{ sAriaLabel }}"
{% endif %}
>
<span class="ibo-button--loading-icon fas fa-spinner fa-pulse"></span>
{% if oUIBlock.GetIconClass() is not empty %}
<span class="ibo-button--icon {{ oUIBlock.GetIconClass() }}"></span>
{% endif %}

View File

@@ -20,6 +20,7 @@
{% endif %}
>
<span class="ibo-button--loading-icon fas fa-spinner fa-pulse"></span>
{% if oUIBlock.GetIconClass() is not empty %}
<span class="ibo-button--icon {{ oUIBlock.GetIconClass() }}"></span>
{% endif %}

View File

@@ -1,10 +1,10 @@
{% block iboInputLabel %}
{% if oUIBlock.IsLabelBefore() %}
<label for="{{ oUIBlock.GetId() }}" {% if oUIBlock.HasDescription() %} class="ibo-has-description" data-tooltip-content="{{ oUIBlock.GetDescription() |raw }}" data-tooltip-max-width="600px" data-tooltip-html-enabled="true"{% endif %}>{{ oUIBlock.GetLabel() |raw }}</label>
<label for="{{ oUIBlock.GetId() }}" {% if oUIBlock.HasDescription() %} class="ibo-input-with-label--label ibo-has-description" data-tooltip-content="{{ oUIBlock.GetDescription() |raw }}" data-tooltip-max-width="600px" data-tooltip-html-enabled="true"{% endif %}>{{ oUIBlock.GetLabel() |raw }}</label>
{{ render_block(oUIBlock.GetInput()) }}
{% else %}
{{ render_block(oUIBlock.GetInput()) }}
<label for="{{ oUIBlock.GetId() }}" {% if oUIBlock.HasDescription() %} class="ibo-has-description" data-tooltip-content="{{ oUIBlock.GetDescription() |raw }}" data-tooltip-max-width="600px" data-tooltip-html-enabled="true"{% endif %}>{{ oUIBlock.GetLabel() |raw }}</label>
<label for="{{ oUIBlock.GetId() }}" {% if oUIBlock.HasDescription() %} class="ibo-input-with-label--label ibo-has-description" data-tooltip-content="{{ oUIBlock.GetDescription() |raw }}" data-tooltip-max-width="600px" data-tooltip-html-enabled="true"{% endif %}>{{ oUIBlock.GetLabel() |raw }}</label>
{% endif %}
{% endblock %}

View File

@@ -15,7 +15,9 @@
namespace Combodo\iTop\Test\UnitTest\Integration;
use ApplicationException;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
use utils;
/**
@@ -24,30 +26,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase;
* @package Combodo\iTop\Test\UnitTest\Setup
*/
class iTopModulesPhpVersionIntegrationTest extends ItopTestCase {
/**
* We had a problem when version was switched from 2.8.0 to 3.0.0, so this test aims to detect such problems
*
* @param string $sVersion
* @param string $sExpectedMinVersion if null the test will expects an exception to occur
*
* @throws \Exception
* @since 3.0.0
* @dataProvider GetItopMinorVersionProvider
*/
public function testGetItopMinorVersion($sVersion, $sExpectedMinVersion) {
if (is_null($sExpectedMinVersion)) {
$this->expectException(\Exception::class);
}
$sActualMinVersion = \utils::GetItopMinorVersion($sVersion);
if (!is_null($sExpectedMinVersion)) {
$this->assertEquals($sExpectedMinVersion, $sActualMinVersion);
}
}
public function GetItopMinorVersionProvider() {
return [['2.8.0', '2.8'], ['3.0.0', '3.0'], ['3.', null], ['3', null]];
}
/**
* @param string $sPhpFile iTop module file
*
@@ -75,6 +53,8 @@ class iTopModulesPhpVersionIntegrationTest extends ItopTestCase {
*
* @group skipPostBuild
* @uses utils::GetItopMinorVersion()
*
* @since 2.7.7 3.0.1 3.1.0 N°4714 uses new {@link ITOP_CORE_VERSION} constant
*/
public function testITopModulesPhpVersion(): void {
if (is_dir(APPROOT.'datamodels/2.x')) {
@@ -89,18 +69,42 @@ class iTopModulesPhpVersionIntegrationTest extends ItopTestCase {
$sPath = $DatamodelsPath.'/*/module.*.php';
$aPhpFiles = glob($sPath);
$sMinorVersion = \utils::GetItopMinorVersion();
$sExpectedVersion = '/^'.str_replace('.', '\.', $sMinorVersion).'\.\d+$/';
$sExpectedVersion = ITOP_CORE_VERSION;
$aModuleWithError = [];
foreach ($aPhpFiles as $sPhpFile) {
$sActualVersion = $this->GetItopModuleVersion($sPhpFile);
if (!preg_match($sExpectedVersion, $sActualVersion)) {
$aModuleWithError[$sPhpFile] = $sActualVersion;
}
$this->assertSame($sExpectedVersion, $sActualVersion,
'Module desc file does not contain the same version as the core: '.$sPhpFile);
}
self::assertEquals([], $aModuleWithError, 'Some modules have wrong versions ! They should match '.$sExpectedVersion);
}
/**
* @dataProvider ItopWikiVersionProvider
* @since 2.7.7 3.0.1 3.1.1 N°4714 new ITOP_CORE_VERSION constant
*/
public function testItopWikiVersion($sItopVersion, $sExpectedWikiVersion) {
try {
$sActualWikiVersion = utils::GetCoreVersionWikiSyntax($sItopVersion);
}
catch (ApplicationException $e) {
self::fail('Cannot get wiki version : '.$e->getMessage());
}
self::assertSame($sExpectedWikiVersion, $sActualWikiVersion, 'Computed wiki version is wrong !');
}
public function ItopWikiVersionProvider()
{
return [
['2.7.0', '2_7_0'],
['2.7.7', '2_7_0'],
['3.0.0', '3_0_0'],
['3.0.1', '3_0_0'],
['3.1.0', '3_1_0'],
['3.1.1', '3_1_0'],
];
}
}

View File

@@ -19,7 +19,7 @@
<phpunit bootstrap="unittestautoload.php"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd"
backupGlobals="false"
backupGlobals="true"
backupStaticAttributes="false"
cacheTokens="false"
colors="true"
@@ -29,7 +29,7 @@
forceCoversAnnotation="false"
mapTestClassNameToCoveredClassName="false"
printerClass="\PHPUnit\TextUI\ResultPrinter"
processIsolation="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"

View File

@@ -121,26 +121,28 @@ function Usage(Page $oP)
//}
}
function DisplayExpressionForm(WebPage $oP, $sAction, $sExpression = '', $sExceptionMessage = '')
function DisplayExpressionForm(WebPage $oP, $sAction, $sExpression = '', $sExceptionMessage = '', $oForm = null)
{
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:ScopeDefinition'));
$oP->AddSubBlock($oPanel);
$oForm = FormUIBlockFactory::MakeStandard('form');
$oForm->SetAction($sAction);
$oPanel->AddSubBlock($oForm);
if ($oForm == null) {
$oForm = FormUIBlockFactory::MakeStandard('export-form');
$oForm->SetAction($sAction);
$oP->AddSubBlock($oForm);
}
$oForm->AddSubBlock($oPanel);
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('interactive', '1'));
$oPanel->AddSubBlock(InputUIBlockFactory::MakeForHidden('interactive', '1'));
$oFieldQuery = FieldUIBlockFactory::MakeStandard('<input type="radio" name="query_mode" value="oql" id="radio_oql" checked><label for="radio_oql">'.Dict::S('Core:BulkExportLabelOQLExpression').'</label>');
$oTextArea = new TextArea('expression', htmlentities($sExpression, ENT_QUOTES, 'UTF-8'), "textarea_oql", 70, 8);
$oTextArea->SetPlaceholder(Dict::S('Core:BulkExportQueryPlaceholder'));
$oTextArea->AddCSSClasses(["ibo-input-text", "ibo-query-oql", "ibo-is-code"]);
$oFieldQuery->AddSubBlock($oTextArea);
$oForm->AddSubBlock($oFieldQuery);
$oPanel->AddSubBlock($oFieldQuery);
if (!empty($sExceptionMessage)) {
$oAlert = AlertUIBlockFactory::MakeForFailure($sExceptionMessage);
$oAlert->SetIsCollapsible(false);
$oForm->AddSubBlock($oAlert);
$oPanel->AddSubBlock($oAlert);
}
$oFieldPhraseBook = FieldUIBlockFactory::MakeStandard('<input type="radio" name="query_mode" value="phrasebook" id="radio_phrasebook"><label for="radio_phrasebook">'.Dict::S('Core:BulkExportLabelPhrasebookEntry').'</label>');
@@ -154,9 +156,9 @@ function DisplayExpressionForm(WebPage $oP, $sAction, $sExpression = '', $sExcep
$oSelect->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($oQuery->GetKey(), $oQuery->Get('name'), false));
}
$oFieldPhraseBook->AddSubBlock($oSelect);
$oForm->AddSubBlock($oFieldPhraseBook);
$oPanel->AddSubBlock($oFieldPhraseBook);
$oForm->AddSubBlock(ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('UI:Button:Next'), "", "", true, "next-btn"));
$oPanel->AddSubBlock(ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('UI:Button:Next'), "", "", true, "next-btn"));
$oP->p('<a target="_blank" href="'.utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php">'.Dict::S('Core:BulkExportCanRunNonInteractive').'</a>');
$oP->p('<a target="_blank" href="'.utils::GetAbsoluteUrlAppRoot().'webservices/export.php">'.Dict::S('Core:BulkExportLegacyExport').'</a>');
$sJSEmptyOQL = json_encode(Dict::S('Core:BulkExportMessageEmptyOQL'));
@@ -259,7 +261,7 @@ EOF
}
if (!$bExpressionIsValid) {
DisplayExpressionForm($oP, $sAction, $sExpression, $sExpressionError);
DisplayExpressionForm($oP, $sAction, $sExpression, $sExpressionError,$oForm);
return;
}