N°2844 - Refactor Panel to include a configurable header

- TitleForObjectDetails no longer exists, use the ObjectDetails's properties instead
This commit is contained in:
Molkobain
2021-03-04 16:51:45 +01:00
parent 4e22906180
commit 1d7bc7c8f7
21 changed files with 648 additions and 428 deletions

View File

@@ -27,9 +27,9 @@ use Combodo\iTop\Application\UI\Base\Component\Field\Field;
use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSet;
use Combodo\iTop\Application\UI\Base\Component\Form\Form;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
@@ -287,8 +287,12 @@ EOF
*/
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false, $sMode = self::ENUM_OBJECT_MODE_VIEW)
{
$aHeaderBlocks = [
'subtitle' => [],
'toolbar' => [],
];
// Standard Header with name, actions menu and history block
//
if (!$oPage->IsPrintableVersion()) {
// Is there a message for this object ??
@@ -309,28 +313,25 @@ EOF
$oPage->AddSessionMessages($sMessageKey, $aRanks, $aMessages);
}
if (!$oPage->IsPrintableVersion() && ($sMode === static::ENUM_OBJECT_MODE_VIEW))
{
if (!$oPage->IsPrintableVersion() && ($sMode === static::ENUM_OBJECT_MODE_VIEW)) {
// action menu
$oSingletonFilter = new DBObjectSearch(get_class($this));
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
$oBlock = new MenuBlock($oSingletonFilter, 'details', false);
$oBlock->Display($oPage, -1);
$aHeaderBlocks['toolbar'][] = $oBlock->GetRenderContent($oPage);
}
$aTags = array();
// Master data sources
$aIcons = array();
if (!$oPage->IsPrintableVersion())
{
if (!$oPage->IsPrintableVersion()) {
$oCreatorTask = null;
$bCanBeDeletedByTask = false;
$bCanBeDeletedByUser = true;
$aMasterSources = array();
$aSyncData = $this->GetSynchroData();
if (count($aSyncData) > 0)
{
foreach($aSyncData as $iSourceId => $aSourceData)
{
if (count($aSyncData) > 0) {
foreach ($aSyncData as $iSourceId => $aSourceData) {
$oDataSource = $aSourceData['source'];
$oReplica = reset($aSourceData['replica']); // Take the first one!
@@ -408,21 +409,28 @@ EOF
}
$sLabel = Dict::S('Tag:Synchronized');
$sSynchroTagId = 'synchro_icon-'.$this->GetKey();
$aIcons[$sSynchroTagId] = ['title' => $sTip, 'css_classes' => 'ibo-title--object-tags--synchronized', 'decoration_classes' => 'fas fa-lock', 'label' => $sLabel];
$aTags[$sSynchroTagId] = ['title' => $sTip, 'css_classes' => 'ibo-object-details--tag--synchronized', 'decoration_classes' => 'fas fa-lock', 'label' => $sLabel];
}
}
if ($this->IsArchived()) {
$sLabel = Dict::S('Tag:Archived');
$sTitle = Dict::S('Tag:Archived+');
$aIcons['archived'] = ['title' => $sTitle, 'css_classes' => 'ibo-title--object-tags--archived', 'decoration_classes' => 'fas fa-archive', 'label' => $sLabel];
$aTags['archived'] = ['title' => $sTitle, 'css_classes' => 'ibo-object-details--tag--archived', 'decoration_classes' => 'fas fa-archive', 'label' => $sLabel];
} elseif ($this->IsObsolete()) {
$sLabel = Dict::S('Tag:Obsolete');
$sTitle = Dict::S('Tag:Obsolete+');
$aIcons['obsolete'] = ['title' => $sTitle, 'css_classes' => 'ibo-title--object-tags--obsolete', 'decoration_classes' => 'fas fa-eye-slash', 'label' => $sLabel];
$aTags['obsolete'] = ['title' => $sTitle, 'css_classes' => 'ibo-object-details--tag--obsolete', 'decoration_classes' => 'fas fa-eye-slash', 'label' => $sLabel];
}
$oPage->AddUiBlock(TitleUIBlockFactory::MakeForObjectDetails($this, $aIcons));
foreach ($aTags as $sIconId => $aIconData) {
$aHeaderBlocks['subtitle'][] = new Html(<<<HTML
<span id="{$sIconId}" class="ibo-object-details--tag {$aIconData['css_classes']}" data-tooltip-content="{$aIconData['title']}" data-tooltip-html-enabled="true"><span class="ibo-object-details--tag-icon"><span class="{$aIconData['decoration_classes']}"></span></span>{$aIconData['label']}</span>
HTML
);
}
return $aHeaderBlocks;
}
/**
@@ -1010,8 +1018,8 @@ EOF
/**
* @param \WebPage $oPage
* @param bool $bEditMode
* @param string $sMode Mode in which the object will be displayed (see static::ENUM_OBJECT_MODE_XXX)
* @param bool $bEditMode Note that this parameter is no longer used in ths method, $sMode is used instead, but we cannot remove it as it part of the base interface (iDisplay)...
* @param string $sMode Mode in which the object will be displayed (see static::ENUM_OBJECT_MODE_XXX)
*
* @throws \ApplicationException
* @throws \ArchivedObjectException
@@ -1034,11 +1042,19 @@ EOF
HTML
);
/** @var \iTopWebPage $oPage */
$this->DisplayBareHeader($oPage, $bEditMode, $sMode);
// Object's details
// TODO 3.0.0: Complete the factory and use it in the different methods (DisplayModifyForm, DisplayTransitionForm), see N°3518
$oObjectDetails = ObjectFactory::MakeDetails($this);
// Note: DisplayBareHeader is called before adding $oObjectDetails to the page, so it can inject HTML before it through $oPage.
/** @var \iTopWebPage $oPage */
$aHeadersBlocks = $this->DisplayBareHeader($oPage, $bEditMode, $sMode);
if (false === empty($aHeadersBlocks['subtitle'])) {
$oObjectDetails->AddSubTitleBlocks($aHeadersBlocks['subtitle']);
}
if (false === empty($aHeadersBlocks['toolbar'])) {
$oObjectDetails->AddToolbarBlocks($aHeadersBlocks['toolbar']);
}
$oPage->AddUiBlock($oObjectDetails);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, '', $oObjectDetails);
@@ -2557,10 +2573,6 @@ HTML;
}
$oContentBlock = new UIContentBlock();
$oContentBlock->SetCSSClasses(['object-details'])
->AddDataAttribute('object-class', $sClass)
->AddDataAttribute('object-id', $iKey)
->AddDataAttribute('object-mode', $sMode);
$oPage->AddUiBlock($oContentBlock);
$oForm = new Form("form_{$this->m_iFormId}");
@@ -2586,12 +2598,7 @@ HTML;
$sHeaderTitle = Dict::Format('UI:ModificationTitle_Class_Object', $sClassLabel,
$this->GetName());
$oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $this->GetRawName(),
$sClassLabel)); // Set title will take care of the encoding
$oForm->AddSubBlock(TitleUIBlockFactory::MakeForObjectDetails($this));
// TODO 3.0.0: Refactor DisplayBareHeader and call it here
$oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $this->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
}
$oToolbarTop = ToolbarUIBlockFactory::MakeStandard(null, ['ibo-toolbar-top']);
@@ -2678,20 +2685,18 @@ JAVASCRIPT
EOF
);
$oObjectDetails = ObjectFactory::MakeDetails($this, $sMode);
$oForm->AddSubBlock($oObjectDetails);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix, $oObjectDetails);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab('UI:PropertiesTab');
if ($sButtonsPosition != 'bottom') {
// top or both, display the buttons here
$oPage->p($sStatesSelection);
$oForm->AddSubBlock($oToolbarTop);
$oObjectDetails->AddToolbarBlock($oToolbarTop);
}
// TODO 3.0.0: Use ObjectDetails block when ready.
$oPanel = new Panel;
$oForm->AddSubBlock($oPanel);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix, $oPanel);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab('UI:PropertiesTab');
$aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams);
if (!is_array($aFieldsMap)) {
$aFieldsMap = array();

View File

@@ -19,16 +19,29 @@
/* SCSS variables */
$ibo-panel--spacing-top: 24px !default;
$ibo-panel--header--margin-bottom: 4px !default;
$ibo-panel--icon--size: 48px !default;
$ibo-panel--icon--spacing: 16px !default;
$ibo-panel--icon--size-as-medallion: 72px !default;
$ibo-panel--icon--spacing--as-medallion: 16px !default;
$ibo-panel--icon--bottom--as-medallion: -24px !default;
$ibo-panel--icon--background-color--as-medallion: $ibo-color-grey-100 !default;
$ibo-panel--icon--border--as-medallion: 2px solid $ibo-color-blue-grey-300 !default;
$ibo-panel--icon--border-radius--as-medallion: $ibo-border-radius-full !default;
$ibo-panel--icon-background--size--must-contain: contain !default;
$ibo-panel--icon-background--size--must-cover: cover !default;
$ibo-panel--icon-background--size--must-zoomout: 66.67% !default;
$ibo-panel--title--color: $ibo-color-grey-900 !default;
$ibo-panel--subtitle--color: $ibo-color-grey-800 !default;
$ibo-panel--highlight--width: 100% !default;
$ibo-panel--highlight--height: 8px !default;
$ibo-panel--highlight--border-radius: $ibo-border-radius-400 $ibo-border-radius-400 0 0 !default;
$ibo-panel--highlight--padding-bottom: $ibo-panel--highlight--height !default;
$ibo-panel--title-icon--max-height: 48px !default;
$ibo-panel--title-icon--margin-right: 5px !default;
$ibo-panel--title--color: $ibo-color-grey-900 !default;
$ibo-panel--subtitle--color: $ibo-color-grey-800 !default;
$ibo-panel--body--background-color: $ibo-color-white-100 !default;
$ibo-panel--body--padding-bottom: 24px !default;
$ibo-panel--body--padding-top: $ibo-panel--body--padding-bottom + $ibo-panel--highlight--height !default;
@@ -81,47 +94,114 @@ $ibo-panel-colors: (
margin-top: $ibo-panel--spacing-top;
}
.ibo-panel {
&.ibo-has-icon {
.ibo-panel--titles {
padding-left: $ibo-panel--icon--spacing;
}
&.ibo-has-medallion-icon {
.ibo-panel--header-left {
position: relative;
z-index: 1;
margin-left: $ibo-panel--icon--spacing--as-medallion;
}
.ibo-panel--icon {
position: absolute;
bottom: $ibo-panel--icon--bottom--as-medallion;
left: 0;
overflow: hidden;
width: $ibo-panel--icon--size-as-medallion;
height: $ibo-panel--icon--size-as-medallion;
min-width: $ibo-panel--icon--size-as-medallion;
min-height: $ibo-panel--icon--size-as-medallion;
background-color: $ibo-panel--icon--background-color--as-medallion;
border: $ibo-panel--icon--border--as-medallion;
border-radius: $ibo-panel--icon--border-radius--as-medallion;
}
.ibo-panel--titles {
padding-left: calc(#{$ibo-panel--icon--size-as-medallion} + #{$ibo-panel--icon--spacing--as-medallion});
}
}
}
}
.ibo-panel--header {
display: flex;
justify-content: space-between;
align-items: stretch;
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: $ibo-panel--header--margin-bottom;
}
.ibo-panel--header-left {
@extend %ibo-fully-centered-content;
justify-content: left;
}
.ibo-panel--icon {
@extend %ibo-fully-centered-content;
width: $ibo-panel--icon--size;
height: $ibo-panel--icon--size;
min-width: $ibo-panel--icon--size;
min-height: $ibo-panel--icon--size;
}
.ibo-panel--icon-background {
width: 100%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: $ibo-panel--icon-background--size--must-contain;
}
.ibo-panel--icon-background--must-contain {
background-size: $ibo-panel--icon-background--size--must-contain;
}
.ibo-panel--icon-background--must-cover {
background-size: $ibo-panel--icon-background--size--must-cover;
}
.ibo-panel--icon-background--must-zoomout {
background-size: $ibo-panel--icon-background--size--must-zoomout;
}
.ibo-panel--title {
display: inline-block;
color: $ibo-panel--title--color;
@extend %ibo-font-ral-med-250;
flex-grow: 1;
@extend %ibo-font-ral-med-250;
flex-grow: 1;
.ibo-panel--title-icon {
display: inline-block;
> img{
max-height: $ibo-panel--title-icon--max-height;
margin-right: $ibo-panel--title-icon--margin-right;
// TODO 3.0.0: Refactor this as it used by the enhanced panel which should be removed
.ibo-panel--title-icon {
display: inline-block;
}
.ibo-panel--title-title {
display: inline-block;
@extend %ibo-font-ral-med-250;
.ibo-panel--title-title-title {
}
}
.ibo-panel--title-title {
display: inline-block;
@extend %ibo-font-ral-med-250;
.ibo-panel--title-title-subtitle {
@extend .ibo-panel--subtitle;
.ibo-panel--title-title-title {
}
.ibo-panel--title-title-subtitle {
@extend .ibo-panel--subtitle;
a.summary {
@extend %ibo-font-ral-nor-250;
color: $ibo-panel--subtitle--color;
}
}
}
a.summary {
@extend %ibo-font-ral-nor-250;
color: $ibo-panel--subtitle--color;
}
}
}
}
.ibo-panel--subtitle {
@extend %ibo-font-ral-nor-250;
color: $ibo-panel--subtitle--color;
display: flex;
@extend %ibo-font-ral-med-250;
color: $ibo-panel--subtitle--color;
}
.ibo-panel--body {

View File

@@ -7,29 +7,12 @@ $ibo-title--text-color: $ibo-color-grey-900 !default;
$ibo-title--padding-y: 12px !default;
$ibo-title--padding-x: 0 !default;
$ibo-title--medallion--size: 90px !default;
$ibo-title--medallion--background-color: $ibo-color-grey-100 !default;
$ibo-title--medallion--border: 2px solid $ibo-color-blue-grey-300 !default;
$ibo-title--medallion--border-radius: $ibo-border-radius-full !default;
$ibo-title--icon--size: 90px !default;
$ibo-title--icon--size--must-contain: contain !default;
$ibo-title--icon--size--must-cover: cover !default;
$ibo-title--icon--size--must-zoomout: 66.67% !default;
$ibo-title--icon-background--size--must-contain: contain !default;
$ibo-title--icon-background--size--must-cover: cover !default;
$ibo-title--icon-background--size--must-zoomout: 66.67% !default;
$ibo-title--status-dot--size: 10px !default;
$ibo-title--status-dot--spacing: 8px !default;
$ibo-title--status-dot--border-radius: $ibo-border-radius-full !default;
$ibo-title--object-tags--margin-left: 12px !default;
$ibo-title--object-tags--color: $ibo-color-grey-900 !default;
$ibo-title--object-tags--icon--margin-right: 6px !default;
$ibo-title--object-tags--icon--color: $ibo-color-grey-700 !default;
$ibo-title--object-tags--separator-dot--background-color: $ibo-color-grey-800 !default;
$ibo-title--object-tags--separator-dot--diameter: 5px !default;
$ibo-title--object-tags--separator-dot--margin-right: 12px !default;
$ibo-title--object-tags--separator-dot--border-radius: $ibo-border-radius-full !default;
.ibo-title {
@extend %ibo-baseline-centered-content;
@@ -38,37 +21,33 @@ $ibo-title--object-tags--separator-dot--border-radius: $ibo-border-radius-full !
padding: $ibo-title--padding-y $ibo-title--padding-x;
}
.ibo-title--medallion {
.ibo-title--icon {
@extend %ibo-fully-centered-content;
width: $ibo-title--medallion--size;
height: $ibo-title--medallion--size;
min-width: $ibo-title--medallion--size;
min-height: $ibo-title--medallion--size;
width: $ibo-title--icon--size;
height: $ibo-title--icon--size;
min-width: $ibo-title--icon--size;
min-height: $ibo-title--icon--size;
overflow: hidden;
background-color: $ibo-title--medallion--background-color;
border: $ibo-title--medallion--border;
border-radius: $ibo-title--medallion--border-radius;
}
.ibo-title--icon {
.ibo-title--icon-background {
width: 100%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: $ibo-title--icon--size--must-contain;
background-size: $ibo-title--icon-background--size--must-contain;
}
.ibo-title--icon--must-contain {
background-size: $ibo-title--icon--size--must-contain;
.ibo-title--icon-background--must-contain {
background-size: $ibo-title--icon-background--size--must-contain;
}
.ibo-title--icon--must-cover {
background-size: $ibo-title--icon--size--must-cover;
.ibo-title--icon-background--must-cover {
background-size: $ibo-title--icon-background--size--must-cover;
}
.ibo-title--icon--must-zoomout {
background-size: $ibo-title--icon--size--must-zoomout;
.ibo-title--icon-background--must-zoomout {
background-size: $ibo-title--icon-background--size--must-zoomout;
}
.ibo-title--for-object-details {
@@ -83,43 +62,6 @@ $ibo-title--object-tags--separator-dot--border-radius: $ibo-border-radius-full !
flex-wrap: wrap;
}
.ibo-title--status {
@extend %ibo-baseline-centered-content;
}
.ibo-title--status-dot {
@extend %ibo-fully-centered-content;
width: $ibo-title--status-dot--size;
height: $ibo-title--status-dot--size;
min-width: $ibo-title--status-dot--size;
min-height: $ibo-title--status-dot--size;
border-radius: $ibo-title--status-dot--border-radius;
}
.ibo-title--status-dot + .ibo-title--status-label {
margin-left: $ibo-title--status-dot--spacing;
}
.ibo-title--status + .ibo-title--object-class {
margin-left: 0.5rem;
&::before {
content: "(";
}
&::after {
content: ")";
}
}
@each $sType, $aColors in $ibo-lifecycle-states-colors {
.ibo-title--status-dot.ibo-is-state-#{$sType} {
color: map-get($aColors, 'secondary-color');
background-color: map-get($aColors, 'primary-color');
}
}
.ibo-title-for-dashlet {
@@ -145,22 +87,3 @@ $ibo-title--object-tags--separator-dot--border-radius: $ibo-border-radius-full !
margin:0;
padding:0;
}
.ibo-title--object-tags {
margin-left: $ibo-title--object-tags--margin-left;
color: $ibo-title--object-tags--color;
}
.ibo-title--object-tags > i {
margin-right: $ibo-title--object-tags--icon--margin-right;
color: $ibo-title--object-tags--icon--color;
}
.ibo-title--object-tags ~ .ibo-title--object-tags::before, .ibo-title--object-class ~ .ibo-title--object-tags::before{
content: " ";
display: inline-block;
vertical-align: middle;
margin-right: $ibo-title--object-tags--separator-dot--margin-right;
width: $ibo-title--object-tags--separator-dot--diameter;
height: $ibo-title--object-tags--separator-dot--diameter;
border-radius: $ibo-title--object-tags--separator-dot--border-radius;
background-color: $ibo-title--object-tags--separator-dot--background-color;
}

View File

@@ -25,7 +25,7 @@
@import "multi-column/column";
@import "dashboard/all";
@import "wizard-container/wizard-container";
@import "object-details";
@import "object/object-details";
@import "activity-panel/activity-panel";
@import "activity-panel/activity-entry";
@import "activity-panel/caselog-entry";

View File

@@ -1,52 +0,0 @@
/*!
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// TODO 3.0.0: This is temporary to make object forms work while it is being migrated to the blocks syste.
// When there is a real ObjectDetails block, rework this to match the block conventions.
.object-details .ibo-title {
z-index: 1;
align-items: start;
position: relative;
padding-left: 32px;
}
.object-details .ibo-title .ibo-title--medallion {
position: absolute;
margin-top: 16px;
}
.object-details .ibo-title.ibo-has-icon .ibo-title--content {
margin-left: calc(90px + 32px);
}
.object-details .ibo-panel {
z-index: 0;
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container > .ibo-tab-container--tabs-list{
padding-left: calc(32px + 90px + 32px - 24px);
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container.ibo-is-vertical{
display: flex;
flex-direction: row;
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container.ibo-is-vertical > .ibo-tab-container--tabs-list{
padding-top: 50px;
flex-direction: column;
height: auto;
padding-left: unset;
margin-right: unset;
min-width: calc(32px + 90px + 32px);
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container.ibo-is-vertical > .ibo-tab-container--tabs-list > .ibo-tab-container--tab-header{
height: 50px;
width: 100%;
justify-content: left;
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container.ibo-is-vertical > .ibo-tab-container--tabs-list > .ibo-tab-container--tab-header > .ibo-tab-container--tab-toggler{
width: 100%;
justify-content: left;
}
.object-details .ibo-panel > .ibo-panel--body > .ibo-tab-container.ibo-is-vertical > .ibo-tab-container--tab-container {
flex-grow: 1;
margin-left: unset;
}

View File

@@ -6,5 +6,6 @@
@import "caselog-entry-form-within-activity-panel";
@import "panel-with-tab-container";
@import "panel-with-datatable";
@import "object-details-with-tab-container";
@import "medallion-with-blocklist";
@import "add-to-dashboard";

View File

@@ -0,0 +1,16 @@
/*!
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Note: We use the child ">" selector to ensure this applies only the child tab container, not another one that would be nested
.ibo-object-details {
> .ibo-panel--body {
> .ibo-tab-container {
> .ibo-tab-container--tabs-list {
// Align tab toggler's title with the panel's title
padding-left: calc(#{$ibo-object-details--icon--spacing--as-medallion} + #{$ibo-object-details--icon--size} + #{$ibo-object-details--icon--spacing--as-medallion} - #{$ibo-tab-container--tab-toggler--padding-x});
}
}
}
}

View File

@@ -0,0 +1,6 @@
/*!
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@import "object-details";

View File

@@ -0,0 +1,121 @@
/*!
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-object-details--icon--size: 96px !default;
$ibo-object-details--icon--spacing--as-medallion: 32px !default;
$ibo-object-details--icon--bottom--as-medallion: -12px !default;
$ibo-object-details--icon--background-color--as-medallion: $ibo-color-grey-100 !default;
$ibo-object-details--icon--border--as-medallion: 2px solid $ibo-color-blue-grey-300 !default;
$ibo-object-details--icon--border-radius--as-medallion: $ibo-border-radius-full !default;
$ibo-object-details--status-dot--size: 10px !default;
$ibo-object-details--status-dot--spacing: 8px !default;
$ibo-object-details--status-dot--border-radius: $ibo-border-radius-full !default;
$ibo-object-details--tag--sibling-spacing: 12px !default;
$ibo-object-details--tag--color: $ibo-panel--subtitle--color !default;
$ibo-object-details--tag-icon--margin-right: 6px !default;
$ibo-object-details--tag-icon--color: $ibo-color-grey-700 !default;
$ibo-object-details--tag--separator--background-color: $ibo-color-grey-800 !default;
$ibo-object-details--tag--separator--diameter: 5px !default;
$ibo-object-details--tag--separator--margin-right: 12px !default;
$ibo-object-details--tag--separator--border-radius: $ibo-border-radius-full !default;
/* Parent block overloads (!= than blocks integrations */
.ibo-object-details {
&.ibo-has-icon.ibo-has-medallion-icon {
.ibo-panel--header-left {
margin-left: $ibo-object-details--icon--spacing--as-medallion;
padding-left: $ibo-object-details--icon--size;
}
.ibo-panel--icon {
bottom: calc(-1 * #{$ibo-object-details--icon--size} / 2 + #{$ibo-object-details--icon--bottom--as-medallion});
width: $ibo-object-details--icon--size;
height: $ibo-object-details--icon--size;
min-width: $ibo-object-details--icon--size;
min-height: $ibo-object-details--icon--size;
}
.ibo-panel--titles {
padding-left: $ibo-object-details--icon--spacing--as-medallion;
}
}
.ibo-panel--title {
@extend %ibo-font-ral-med-350;
}
.ibo-panel--subtitle {
@extend %ibo-font-ral-med-150;
}
}
.ibo-object-details--status {
@extend %ibo-baseline-centered-content;
}
.ibo-object-details--status-dot {
@extend %ibo-fully-centered-content;
width: $ibo-object-details--status-dot--size;
height: $ibo-object-details--status-dot--size;
min-width: $ibo-object-details--status-dot--size;
min-height: $ibo-object-details--status-dot--size;
border-radius: $ibo-object-details--status-dot--border-radius;
}
.ibo-object-details--status-dot + .ibo-object-details--status-label {
margin-left: $ibo-object-details--status-dot--spacing;
}
.ibo-object-details--status + .ibo-object-details--object-class {
margin-left: 0.5rem;
&::before {
content: "(";
}
&::after {
content: ")";
}
}
@each $sType, $aColors in $ibo-lifecycle-states-colors {
.ibo-object-details--status-dot.ibo-is-state-#{$sType} {
color: map-get($aColors, 'secondary-color');
background-color: map-get($aColors, 'primary-color');
}
}
.ibo-object-details--tag {
color: $ibo-object-details--tag--color;
&:not(:first-child) {
margin-left: $ibo-object-details--tag--sibling-spacing;
}
}
.ibo-object-details--tag-icon {
margin-right: $ibo-object-details--tag-icon--margin-right;
color: $ibo-object-details--tag-icon--color;
}
.ibo-object-details--object-class,
.ibo-object-details--tag {
~ .ibo-object-details--tag::before {
content: " ";
display: inline-block;
vertical-align: middle;
margin-right: $ibo-object-details--tag--separator--margin-right;
width: $ibo-object-details--tag--separator--diameter;
height: $ibo-object-details--tag--separator--diameter;
border-radius: $ibo-object-details--tag--separator--border-radius;
background-color: $ibo-object-details--tag--separator--background-color;
}
}

View File

@@ -209,8 +209,7 @@ $(function() {
const oActivityPanelElem = this.element.closest(this.js_selectors.activity_panel);
const sHostObjClass = oActivityPanelElem.attr('data-object-class');
const sHostObjId = oActivityPanelElem.attr('data-object-id');
// TODO 3.0.0: This might need to be updated when object details are refactored and in a real block
const oGeneralFormElem = $('.object-details[data-object-class="'+sHostObjClass+'"][data-object-id="'+sHostObjId+'"] > form');
const oGeneralFormElem = $('.ibo-object-details[data-object-class="'+sHostObjClass+'"][data-object-id="'+sHostObjId+'"]').closest('form');
// Protection in case this is called with non editable general form
if (oGeneralFormElem.length === 0) {

View File

@@ -83,15 +83,34 @@ class Panel extends UIContentBlock
/** @var string ENUM_CONTENT_AREA_TOOLBAR The toolbar content area (for actions) */
public const ENUM_CONTENT_AREA_TOOLBAR = 'toolbar';
/** @var string Icon should be contained (boxed) in the medallion, best for icons with transparent background and some margin around */
public const ENUM_ICON_COVER_METHOD_CONTAIN = 'contain';
/** @var string Icon should be a litte zoomed out to cover almost all space, best for icons with transparent background and no margin around (eg. class icons) */
public const ENUM_ICON_COVER_METHOD_ZOOMOUT = 'zoomout';
/** @var string Icon should cover all the space, best for icons with filled background */
public const ENUM_ICON_COVER_METHOD_COVER = 'cover';
/** @var string DEFAULT_COLOR */
public const DEFAULT_COLOR = self::ENUM_COLOR_NEUTRAL;
/** @var null */
public const DEFAULT_ICON_URL = null;
/** @var string */
public const DEFAULT_ICON_COVER_METHOD = self::ENUM_ICON_COVER_METHOD_CONTAIN;
/** @var bool */
public const DEFAULT_ICON_AS_MEDALLION = false;
/** @var string $sTitle */
protected $sTitle;
/** @var UIContentBlock */
protected $oSubTitleBlock;
/** @var null|string $sIconUrl */
protected $sIconUrl;
/** @var string How the icon should cover its container, see static::ENUM_ICON_COVER_METHOD_XXX */
protected $sIconCoverMethod;
/** @var bool Whether the icon should be rendered as a medallion (rounded with border) or a standalone image */
protected $bIconAsMedallion;
/** @var string $sColor */
protected $sColor;
/** @var string $sSubTitle */
protected $sSubTitle;
/** @var bool $bIsCollapsible */
protected $bIsCollapsible;
@@ -107,7 +126,11 @@ class Panel extends UIContentBlock
{
parent::__construct($sId);
$this->sTitle = $sTitle;
$this->oSubTitleBlock = new UIContentBlock();
$this->aSubBlocks = $aSubBlocks;
$this->sIconUrl = static::DEFAULT_ICON_URL;
$this->sIconCoverMethod = static::DEFAULT_ICON_COVER_METHOD;
$this->bIconAsMedallion = static::DEFAULT_ICON_AS_MEDALLION;
$this->sColor = $sColor;
$this->SetMainBlocks([]);
$this->SetToolBlocks([]);
@@ -115,6 +138,16 @@ class Panel extends UIContentBlock
}
/**
* @see static::$sTitle
* @return bool
*/
public function HasTitle(): bool
{
return !empty($this->sTitle);
}
/**
* @see static::$sTitle
* @return string
*/
public function GetTitle()
@@ -123,6 +156,8 @@ class Panel extends UIContentBlock
}
/**
* @see static::$sTitle
*
* @param string $sTitle
*
* @return $this
@@ -134,6 +169,61 @@ class Panel extends UIContentBlock
return $this;
}
/**
* @see static::$sIconUrl
* @return bool
*/
public function HasIcon(): bool
{
return !empty($this->sIconUrl);
}
/**
* @see static::$sIconUrl
* @return null|string
*/
public function GetIconUrl(): ?string
{
return $this->sIconUrl;
}
/**
* @see static::$sIconCoverMethod
* @return string
*/
public function GetIconCoverMethod(): string
{
return $this->sIconCoverMethod;
}
/**
* @return bool True if the icon should be displayed as a medallion (round with a border) or as-is.
*/
public function IsIconAsMedallion(): bool
{
return $this->bIconAsMedallion;
}
/**
* @see static::$sIconUrl
* @see static::$sIconCoverMethod
* @see static::$bIconAsMedallion
*
* @param string $sIconUrl
* @param string $sIconCoverMethod
* @param bool $bIconAsMedallion
*
* @return $this
*/
public function SetIcon(string $sIconUrl, string $sIconCoverMethod = self::DEFAULT_ICON_COVER_METHOD, bool $bIconAsMedallion = self::DEFAULT_ICON_AS_MEDALLION)
{
$this->sIconUrl = $sIconUrl;
$this->sIconCoverMethod = $sIconCoverMethod;
$this->bIconAsMedallion = $bIconAsMedallion;
return $this;
}
/**
* @return string
*/
@@ -155,21 +245,60 @@ class Panel extends UIContentBlock
}
/**
* @return string
* @see static::$oSubTitleBlock
* @return bool
*/
public function GetSubTitle()
public function HasSubTitle(): bool
{
return $this->sSubTitle;
return $this->oSubTitleBlock->HasSubBlocks();
}
/**
* @see static::$oSubTitleBlock
* @return string
*/
public function GetSubTitleBlock()
{
return $this->oSubTitleBlock;
}
/**
* Set the subtitle from $sSubTitle, overwritting any existing block
*
* @see static::$oSubTitleBlock
*
* @param string $sSubTitle
*
* @return $this
*/
public function SetSubTitle(string $sSubTitle)
{
$this->sSubTitle = $sSubTitle;
$this->oSubTitleBlock->AddHtml($sSubTitle);
return $this;
}
/**
* Add a UIBlock to the subtitle
*
* @see static::$oSubTitleBlock
*
* @param \Combodo\iTop\Application\UI\Base\iUIBlock $oBlock
*
* @return $this
*/
public function AddSubTitleBlock(iUIBlock $oBlock)
{
$this->oSubTitleBlock->AddSubBlock($oBlock);
return $this;
}
public function AddSubTitleBlocks(array $aBlocks)
{
foreach ($aBlocks as $oBlock) {
$this->AddSubTitleBlock($oBlock);
}
return $this;
}
@@ -192,8 +321,7 @@ class Panel extends UIContentBlock
$this->bIsCollapsible = $bIsCollapsible;
return $this;
}
//----------------------
// Specific content area

View File

@@ -65,9 +65,10 @@ class PanelEnhanced extends Panel
*
* @return PanelEnhanced
*/
public function SetIconUrl(string $sIconUrl): PanelEnhanced
public function SetIcon(string $sIconUrl): PanelEnhanced
{
$this->sIconUrl = $sIconUrl;
return $this;
}

View File

@@ -1,96 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Base\Component\Title;
class TitleForObjectDetails extends Title
{
public const DEFAULT_HTML_TEMPLATE_REL_PATH = 'base/components/title/titleforobjectdetails';
/** @var string */
protected $sClassName;
/** @var string */
protected $sObjectName;
protected $sStatusCode;
protected $sStatusLabel;
protected $sStatusColor;
protected $aTags;
public function __construct(string $sClassName, string $sObjectName, ?string $sId = null)
{
parent::__construct('', 2, $sId);
$this->sClassName = $sClassName;
$this->sObjectName = $sObjectName;
$this->sStatusCode = null;
$this->sStatusLabel = null;
$this->sStatusColor = null;
$this->aTags = [];
}
/**
* @return string
*/
public function GetClassName(): string
{
return $this->sClassName;
}
/**
* @return string
*/
public function GetObjectName(): string
{
return $this->sObjectName;
}
public function SetStatus($sCode, $sLabel, $sColor)
{
$this->sStatusCode = $sColor;
$this->sStatusLabel = $sLabel;
$this->sStatusColor = $sColor;
return $this;
}
public function GetStatusCode()
{
return $this->sStatusCode;
}
public function GetStatusLabel()
{
return $this->sStatusLabel;
}
public function GetStatusColor()
{
return $this->sStatusColor;
}
/**
* @return array
*/
public function GetTags(): array
{
return $this->aTags;
}
/**
* @param array $aTags
*
* @return $this
*/
public function SetTags(array $aTags)
{
$this->aTags = $aTags;
return $this;
}
}

View File

@@ -9,9 +9,6 @@ namespace Combodo\iTop\Application\UI\Base\Component\Title;
use Combodo\iTop\Application\UI\Base\AbstractUIBlockFactory;
use Combodo\iTop\Application\UI\Helper\UIHelper;
use DBObject;
use MetaModel;
class TitleUIBlockFactory extends AbstractUIBlockFactory
{
@@ -34,54 +31,6 @@ class TitleUIBlockFactory extends AbstractUIBlockFactory
return $oTitle;
}
public static function MakeForObjectDetails(DBObject $oObject, array $aTags = [], ?string $sId = null)
{
// TODO 3.0.0: Refactor all of this
$sObjClass = get_class($oObject);
$sObjClassName = MetaModel::GetName($sObjClass);
$sObjName = $oObject->GetName();
// Object icon
// - Default icon is the class icon
$sObjIconUrl = $oObject->GetIcon(false);
// Note: Class icons are a square image with no margin around, so they need to be zoomed out in the medallion
$sIconCoverMethod = Title::ENUM_ICON_COVER_METHOD_ZOOMOUT;
// - Use object image from semantic attribute only if it's not the default image
if(!$oObject->IsNew() && MetaModel::HasImageAttributeCode($sObjClass)){
$sImageAttCode = MetaModel::GetImageAttributeCode($sObjClass);
if(!empty($sImageAttCode)){
/** @var \ormDocument $oImage */
$oImage = $oObject->Get($sImageAttCode);
if(!$oImage->IsEmpty()){
$sObjIconUrl = $oImage->GetDisplayURL($sObjClass, $oObject->GetKey(), $sImageAttCode);
$sIconCoverMethod = Title::ENUM_ICON_COVER_METHOD_COVER;
}
}
}
$oTitle = new TitleForObjectDetails($sObjClassName, $sObjName, $sId);
if(!empty($sObjIconUrl)) {
$oTitle->SetIcon($sObjIconUrl, $sIconCoverMethod);
}
if (MetaModel::HasStateAttributeCode($sObjClass)) {
$sStateCode = $oObject->GetState();
// Protection against classes with no default state (in which case we don't display the status)
if (!empty($sStateCode)) {
$sStatusAttCode = MetaModel::GetStateAttributeCode($sObjClass);
$sStatusLabel = $oObject->GetStateLabel();
$sStatusColor = UIHelper::GetColorFromStatus(get_class($oObject), $sStateCode);
$oTitle->SetStatus($sStatusAttCode, $sStatusLabel, $sStatusColor);
}
}
$oTitle->SetTags($aTags);
return $oTitle;
}
public static function MakeNeutral(string $sTitle, int $iLevel = 1, ?string $sId = null)
{
return new Title($sTitle, $iLevel, $sId);

View File

@@ -44,30 +44,27 @@ class ObjectDetails extends Panel
/**
* ObjectDetails constructor.
*
* @param \DBObject $oObject The object for which we display the details
* @param string $sMode See \cmdbAbstractObject::ENUM_OBJECT_MODE_XXX
* @param string|null $sId ID of the block itself, not the $oObject ID
* @param \DBObject $oObject The object for which we display the details
* @param string $sMode See \cmdbAbstractObject::ENUM_OBJECT_MODE_XXX
* @param string|null $sId ID of the block itself, not the $oObject ID
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function __construct(DBObject $oObject, string $sMode = cmdbAbstractObject::DEFAULT_OBJECT_MODE, ?string $sId = null) {
public function __construct(DBObject $oObject, string $sMode = cmdbAbstractObject::DEFAULT_OBJECT_MODE, ?string $sId = null)
{
$this->sClassName = get_class($oObject);
$this->sClassLabel = MetaModel::GetName($this->GetClassName());
$this->sObjectId = $oObject->GetKey();
// Note: We get the raw name as only the front-end consumer knows when and how to encode it.
$this->sObjectName = $oObject->GetRawName();
$this->sObjectMode = $sMode;
$this->sIconUrl = $oObject->GetIcon(false);
if(MetaModel::HasStateAttributeCode($this->sClassName)) {
$this->sStatusCode = $oObject->GetState();
$this->sStatusLabel = $oObject->GetStateLabel();
$this->sStatusColor = UIHelper::GetColorFromStatus($this->sClassName, $this->sStatusCode);
}
parent::__construct($this->sObjectName, [], static::DEFAULT_COLOR, $sId);
parent::__construct('', [], static::DEFAULT_COLOR, $sId);
$this->ComputeIconUrl($oObject);
$this->ComputeState($oObject);
}
/**
@@ -159,4 +156,44 @@ class ObjectDetails extends Panel
{
return $this->sStatusColor;
}
/**
* @inheritDoc
*/
public function HasSubTitle(): bool
{
return !empty($this->sStatusCode);
}
protected function ComputeIconUrl(DBObject $oObject): void
{
// Default icon is the class icon
$sIconUrl = $oObject->GetIcon(false);
// Note: Class icons are a square image with no margin around, so they need to be zoomed out in the medallion
$sIconCoverMethod = static::ENUM_ICON_COVER_METHOD_ZOOMOUT;
// Use object image from semantic attribute only if it's not the default image
if (!$oObject->IsNew() && MetaModel::HasImageAttributeCode($this->sClassName)) {
$sImageAttCode = MetaModel::GetImageAttributeCode($this->sClassName);
if (!empty($sImageAttCode)) {
/** @var \ormDocument $oImage */
$oImage = $oObject->Get($sImageAttCode);
if (!$oImage->IsEmpty()) {
$sIconUrl = $oImage->GetDisplayURL($this->sClassName, $this->sObjectId, $sImageAttCode);
$sIconCoverMethod = static::ENUM_ICON_COVER_METHOD_COVER;
}
}
}
$this->SetIcon($sIconUrl, $sIconCoverMethod, true);
}
protected function ComputeState(DBObject $oObject): void
{
if (MetaModel::HasStateAttributeCode($this->sClassName)) {
$this->sStatusCode = $oObject->GetState();
$this->sStatusLabel = $oObject->GetStateLabel();
$this->sStatusColor = UIHelper::GetColorFromStatus($this->sClassName, $this->sStatusCode);
}
}
}

View File

@@ -69,6 +69,9 @@ abstract class UIBlock implements iUIBlock
/** @var string ENUM_BLOCK_FILES_TYPE_TEMPLATE */
public const ENUM_BLOCK_FILES_TYPE_TEMPLATE = 'template';
/** @var array Cache for the CSS classes of a block inheritance. Key is the block class, value is an array of CSS classes */
private static $aBlocksInheritanceCSSClassesCache = [];
/** @var string $sId */
protected $sId;
@@ -400,6 +403,42 @@ abstract class UIBlock implements iUIBlock
return implode(' ', $this->GetAdditionalCSSClasses());
}
/**
* @return string[] The identification CSS classes of the all the parent blocks of the current one
*/
public function GetBlocksInheritanceCSSClasses(): array
{
$sCurrentClass = static::class;
// Add to cache if not already there
if (false === array_key_exists($sCurrentClass, self::$aBlocksInheritanceCSSClassesCache)) {
// Start with self
$aCSSClasses = [static::BLOCK_CODE];
// Get class ONLY from parents that implement iUIBlock
foreach (class_parents(static::class) as $sParentClass) {
if (false === in_array(iUIBlock::class, class_implements($sParentClass))) {
continue;
}
$aCSSClasses[] = $sParentClass::BLOCK_CODE;
}
self::$aBlocksInheritanceCSSClassesCache[$sCurrentClass] = $aCSSClasses;
}
return self::$aBlocksInheritanceCSSClassesCache[$sCurrentClass];
}
/**
* @see static::GetBlocksInheritanceCSSClasses()
* @return string Same as the regular method but as a space separated string
*/
public function GetBlocksInheritanceCSSClassesAsString(): string
{
return implode(' ', $this->GetBlocksInheritanceCSSClasses());
}
/**
* Return an array of the URL of the block $sFilesType and its sub blocks.
* URL is relative unless the $bAbsoluteUrl is set to true.

View File

@@ -1,7 +1,9 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% apply spaceless %}
<div id="{{ oUIBlock.GetId() }}" class="ibo-panel ibo-is-{{ oUIBlock.GetColor() }} {{ oUIBlock.GetAdditionalCSSClassesAsString() }}{% if oUIBlock.IsHidden() %} ibo-is-hidden{% endif %} ibo-is-opened" {% block iboPanelMetaData %}{% endblock %}>
<div id="{{ oUIBlock.GetId() }}"
class="ibo-panel ibo-is-{{ oUIBlock.GetColor() }} {{ oUIBlock.GetBlocksInheritanceCSSClassesAsString() }} {{ oUIBlock.GetAdditionalCSSClassesAsString() }} {% if oUIBlock.HasIcon() %}ibo-has-icon{% endif %} {% if oUIBlock.IsIconAsMedallion() %}ibo-has-medallion-icon{% endif %} {% if oUIBlock.IsHidden() %}ibo-is-hidden{% endif %} ibo-is-opened"
{% block iboPanelMetaData %}{% endblock %}>
<div class="ibo-panel--header">
{% block iboPanelHeader %}
<div class="ibo-panel--header-left">
@@ -12,9 +14,24 @@
</div>
{% endif %}
{% block iboPanelHeaderLeft %}
<div class="ibo-panel--title">{% block iboPanelTitle %}{{ oUIBlock.GetTitle()|raw }}{% endblock %}</div>
{% if oUIBlock.GetSubTitle() is not null %}
<div class="ibo-panel--subtitle">{% block iboPanelSubTitle %}{{ oUIBlock.GetSubTitle()|raw }}{% endblock %}</div>
{% if oUIBlock.HasIcon() %}
<div class="ibo-panel--icon">
{% block iboPanelIcon %}
<div class="ibo-panel--icon-background ibo-panel--icon-background--must-{{ oUIBlock.GetIconCoverMethod() }}" style="background-image: url('{{ oUIBlock.GetIconUrl()|raw }}');"></div>
{% endblock %}
</div>
{% endif %}
{% if oUIBlock.HasTitle() or oUIBlock.HasSubTitle() %}
<div class="ibo-panel--titles">
{% block iboPanelTitles %}
{% if oUIBlock.HasTitle() %}
<div class="ibo-panel--title">{% block iboPanelTitle %}{{ oUIBlock.GetTitle() }}{% endblock %}</div>
{% endif %}
{% if oUIBlock.HasSubTitle() %}
<div class="ibo-panel--subtitle">{% block iboPanelSubTitle %}{{ render_block(oUIBlock.GetSubTitleBlock()) }}{% endblock %}</div>
{% endif %}
{% endblock %}
</div>
{% endif %}
{% endblock %}
</div>

View File

@@ -1,14 +1,14 @@
{% apply spaceless %}
<div id="{{ oUIBlock.GetId() }}" class="ibo-title {% if oUIBlock.HasIcon() %}ibo-has-icon{% endif %}{% if oUIBlock.IsHidden() %} ibo-is-hidden{% endif %}">
{% if oUIBlock.HasIcon() %}
<div {% if oUIBlock.IsMedallion %}class="ibo-title--medallion"{% endif %}>
<div class="ibo-title--icon ibo-title--icon--must-{{ oUIBlock.GetIconCoverMethod() }}" style="background-image: url('{{ oUIBlock.GetIconUrl()|raw }}');"></div>
<div class="ibo-title--icon">
<div class="ibo-title--icon-background ibo-title--icon-background--must-{{ oUIBlock.GetIconCoverMethod() }}" style="background-image: url('{{ oUIBlock.GetIconUrl()|raw }}');"></div>
</div>
{% endif %}
<div class="ibo-title--content">
{% block iboPageTitleText %}
<h{{ oUIBlock.GetLevel() }} class="ibo-title--text title is-size-{{ oUIBlock.GetLevel() + 2 }}">
{{ oUIBlock.GetTitle()|raw }}
{{ oUIBlock.GetTitle() }}
</h{{ oUIBlock.GetLevel() }}>
{% endblock %}
</div>

View File

@@ -1,19 +0,0 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% extends 'base/components/title/layout.html.twig' %}
{% block iboPageTitleText %}
<h1 class="ibo-title--for-object-details">{{ oUIBlock.GetObjectName()|raw }}</h1>
<div class="ibo-title--subtitle">
{% if oUIBlock.GetStatusLabel() is not empty %}
<span class="ibo-title--status">
<span class="ibo-title--status-dot ibo-is-state-{{ oUIBlock.GetStatusColor() }}"></span>
<span class="ibo-title--status-label">{{ oUIBlock.GetStatusLabel() }}</span>
</span>
{% endif %}
<span class="ibo-title--object-class">{{ oUIBlock.GetClassName() }}</span>
{% for sTag, aTagValues in oUIBlock.GetTags() %}
<span id="{{ sTag }}" class="ibo-title--object-tags {{ aTagValues.css_classes }}" data-tooltip-content="{{ aTagValues.title }}" data-tooltip-html-enabled="true"><i class="{{ aTagValues.decoration_classes }}"></i>{{ aTagValues.label }}</span>
{% endfor %}
</div>
{% endblock %}

View File

@@ -8,15 +8,13 @@
data-object-mode="{{ oUIBlock.GetObjectMode() }}"
{% endblock %}
{% block iboPanelHeaderLeft %}
<div class="ibo-object-details--medallion">
{% block iboObjectDetailsMedallion %}
{% endblock %}
</div>
<div>
{{ parent() }}
<div class="ibo-object-details--status" data-role="ibo-object-details--status"></div>
</div>
{% endblock %}
{% block iboPanelTitle %}{{ oUIBlock.GetTitle() }}{% endblock %}
{% block iboPanelSubTitle %}
{% if oUIBlock.GetStatusLabel() is not empty %}
<span class="ibo-object-details--status" data-status-code="{{ oUIBlock.GetStatusCode() }}">
<span class="ibo-object-details--status-dot ibo-is-state-{{ oUIBlock.GetStatusColor() }}"></span>
<span class="ibo-object-details--status-label">{{ oUIBlock.GetStatusLabel() }}</span>
</span>
{% endif %}
<span class="ibo-object-details--object-class">{{ oUIBlock.GetClassName() }}</span>
{{ parent() }}
{% endblock %}

View File

@@ -26,10 +26,13 @@ use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\CollapsibleSection\CollapsibleSection;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\Object\ObjectFactory;
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
use iTopWebPage;
use LoginWebPage;
use MetaModel;
use utils;
require_once '../../../approot.inc.php';
@@ -127,10 +130,12 @@ $oPageContentLayout->AddMainBlock(new Html('<hr/>'));
/////////
$oPanelsTitle = new Html('<h2 id="title-panels">Panels examples</h2>');
$oPage->AddUiBlock($oPanelsTitle);
$aSubBlocks = [
new Html('<div>Panel body, can contain anything from simple text to rich text, forms, images, <a href="#">links</a>, graphs or tables.</div>'),
new Html('<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>'),
new Html('<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>'),
];
$sClassIconUrl = MetaModel::GetClassIcon('Organization', false);
$oPanel = PanelUIBlockFactory::MakeNeutral('Neutral panel');
$oPanel->SetSubBlocks($aSubBlocks);
@@ -164,8 +169,70 @@ $oPanel = PanelUIBlockFactory::MakeWithBrandingSecondaryColor('Panel with brandi
$oPanel->SetSubBlocks($aSubBlocks);
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('Panel with title only');
$oPanel->SetSubBlocks($aSubBlocks);
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('')
->SetSubBlocks($aSubBlocks)
->SetSubTitle('Panel with subtitle only');
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('Panel with title and subtitle')
->SetSubBlocks($aSubBlocks)
->SetSubTitle('Subtitle');
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('Panel with title and icon')
->SetSubBlocks($aSubBlocks)
->SetIcon($sClassIconUrl);
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('')
->SetSubBlocks($aSubBlocks)
->SetSubTitle('Panel with subtitle and icon')
->SetIcon($sClassIconUrl);
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('Panel with title, subtitle and icon')
->SetSubBlocks($aSubBlocks)
->SetSubTitle('Subtitle')
->SetIcon($sClassIconUrl);
$oPageContentLayout->AddMainBlock($oPanel);
$oPanel = PanelUIBlockFactory::MakeNeutral('Panel with title, subtitle and icon as a medallion')
->SetSubBlocks($aSubBlocks)
->SetSubTitle('Subtitle')
->SetIcon($sClassIconUrl, Panel::ENUM_ICON_COVER_METHOD_ZOOMOUT, true);
$oPageContentLayout->AddMainBlock($oPanel);
$oPageContentLayout->AddMainBlock(new Html('<hr/>'));
/////////
// ObjectDetails
/////////
$oObjecTDetailsTitle = new Html('<h2 id="title-object-details">ObjectDetails examples</h2>');
$oPage->AddUiBlock($oObjecTDetailsTitle);
$oOrgObject = MetaModel::NewObject('Organization');
$oOrgObject->Set('name', 'Stub, no tab container. Just to see how the header is displayed');
$oOrgObject->Set('status', 'active');
$oObjectDetails = ObjectFactory::MakeDetails($oOrgObject);
$oPageContentLayout->AddMainBlock($oObjectDetails);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, '', $oObjectDetails);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab('First');
$oPage->add('Extra tabs icon is normal as there is no JS widget instantiated here.');
$oPage->SetCurrentTab('Second');
$oPage->SetCurrentTab('Third');
$oPage->SetCurrentTab('Fourth');
$oPage->SetCurrentTab('Fifth');
$oPage->SetCurrentTab('Sixth');
$oPage->SetCurrentTab('Seventh');
$oPage->SetCurrentTabContainer();
$oPageContentLayout->AddMainBlock(new Html('<hr/>'));
/////////
// Collapsible Section