N°4684 - Align portal default theme with backoffice one (#702)

* Prepare SCSS files and move nav menu / main wrapper from Bootstrap positioning

* Small work on navigation menu

* Split bootstrap theme file into multiple files inside themes/

* Fix unit test missing css/ import path

* Better display for usercard

* Upload precompiled portal stylesheets to fix unit test based on portal.css

* Polish menu

* Stylize home tiles

* Stylize home tiles and layout pages

* Stylize home tiles and layout pages

* Stylize home tiles and layout pages

* Stylize home tiles and layout pages

* Define default font in a more elegant way

* Small implementation for open/close navigation_menu

* Fix navigation menu dropdown menu not working

* Fix menu colors

* Set  <html> lang attribute

* Add accessibility attributes to menu toggler

* Fix bricks / page title dot spacing

* new look adaptation

* Fix padding in manage brick

* Fix menu entries font size and color

* Change manage export color

* Fix icon size in tiles

* Add style to manage brick panels

* Redesign browse brick mosaic view

* Fix variable name collision

* - Set templates cache in dev mode to 1s
- Implements components classes JS
- Move navigations layouts outside the global layout
- Update tiles

* Fix tile description font size

* Redesign browse brick tree mode

* Tweak navigation menu css

* - use custom elements for js components
- adjust layouts

* Modify forms/modals

* Modify method name following code review

* Add a dropdown element to replace bootstrap one

* improvement to dropdown

* datatable prevent column sort icon to wrap

* update composer json file.
Without classmap-authoritative flag, classmap are not generated
There is no test folder

* remove colored circle in manage brick tile titles

* remove white span between title and title additional part in brick layout

* convert navigation menu js to custom element

* navigation menu (WIP)

* Improvement to dropdown

* Fix some caselog classes

* Improvement to dropdown

* Improvement to dropdown

* navigation menu (WIP)

* portal ui version  2025

* datatable sort icon issue on link sets

* portal ui settings

* Fix dropdown for browse brick

* add portal scss colors

* add alerts scss=

* Buttons improvement

* Correction list table action issue

* responsive adjustments

* restore ben-j erased stephen

* ipb-button integration

* remove table header bottom border

* remove brick page ipb-page--main-header duplicate

* Adjust button styel

* Fix browse brick buttons

* Correctly overload approot and fix scsss imports

* Fix treeview expand buttons, fix mosaic first display glitch and add animation to each mosaic tile drawn

* Fix treeview toolbar

* remove wrap from ipb-button-groups

* Fix hover and clickable space in mosaics

* Clean dropdown css

* Fix dropdown menu content for a better display

* Align pagination buttons with theme buttons

* Align pagination buttons with theme buttons

* Fix drowdown

* Add precompiled stylesheets for merge to main branch

---------

Co-authored-by: Benjamin Dalsass <95754414+bdalsass@users.noreply.github.com>
This commit is contained in:
Stephen Abello
2025-03-05 14:31:00 +01:00
committed by GitHub
parent c9c3b6c108
commit f095f93326
113 changed files with 17510 additions and 7731 deletions

View File

@@ -64,8 +64,8 @@ class ManageBrick extends PortalBrick
const ENUM_PAGE_TEMPLATE_PATH_CHART = 'itop-portal-base/portal/templates/bricks/manage/layout-chart.html.twig';
/** Overloaded constants */
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-pen-square';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-pen-square fa-2x';
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-tag';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-tag fa-2x';
/**
* @deprecated 3.2.1
*/
@@ -95,6 +95,8 @@ class ManageBrick extends PortalBrick
const DEFAULT_GROUP_LIMIT = 0;
/** @var bool DEFAULT_GROUP_SHOW_OTHERS */
const DEFAULT_GROUP_SHOW_OTHERS = true;
/** @var int DEFAULT_WIDTH */
const DEFAULT_WIDTH = 500;
/** @var array $aDisplayModes */
public static array $aDisplayModes = array(
@@ -156,19 +158,24 @@ class ManageBrick extends PortalBrick
/** @var array $aDefaultTileData */
private static array $aDefaultTileData = [
self::ENUM_TILE_MODE_BADGE => [
'decorationCssClass' => 'fas fa-id-card fa-2x',
'decorationCssClass' => 'fas fa-tags fa-2x',
'width' => self::DEFAULT_WIDTH,
],
self::ENUM_TILE_MODE_TOP => [
'decorationCssClass' => 'fas fa-list-ol fa-2x',
'width' => self::DEFAULT_WIDTH,
],
self::ENUM_TILE_MODE_PIE => [
'decorationCssClass' => 'fas fa-chart-pie fa-2x',
'width' => 600,
],
self::ENUM_TILE_MODE_TEXT => [
'decorationCssClass' => 'fas fa-pen-square fa-2x',
'decorationCssClass' => 'fas fa-tag fa-2x',
'width' => self::DEFAULT_WIDTH,
],
self::ENUM_TILE_MODE_BAR => [
'decorationCssClass' => 'fas fa-chart-bar fa-2x',
'width' => 600,
],
];
@@ -918,6 +925,7 @@ class ManageBrick extends PortalBrick
$this->sDecorationClassHome = static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass'];
$this->SetDecorationClassNavigationMenu(static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass']);
$this->SetDecorationClassHome(static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass']);
$this->SetWidth(static::$aDefaultTileData[$this->GetTileMode()]['width']);
}
break;
}

View File

@@ -45,9 +45,9 @@ abstract class PortalBrick extends AbstractBrick
const ENUM_OPENING_TARGET_NEW = 'new';
/** @var int DEFAULT_WIDTH */
const DEFAULT_WIDTH = 6;
const DEFAULT_WIDTH = 400;
/** @var int DEFAULT_HEIGHT */
const DEFAULT_HEIGHT = 1;
const DEFAULT_HEIGHT = null;
/** @var bool DEFAULT_MODAL */
const DEFAULT_MODAL = false;
/** @var bool DEFAULT_VISIBLE_HOME */
@@ -73,7 +73,7 @@ abstract class PortalBrick extends AbstractBrick
/** @var int $iWidth */
protected $iWidth;
/** @var bool width in pixel flag */
public bool $bIsWidthPixel = false;
public bool $bIsWidthPixel = true;
/** @var int $iHeight */
protected $iHeight;
/** @var bool $bModal */

View File

@@ -34,6 +34,7 @@ use DOMFormatException;
class UserProfileBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_WIDTH = 200;
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
const DEFAULT_VISIBLE_HOME = false;
const DEFAULT_DECORATION_CLASS_HOME = 'glyphicon glyphicon-user';

View File

@@ -44,6 +44,7 @@ abstract class AbstractController extends SymfonyAbstractController implements T
{
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'layout.html.twig'),
TemplateDefinitionDto::Create('navigation_menu', static::TEMPLATES_BASE_PATH.'/pages/navigation_menu.html.twig'),
TemplateDefinitionDto::Create('modal', static::TEMPLATES_BASE_PATH . 'modal/layout.html.twig'),
TemplateDefinitionDto::Create('loader', static::TEMPLATES_BASE_PATH.'helpers/loader.html.twig'),
TemplateDefinitionDto::Create('tagset_clic_handler_js', static::TEMPLATES_BASE_PATH.'helpers/tagset_clic_handler.js.twig'),

View File

@@ -37,6 +37,7 @@ class PortalCollector extends AbstractDataCollector
'instances_overridden_templates' => $this->oTemplatesProviderService->GetInstancesOverriddenTemplatesPaths(),
'templates_count' => $this->ComputeOverridesCount($aTemplatesDefinitions),
'ui_version' => $oRegister->GetUIVersion(),
'ui_settings' => $oRegister->GetSettings(),
];
}
@@ -84,6 +85,15 @@ class PortalCollector extends AbstractDataCollector
return $this->data['ui_version'];
}
/**
* @return string
* @noinspection PhpUnused
*/
public function GetUISettings(): array
{
return $this->data['ui_settings'];
}
private function ComputeOverridesCount($aTemplatesDefinitions): array
{
$iCount = 0;

View File

@@ -75,13 +75,17 @@ class Basic extends AbstractConfiguration
$aPortalConf = array(
'properties' => array(
'id' => $_ENV['PORTAL_ID'],
'ui_version' => '2017',
'ui_version' => '2025',
'ui_settings' => [
'navigation_menu' => 'horizontal',
],
'name' => 'Page:DefaultTitle',
'logo' => Branding::GetPortalLogoAbsoluteUrl(),
'favicon' => Branding::GetPortalFavIconAbsoluteUrl(),
'themes' => array(
'bootstrap' => 'itop-portal-base/portal/public/css/bootstrap-theme-combodo.scss',
'portal' => 'itop-portal-base/portal/public/css/portal.scss',
'main' => 'itop-portal-base/portal/public/css/main.scss',
'others' => array(),
),
'templates' => array(
@@ -127,6 +131,11 @@ class Basic extends AbstractConfiguration
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
break;
case 'ui_settings':
foreach ($oPropertyNode->GetNodes('*') as $oSubNode) {
$aPortalConf['properties'][$oPropertyNode->nodeName][$oSubNode->nodeName] = $oSubNode->GetText();
}
break;
case 'themes':
case 'templates':

View File

@@ -140,7 +140,7 @@ class SessionMessageHelper implements IteratorAggregate
$aRanks = array();
foreach ($aMessageObjectData as $sMessageId => $aMessageData)
{
$sMsgClass = 'alert alert-dismissible alert-';
$sMsgClass = 'ipb-alert alert alert-dismissible alert-';
switch ($aMessageData['severity'])
{
case static::ENUM_SEVERITY_INFO:

View File

@@ -92,8 +92,14 @@ class TemplatesProviderService
$sUIVersion = $aCombodoPortalInstanceConf['properties']['ui_version'];
}
// UI settings
$aUISettings = [];
if (isset($aCombodoPortalInstanceConf['properties']['ui_settings'])) {
$aUISettings = $aCombodoPortalInstanceConf['properties']['ui_settings'];
}
// create template register
$oTemplateRegister = new TemplatesRegister($sUIVersion);
$oTemplateRegister = new TemplatesRegister($sUIVersion, $aUISettings);
// search for templates providers
// only non-abstract classes are discovered.

View File

@@ -33,8 +33,7 @@ class TemplatesRegister
/** @var array Templates definitions (possibly altered by portal configuration) */
private array $aTemplatesDefinitions = [];
public function __construct(private string $sTemplateUIVersion = 'unset')
public function __construct(private string $sTemplateUIVersion = 'unset', private array $aSettings = [])
{
}
@@ -47,6 +46,16 @@ class TemplatesRegister
return $this->sTemplateUIVersion;
}
public function GetSettings(): array
{
return $this->aSettings;
}
public function GetSetting(string $sSettingName): string
{
return $this->aSettings[$sSettingName];
}
public function IsProviderExists(string $sProviderId): bool
{
return array_key_exists($sProviderId, $this->aTemplatesDefinitions);

View File

@@ -19,7 +19,9 @@
namespace Combodo\iTop\Portal\Twig;
use appUserPreferences;
use Combodo\iTop\Portal\EventListener\UserProvider;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
@@ -34,17 +36,16 @@ use Twig\Extension\GlobalsInterface;
*/
class AppGlobal extends AbstractExtension implements GlobalsInterface
{
/** @var \Combodo\iTop\Portal\EventListener\UserProvider $userProvider */
private $userProvider;
/**
* Constructor.
*
* @param \Combodo\iTop\Portal\EventListener\UserProvider $userProvider
* @param \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService $oTemplateProviderService
*/
public function __construct(UserProvider $userProvider)
public function __construct(private UserProvider $userProvider, private TemplatesProviderService $oTemplateProviderService)
{
$this->userProvider = $userProvider;
}
/**
@@ -56,6 +57,9 @@ class AppGlobal extends AbstractExtension implements GlobalsInterface
{
$data = array();
$data['allowed_portals'] = $this->userProvider->getAllowedPortals();
$data['user_preferences'] = json_decode(appUserPreferences::GetAsJSON(), true);
$data['ui_settings'] = $this->oTemplateProviderService->GetRegister()->GetSettings();
return $data;
}