diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index 1877490b4..31cfe1fe4 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -17,6 +17,11 @@
* You should have received a copy of the GNU Affero General Public License
*/
+use Combodo\iTop\Application\UI\Component\Field\Field;
+use Combodo\iTop\Application\UI\Component\FieldSet\FieldSet;
+use Combodo\iTop\Application\UI\Layout\Column\Column;
+use Combodo\iTop\Application\UI\Layout\MultiColumn\MultiColumn;
+
define('OBJECT_PROPERTIES_TAB', 'ObjectProperties');
define('HILIGHT_CLASS_CRITICAL', 'red');
@@ -806,93 +811,43 @@ EOF
$sClass = get_class($this);
$aDetailsList = MetaModel::GetZListItems($sClass, 'details');
$aDetailsStruct = self::ProcessZlist($aDetailsList, array('UI:PropertiesTab' => array()), 'UI:PropertiesTab', 'col1', '');
- // Compute the list of properties to display, first the attributes in the 'details' list, then
- // all the remaining attributes that are not external fields
- $sEditMode = ($bEditMode) ? 'edit' : 'view';
- $aDetails = array();
- $iInputId = 0;
$aFieldsMap = array();
$aFieldsComments = (isset($aExtraParams['fieldsComments'])) ? $aExtraParams['fieldsComments'] : array();
$aExtraFlags = (isset($aExtraParams['fieldsFlags'])) ? $aExtraParams['fieldsFlags'] : array();
- foreach($aDetailsStruct as $sTab => $aCols)
- {
- $aDetails[$sTab] = array();
- $aTableStyles[] = 'vertical-align:top';
- $aTableClasses = array();
- $aColStyles[] = 'vertical-align:top';
- $aColClasses = array();
-
+ foreach ($aDetailsStruct as $sTab => $aCols) {
ksort($aCols);
- $iColCount = count($aCols);
- if ($iColCount > 1)
- {
- $aTableClasses[] = 'n-cols-details';
- $aTableClasses[] = $iColCount.'-cols-details';
-
- $aColStyles[] = 'width:'.floor(100 / $iColCount).'%';
- }
- else
- {
- $aTableClasses[] = 'one-col-details';
- }
-
$oPage->SetCurrentTab($sTab);
- $oPage->add('
');
- foreach($aCols as $sColIndex => $aFieldsets)
- {
- $oPage->add('');
- $sPreviousLabel = '';
- $aDetails[$sTab][$sColIndex] = array();
- foreach($aFieldsets as $sFieldsetName => $aFields)
- {
- if (!empty($sFieldsetName) && ($sFieldsetName[0] != '_'))
- {
- $sLabel = $sFieldsetName;
+ $oMultiColumn = new MultiColumn();
+ $oPage->AddUiBlock($oMultiColumn);
+
+ foreach ($aCols as $sColIndex => $aFieldsets) {
+ $oColumn = new Column();
+ $oMultiColumn->AddColumn($oColumn);
+
+ foreach ($aFieldsets as $sFieldsetName => $aFields) {
+ if ($sFieldsetName[0] != '_') {
+ $oFieldSet = new FieldSet(Dict::S($sFieldsetName));
+ $oColumn->AddSubBlock($oFieldSet);
}
- else
- {
- $sLabel = '';
- }
- if ($sLabel != $sPreviousLabel)
- {
- if (!empty($sPreviousLabel))
- {
- $oPage->add('');
- }
- $aDetails[$sTab][$sColIndex] = array();
- $sPreviousLabel = $sLabel;
- }
- foreach($aFields as $sAttCode)
- {
+ $aDetails = [];
+ foreach ($aFields as $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClass, $sAttCode);
- if ($bEditMode)
- {
+ if ($bEditMode) {
$sComments = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$sInfos = '';
$iFlags = $this->GetFormAttributeFlags($sAttCode);
- if (array_key_exists($sAttCode, $aExtraFlags))
- {
+ if (array_key_exists($sAttCode, $aExtraFlags)) {
// the caller may override some flags if needed
$iFlags = $iFlags | $aExtraFlags[$sAttCode];
}
- if ((!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) && !($oAttDef instanceof AttributeDashboard))
- {
+ if ((!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) && !($oAttDef instanceof AttributeDashboard)) {
$sInputId = $this->m_iFormId.'_'.$sAttCode;
- if ($oAttDef->IsWritable())
- {
- if ($sStateAttCode == $sAttCode)
- {
+ if ($oAttDef->IsWritable()) {
+ if ($sStateAttCode == $sAttCode) {
// State attribute is always read-only from the UI
$sHTMLValue = $this->GetStateLabel();
$val = array(
@@ -901,20 +856,15 @@ EOF
'comments' => $sComments,
'infos' => $sInfos,
);
- }
- else
- {
- if ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE))
- {
+ } else {
+ if ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) {
// Check if the attribute is not read-only because of a synchro...
- if ($iFlags & OPT_ATT_SLAVE)
- {
+ if ($iFlags & OPT_ATT_SLAVE) {
$aReasons = array();
$this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = " ";
$sTip = '';
- foreach($aReasons as $aRow)
- {
+ foreach ($aReasons as $aRow) {
$sDescription = htmlentities($aRow['description'], ENT_QUOTES,
'UTF-8');
$sDescription = str_replace(array("\r\n", "\n"), " ",
@@ -985,10 +935,8 @@ EOF
// - For simple fields, we get the raw (stored) value as well
$bExcludeRawValue = false;
- foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
- {
- if (is_a($sAttDefClass, $sAttDefClassToExclude, true))
- {
+ foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
+ if (is_a($sAttDefClass, $sAttDefClassToExclude, true)) {
$bExcludeRawValue = true;
break;
}
@@ -996,24 +944,22 @@ EOF
$val['value_raw'] = ($bExcludeRawValue === false) ? $this->Get($sAttCode) : '';
// The field is visible, add it to the current column
- $aDetails[$sTab][$sColIndex][] = $val;
- $iInputId++;
+ $aDetails[] = $val;
+ $oField = new Field($val);
+ if ($sFieldsetName[0] != '_') {
+ $oFieldSet->AddSubBlock($oField);
+ } else {
+ $oColumn->AddSubBlock($oField);
+ }
}
}
+// if ($sFieldsetName[0] != '_') {
+// $oFieldSet->AddSubBlock(new Html($oPage->GetDetails($aDetails)));
+// } else {
+// $oColumn->AddSubBlock(new Html($oPage->GetDetails($aDetails)));
+// }
}
- if (!empty($sPreviousLabel))
- {
- $oPage->add('');
- }
- $oPage->add(' | ');
}
- $oPage->add('
');
}
return $aFieldsMap;
diff --git a/css/backoffice/components/_all.scss b/css/backoffice/components/_all.scss
index 0539711ae..ecaaa2edf 100644
--- a/css/backoffice/components/_all.scss
+++ b/css/backoffice/components/_all.scss
@@ -18,4 +18,6 @@
@import "ajaxtab";
@import "title";
@import "form";
-@import "input";
\ No newline at end of file
+@import "input";
+@import "fieldset";
+@import "field";
\ No newline at end of file
diff --git a/css/backoffice/components/_field.scss b/css/backoffice/components/_field.scss
new file mode 100644
index 000000000..ee36d1a89
--- /dev/null
+++ b/css/backoffice/components/_field.scss
@@ -0,0 +1,34 @@
+/*!
+ * copyright Copyright (C) 2010-2020 Combodo SARL
+ * license http://opensource.org/licenses/AGPL-3.0
+ */
+
+.ibo-field-large {
+ display: inherit;
+
+ .ibo-field-label {
+ display: inherit;
+ }
+}
+
+.ibo-field-small {
+ display: table;
+ width: 100%;
+
+ .ibo-field-label {
+ display: table-cell;
+ vertical-align: top;
+ }
+}
+
+.ibo-field-label {
+ min-width: 100px;
+ max-width: 145px;
+ width: 30%;
+ padding-right: 10px;
+}
+
+.ibo-field-value {
+ display: table;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/css/backoffice/components/_fieldset.scss b/css/backoffice/components/_fieldset.scss
new file mode 100644
index 000000000..2b1c120e8
--- /dev/null
+++ b/css/backoffice/components/_fieldset.scss
@@ -0,0 +1,4 @@
+/*!
+ * copyright Copyright (C) 2010-2020 Combodo SARL
+ * license http://opensource.org/licenses/AGPL-3.0
+ */
diff --git a/css/backoffice/layout/_all.scss b/css/backoffice/layout/_all.scss
index 20ae44aaa..c866387f8 100644
--- a/css/backoffice/layout/_all.scss
+++ b/css/backoffice/layout/_all.scss
@@ -23,4 +23,6 @@
@import "activity-panel/activity-entry";
@import "activity-panel/caselog-entry";
@import "activity-panel/edits-entry";
-@import "activity-panel/transition-entry";
\ No newline at end of file
+@import "activity-panel/transition-entry";
+@import "multicolumn";
+@import "column";
\ No newline at end of file
diff --git a/css/backoffice/layout/_column.scss b/css/backoffice/layout/_column.scss
new file mode 100644
index 000000000..e0ae24b08
--- /dev/null
+++ b/css/backoffice/layout/_column.scss
@@ -0,0 +1,7 @@
+/*!
+ * copyright Copyright (C) 2010-2020 Combodo SARL
+ * license http://opensource.org/licenses/AGPL-3.0
+ */
+
+.ibo-column {
+}
\ No newline at end of file
diff --git a/css/backoffice/layout/_multicolumn.scss b/css/backoffice/layout/_multicolumn.scss
new file mode 100644
index 000000000..1284ddec5
--- /dev/null
+++ b/css/backoffice/layout/_multicolumn.scss
@@ -0,0 +1,10 @@
+/*!
+ * copyright Copyright (C) 2010-2020 Combodo SARL
+ * license http://opensource.org/licenses/AGPL-3.0
+ */
+
+.ibo-multi-column {
+ width: 100%;
+ display: flex;
+ flex-wrap: nowrap;
+}
\ No newline at end of file
diff --git a/js/layouts/tab-container.js b/js/layouts/tab-container.js
index a0527a4fc..2f62d07e5 100644
--- a/js/layouts/tab-container.js
+++ b/js/layouts/tab-container.js
@@ -40,3 +40,5 @@ if ($.bbq) {
} else {
tabs.tabs();
}
+$('.ibo-tab-container-spinner').hide();
+$('.ibo-tab-container').show();
\ No newline at end of file
diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php
index 66a290779..e45a082d9 100644
--- a/lib/composer/autoload_classmap.php
+++ b/lib/composer/autoload_classmap.php
@@ -155,6 +155,8 @@ return array(
'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => $baseDir . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => $baseDir . '/sources/application/UI/Component/Button/Button.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => $baseDir . '/sources/application/UI/Component/Button/ButtonFactory.php',
+ 'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => $baseDir . '/sources/application/UI/Component/FieldSet/FieldSet.php',
+ 'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => $baseDir . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => $baseDir . '/sources/application/UI/Component/Form/Form.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php',
@@ -195,6 +197,8 @@ return array(
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanel' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityPanel.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanelFactory' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityPanelFactory.php',
+ 'Combodo\\iTop\\Application\\UI\\Layout\\Column\\Column' => $baseDir . '/sources/application/UI/Layout/Column/Column.php',
+ 'Combodo\\iTop\\Application\\UI\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/application/UI/Layout/MultiColumn/MultiColumn.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenu' => $baseDir . '/sources/application/UI/Layout/NavigationMenu/NavigationMenu.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenuFactory' => $baseDir . '/sources/application/UI/Layout/NavigationMenu/NavigationMenuFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => $baseDir . '/sources/application/UI/Layout/PageContent/PageContent.php',
diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php
index eb3cf7b0f..b3aa92969 100644
--- a/lib/composer/autoload_static.php
+++ b/lib/composer/autoload_static.php
@@ -385,6 +385,8 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => __DIR__ . '/../..' . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/Button.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/ButtonFactory.php',
+ 'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => __DIR__ . '/../..' . '/sources/application/UI/Component/FieldSet/FieldSet.php',
+ 'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => __DIR__ . '/../..' . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => __DIR__ . '/../..' . '/sources/application/UI/Component/Form/Form.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php',
@@ -425,6 +427,8 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanel' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityPanel.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanelFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityPanelFactory.php',
+ 'Combodo\\iTop\\Application\\UI\\Layout\\Column\\Column' => __DIR__ . '/../..' . '/sources/application/UI/Layout/Column/Column.php',
+ 'Combodo\\iTop\\Application\\UI\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/application/UI/Layout/MultiColumn/MultiColumn.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenu' => __DIR__ . '/../..' . '/sources/application/UI/Layout/NavigationMenu/NavigationMenu.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenuFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/NavigationMenu/NavigationMenuFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => __DIR__ . '/../..' . '/sources/application/UI/Layout/PageContent/PageContent.php',
diff --git a/sources/application/UI/Component/Field/Field.php b/sources/application/UI/Component/Field/Field.php
new file mode 100644
index 000000000..eb8b596b2
--- /dev/null
+++ b/sources/application/UI/Component/Field/Field.php
@@ -0,0 +1,41 @@
+aParams = $aParams;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetParams(): array
+ {
+ return $this->aParams;
+ }
+
+}
\ No newline at end of file
diff --git a/sources/application/UI/Component/FieldSet/FieldSet.php b/sources/application/UI/Component/FieldSet/FieldSet.php
new file mode 100644
index 000000000..1a50ea9cd
--- /dev/null
+++ b/sources/application/UI/Component/FieldSet/FieldSet.php
@@ -0,0 +1,47 @@
+sLegend = $sLegend;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetLegend(): string
+ {
+ return $this->sLegend;
+ }
+
+}
\ No newline at end of file
diff --git a/sources/application/UI/Layout/Column/Column.php b/sources/application/UI/Layout/Column/Column.php
new file mode 100644
index 000000000..36ac0c648
--- /dev/null
+++ b/sources/application/UI/Layout/Column/Column.php
@@ -0,0 +1,23 @@
+aColumns = [];
+ }
+
+ public function AddColumn(Column $oColumn): self
+ {
+ $this->aColumns[] = $oColumn;
+ return $this;
+ }
+
+ public function GetSubBlocks()
+ {
+ return $this->aColumns;
+ }
+}
\ No newline at end of file
diff --git a/sources/application/WebPage/TabManager.php b/sources/application/WebPage/TabManager.php
index d064e7858..a66cbe3aa 100644
--- a/sources/application/WebPage/TabManager.php
+++ b/sources/application/WebPage/TabManager.php
@@ -4,6 +4,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
+use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab;
use Combodo\iTop\Application\UI\Layout\TabContainer\TabContainer;
@@ -56,6 +57,24 @@ class TabManager
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
}
+ public function AddUIBlockToCurrentTab(iUIBlock $oBlock): iUIBlock
+ {
+ $this->AddUIBlockToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $oBlock);
+ return $oBlock;
+ }
+
+ public function AddUIBlockToTab(string $sTabContainer, string $sTabCode, iUIBlock $oBlock, $sTabTitle = null): void
+ {
+ if (!$this->TabExists($sTabContainer, $sTabCode)) {
+ $this->InitTab($sTabContainer, $sTabCode, static::ENUM_TAB_TYPE_HTML, $sTabTitle);
+ }
+
+ $oTab = $this->GetTab($sTabContainer, $sTabCode);
+
+ // Append to the content of the tab
+ $oTab->AddSubBlock($oBlock);
+ }
+
/**
* @return int
* @deprecated 2.8.0
diff --git a/sources/application/WebPage/iTopWebPage.php b/sources/application/WebPage/iTopWebPage.php
index ef2d13c52..369ee9f09 100644
--- a/sources/application/WebPage/iTopWebPage.php
+++ b/sources/application/WebPage/iTopWebPage.php
@@ -45,6 +45,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
private $m_aMessages;
private $m_aInitScript = array();
+ /** @var \TabManager */
protected $m_oTabs;
protected $bBreadCrumbEnabled;
protected $sBreadCrumbEntryId;
@@ -1320,6 +1321,14 @@ EOF;
return null;
}
+ public function AddUiBlock(iUIBlock $oBlock): iUIBlock
+ {
+ if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) {
+ return $this->m_oTabs->AddUIBlockToCurrentTab($oBlock);
+ }
+ return parent::AddUiBlock($oBlock);
+ }
+
/**
* @inheritDoc
*/
diff --git a/templates/components/field/layout.html.twig b/templates/components/field/layout.html.twig
new file mode 100644
index 000000000..019b27d24
--- /dev/null
+++ b/templates/components/field/layout.html.twig
@@ -0,0 +1,5 @@
+{% set aParams = oUIBlock.GetParams() %}
+
+
{{ aParams.label|raw }}
+
{{ aParams.value|raw }}
+
\ No newline at end of file
diff --git a/templates/components/fieldset/layout.html.twig b/templates/components/fieldset/layout.html.twig
new file mode 100644
index 000000000..8a48346eb
--- /dev/null
+++ b/templates/components/fieldset/layout.html.twig
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/templates/layouts/column/layout.html.twig b/templates/layouts/column/layout.html.twig
new file mode 100644
index 000000000..716e4f3eb
--- /dev/null
+++ b/templates/layouts/column/layout.html.twig
@@ -0,0 +1,7 @@
+{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
+{# @license http://opensource.org/licenses/AGPL-3.0 #}
+
+ {% for oSubBlock in oUIBlock.GetSubBlocks() %}
+ {{ render_block(oSubBlock, {aPage: aPage}) }}
+ {% endfor %}
+
\ No newline at end of file
diff --git a/templates/layouts/multicolumn/layout.html.twig b/templates/layouts/multicolumn/layout.html.twig
new file mode 100644
index 000000000..440076158
--- /dev/null
+++ b/templates/layouts/multicolumn/layout.html.twig
@@ -0,0 +1,7 @@
+{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
+{# @license http://opensource.org/licenses/AGPL-3.0 #}
+
+ {% for oSubBlock in oUIBlock.GetSubBlocks() %}
+ {{ render_block(oSubBlock, {aPage: aPage}) }}
+ {% endfor %}
+
\ No newline at end of file
diff --git a/templates/layouts/tabcontainer/layout.html.twig b/templates/layouts/tabcontainer/layout.html.twig
index b7815fdfe..17949b722 100644
--- a/templates/layouts/tabcontainer/layout.html.twig
+++ b/templates/layouts/tabcontainer/layout.html.twig
@@ -1,27 +1,26 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
-
- {% block iboTabContainer %}
-
-
-
+{% block iboTabContainer %}
+
+
+
+
-
- {% endblock %}
-
+
+ {% for oTab in oUIBlock.GetSubBlocks() %}
+ {% if oTab.GetType() == 'html' %}
+
+ {{ render_block(oTab, {aPage: aPage}) }}
+
+ {% endif %}
+ {% endfor %}
+
+
+{% endblock %}