浏览代码

Customer portal : Look and feel WIP

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@4107 a333f486-631f-4898-b8df-5754b55c2be0
glajarige 9 年之前
父节点
当前提交
fadddda8e6
共有 21 个文件被更改,包括 759 次插入39 次删除
  1. 10 2
      datamodels/2.x/itop-incident-mgmt-itil/datamodel.itop-incident-mgmt-itil.xml
  2. 10 2
      datamodels/2.x/itop-knownerror-mgmt/datamodel.itop-knownerror-mgmt.xml
  3. 34 2
      datamodels/2.x/itop-portal-base/portal/src/entities/abstractbrick.class.inc.php
  4. 2 0
      datamodels/2.x/itop-portal-base/portal/src/entities/browsebrick.class.inc.php
  5. 2 0
      datamodels/2.x/itop-portal-base/portal/src/entities/createbrick.class.inc.php
  6. 2 0
      datamodels/2.x/itop-portal-base/portal/src/entities/managebrick.class.inc.php
  7. 241 5
      datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php
  8. 2 0
      datamodels/2.x/itop-portal-base/portal/src/entities/userprofilebrick.class.inc.php
  9. 2 2
      datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php
  10. 5 2
      datamodels/2.x/itop-portal-base/portal/src/views/bricks/tile.html.twig
  11. 12 4
      datamodels/2.x/itop-portal-base/portal/src/views/layout.html.twig
  12. 166 6
      datamodels/2.x/itop-portal-base/portal/web/css/portal.css
  13. 3 0
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/css/font-awesome.min.css
  14. 二进制
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/FontAwesome.otf
  15. 二进制
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.eot
  16. 196 0
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.svg
  17. 二进制
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.ttf
  18. 二进制
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.woff
  19. 二进制
      datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.woff2
  20. 10 2
      datamodels/2.x/itop-request-mgmt-itil/datamodel.itop-request-mgmt-itil.xml
  21. 62 12
      datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml

+ 10 - 2
datamodels/2.x/itop-incident-mgmt-itil/datamodel.itop-incident-mgmt-itil.xml

@@ -1769,10 +1769,18 @@
 				</brick>
 				<brick id="create-incident-itil" xsi:type="Combodo\iTop\Portal\Brick\CreateBrick" _delta="define">
 					<active>true</active>
-					<rank>3.5</rank>
+					<rank>
+						<default>3.5</default>
+					</rank>
 					<width>8</width>
 					<modal>true</modal>
-					<title>Portal:CreateNewIncidentItil</title>
+					<title>
+						<default>Portal:CreateNewIncidentItil</default>
+					</title>
+					<description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+					<decoration_class>
+						<default>fa fa-plus fa-2x</default>
+					</decoration_class>
 					<class>Incident</class>
 					<!-- Class that will be created with the form -->
 					<rules>

+ 10 - 2
datamodels/2.x/itop-knownerror-mgmt/datamodel.itop-knownerror-mgmt.xml

@@ -604,9 +604,17 @@
       <bricks>
         <brick id="faq" xsi:type="Combodo\iTop\Portal\Brick\BrowseBrick" _delta="define">
           <active>true</active>
-          <rank>7</rank>
+          <rank>
+			  <default>7</default>
+		  </rank>
           <width>4</width>
-          <title>Brick:Portal:FAQ:Title</title>
+			<title>
+				<default>Brick:Portal:FAQ:Title</default>
+			</title>
+			<description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+			<decoration_class>
+				<default>fa fa-map fa-2x</default>
+			</decoration_class>
           <levels>
             <level id="1">
               <class>FAQCategory</class>

+ 34 - 2
datamodels/2.x/itop-portal-base/portal/src/entities/abstractbrick.class.inc.php

@@ -42,6 +42,7 @@ abstract class AbstractBrick
 	const ENUM_DATA_LOADING_AUTO = 'auto';
 	const DEFAULT_MANDATORY = true;
 	const DEFAULT_ACTIVE = true;
+	const DEFAULT_VISIBLE = true;
 	const DEFAULT_RANK = 1.0;
 	const DEFAULT_PAGE_TEMPLATE_PATH = null;
 	const DEFAULT_TITLE = '';
@@ -53,6 +54,7 @@ abstract class AbstractBrick
 	protected $sId;
 	protected $bMandatory;
 	protected $bActive;
+	protected $bVisible;
 	protected $fRank;
 	protected $sPageTemplatePath;
 	protected $sTitle;
@@ -80,6 +82,7 @@ abstract class AbstractBrick
 	{
 		$this->bMandatory = static::DEFAULT_MANDATORY;
 		$this->bActive = static::DEFAULT_ACTIVE;
+		$this->bVisible = static::DEFAULT_VISIBLE;
 		$this->fRank = static::DEFAULT_RANK;
 		$this->sPageTemplatePath = static::DEFAULT_PAGE_TEMPLATE_PATH;
 		$this->sTitle = static::DEFAULT_TITLE;
@@ -122,6 +125,16 @@ abstract class AbstractBrick
 	}
 
 	/**
+	 * Returns if brick is visible
+	 *
+	 * @return boolean
+	 */
+	public function GetVisible()
+	{
+		return $this->bVisible;
+	}
+
+	/**
 	 * Returns the brick rank
 	 *
 	 * @return float
@@ -234,6 +247,17 @@ abstract class AbstractBrick
 	}
 
 	/**
+	 * Sets if the brick is visible
+	 *
+	 * @param boolean $bVisible
+	 */
+	public function SetVisible($bVisible)
+	{
+		$this->bVisible = $bVisible;
+		return $this;
+	}
+
+	/**
 	 * Sets if the brick is active
 	 *
 	 * @param boolean $bActive
@@ -512,7 +536,11 @@ abstract class AbstractBrick
 					$this->SetActive(($oBrickSubNode->GetText() === 'false') ? false : true );
 					break;
 				case 'rank':
-					$this->SetRank((float) $oBrickSubNode->GetText(static::DEFAULT_RANK));
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$this->SetRank((float) $oOptionalNode->GetText(static::DEFAULT_RANK));
+					}
 					break;
 				case 'templates':
 					$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id=' . ModuleDesign::XPathQuote('page') . ']');
@@ -522,7 +550,11 @@ abstract class AbstractBrick
 					}
 					break;
 				case 'title':
-					$this->SetTitle($oBrickSubNode->GetText(static::DEFAULT_TITLE));
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$this->SetTitle($oOptionalNode->GetText(static::DEFAULT_TITLE));
+					}
 					break;
 				case 'description':
 					$this->SetDescription($oBrickSubNode->GetText(static::DEFAULT_DESCRIPTION));

+ 2 - 0
datamodels/2.x/itop-portal-base/portal/src/entities/browsebrick.class.inc.php

@@ -30,6 +30,8 @@ use \Combodo\iTop\Portal\Brick\PortalBrick;
  */
 class BrowseBrick extends PortalBrick
 {
+	const DEFAULT_HOME_ICON_CLASS = 'fa fa-map';
+	const DEFAULT_NAVIGATION_MENU_ICON_CLASS = 'fa fa-map fa-2x';
 	const ENUM_BROWSE_MODE_LIST = 'list';
 	const ENUM_BROWSE_MODE_TREE = 'tree';
 	const ENUM_ACTION_VIEW = 'view';

+ 2 - 0
datamodels/2.x/itop-portal-base/portal/src/entities/createbrick.class.inc.php

@@ -30,6 +30,8 @@ use \Combodo\iTop\Portal\Brick\PortalBrick;
  */
 class CreateBrick extends PortalBrick
 {
+	const DEFAULT_HOME_ICON_CLASS = 'fa fa-plus';
+	const DEFAULT_NAVIGATION_MENU_ICON_CLASS = 'fa fa-plus fa-2x';
 	const DEFAULT_CLASS = '';
 
 	static $sRouteName = 'p_create_brick';

+ 2 - 0
datamodels/2.x/itop-portal-base/portal/src/entities/managebrick.class.inc.php

@@ -32,6 +32,8 @@ use MetaModel;
  */
 class ManageBrick extends PortalBrick
 {
+	const DEFAULT_HOME_ICON_CLASS = 'fa fa-pencil-square';
+	const DEFAULT_NAVIGATION_MENU_ICON_CLASS = 'fa fa-pencil-square fa-2x';
 	const ENUM_ACTION_VIEW = 'view';
 	const ENUM_ACTION_EDIT = 'edit';
 	const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/manage/layout.html.twig';

+ 241 - 5
datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php

@@ -37,6 +37,8 @@ abstract class PortalBrick extends AbstractBrick
 	const DEFAULT_MODAL = false;
 	const DEFAULT_VISIBLE_HOME = true;
 	const DEFAULT_VISIBLE_NAVIGATION_MENU = true;
+	const DEFAULT_DECORATION_CLASS_HOME = '';
+	const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = '';
 	const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/tile.html.twig';
 
 	static $sRouteName = null;
@@ -45,7 +47,14 @@ abstract class PortalBrick extends AbstractBrick
 	protected $bModal;
 	protected $bVisibleHome;
 	protected $bVisibleNavigationMenu;
+	protected $sDecorationClassHome;
+	protected $sDecorationClassNavigationMenu;
 	protected $sTileTemplatePath;
+	// Vars below are itemization from parent class
+	protected $fRankHome;
+	protected $fRankNavigationMenu;
+	protected $sTitleHome;
+	protected $sTitleNavigationMenu;
 
 	static function GetRouteName()
 	{
@@ -64,6 +73,8 @@ abstract class PortalBrick extends AbstractBrick
 		$this->bModal = static::DEFAULT_MODAL;
 		$this->bVisibleHome = static::DEFAULT_VISIBLE_HOME;
 		$this->bVisibleNavigationMenu = static::DEFAULT_VISIBLE_NAVIGATION_MENU;
+		$this->sDecorationClassHome = static::DEFAULT_DECORATION_CLASS_HOME;
+		$this->sDecorationClassNavigationMenu = static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU;
 		$this->sTileTemplatePath = static::DEFAULT_TILE_TEMPLATE_PATH;
 	}
 
@@ -118,6 +129,66 @@ abstract class PortalBrick extends AbstractBrick
 	}
 
 	/**
+	 * Returns if the brick's rank on the portal's home page
+	 *
+	 * @return int
+	 */
+	public function GetRankHome()
+	{
+		return $this->bRankHome;
+	}
+
+	/**
+	 * Returns if the brick's rank on the portal's navigation menu
+	 *
+	 * @return int
+	 */
+	public function GetRankNavigationMenu()
+	{
+		return $this->bRankNavigationMenu;
+	}
+
+	/**
+	 * Return the css class that will be applied to the brick's decoration in its home tile
+	 *
+	 * @return string
+	 */
+	public function GetDecorationClassHome()
+	{
+		return $this->sDecorationClassHome;
+	}
+
+	/**
+	 * Return the css class that will be applied to the brick's decoration in its navigation menu item
+	 *
+	 * @return string
+	 */
+	public function GetDecorationClassNavigationMenu()
+	{
+		return $this->sDecorationClassNavigationMenu;
+	}
+
+	/**
+	 * Return the brick's title on the home page
+	 *
+	 * @return string
+	 */
+	public function GetTitleHome()
+	{
+		return $this->sTitleHome;
+	}
+
+	/**
+	 * Return the brick's title on the navigation menu
+	 *
+	 * @return string
+	 */
+	public function GetTitleNavigationMenu()
+	{
+		return $this->sTitleNavigationMenu;
+	}
+
+	/**
 	 * Returns the brick tile template path
 	 *
 	 * @return string
@@ -183,6 +254,72 @@ abstract class PortalBrick extends AbstractBrick
 	}
 
 	/**
+	 * Sets if the brick's rank on the portal's home
+	 *
+	 * @param boolean $fRank
+	 */
+	public function SetRankHome($fRankHome)
+	{
+		$this->fRankHome = $fRankHome;
+		return $this;
+	}
+
+	/**
+	 * Sets if the brick's rank on the portal's navigation menu
+	 *
+	 * @param boolean $fRank
+	 */
+	public function SetRankNavigationMenu($fRankNavigationMenu)
+	{
+		$this->fRankNavigationMenu = $fRankNavigationMenu;
+		return $this;
+	}
+
+	/**
+	 * Sets if the brick's decoration class on the portal's home
+	 *
+	 * @param boolean $sDecorationClassHome
+	 */
+	public function SetDecorationClassHome($sDecorationClassHome)
+	{
+		$this->sDecorationClassHome = $sDecorationClassHome;
+		return $this;
+	}
+
+	/**
+	 * Sets if the brick's decoration class on the portal's navigation menu
+	 *
+	 * @param boolean $sDecorationClassNavigationMenu
+	 */
+	public function SetDecorationClassNavigationMenu($sDecorationClassNavigationMenu)
+	{
+		$this->sDecorationClassNavigationMenu = $sDecorationClassNavigationMenu;
+		return $this;
+	}
+
+	/**
+	 * Sets if the brick's title on the portal's home
+	 *
+	 * @param boolean $sTitleHome
+	 */
+	public function SetTitleHome($sTitleHome)
+	{
+		$this->sTitleHome = $sTitleHome;
+		return $this;
+	}
+
+	/**
+	 * Sets if the brick's title on the portal's navigation menu
+	 *
+	 * @param boolean $sTitleNavigationMenu
+	 */
+	public function SetTitleNavigationMenu($sTitleNavigationMenu)
+	{
+		$this->sTitleNavigationMenu = $sTitleNavigationMenu;
+		return $this;
+	}
+
+	/**
 	 * Sets the brick tile template path
 	 *
 	 * @param boolean $sTileTemplatePath
@@ -219,11 +356,29 @@ abstract class PortalBrick extends AbstractBrick
 					$bModal = ($oBrickSubNode->GetText(static::DEFAULT_MODAL) === 'true');
 					$this->SetModal($bModal);
 					break;
-				case 'visible_home':
-					$this->SetVisibleHome(($oBrickSubNode->GetText() === 'false') ? false : true );
-					break;
-				case 'visible_navigation_menu':
-					$this->SetVisibleNavigationMenu(($oBrickSubNode->GetText() === 'false') ? false : true );
+				case 'visible':
+					// Default value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = ($oOptionalNode->GetText() === 'false') ? false : true;
+						$this->SetVisibleHome($optionalNodeValue);
+						$this->SetVisibleNavigationMenu($optionalNodeValue);
+					}
+					// Home value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('home');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = ($oOptionalNode->GetText() === 'false') ? false : true;
+						$this->SetVisibleHome($optionalNodeValue);
+					}
+					// Navigation menu value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('navigation_menu');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = ($oOptionalNode->GetText() === 'false') ? false : true;
+						$this->SetVisibleNavigationMenu($optionalNodeValue);
+					}
 					break;
 				case 'templates':
 					$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id=' . ModuleDesign::XPathQuote('tile') . ']');
@@ -232,6 +387,87 @@ abstract class PortalBrick extends AbstractBrick
 						$this->SetTileTemplatePath($oTemplateNodeList->item(0)->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
 					}
 					break;
+				case 'rank':
+					// Setting value from parent attribute
+					$this->SetRankHome($this->fRank);
+					$this->SetRankNavigationMenu($this->fRank);
+					// Default value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_RANK);
+						$this->SetRankHome($optionalNodeValue);
+						$this->SetRankNavigationMenu($optionalNodeValue);
+					}
+					// Home value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('home');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_RANK);
+						$this->SetRankHome($optionalNodeValue);
+					}
+					// Navigation menu value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('navigation_menu');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_RANK);
+						$this->SetRankNavigationMenu($optionalNodeValue);
+					}
+					break;
+				case 'title':
+					// Setting value from parent attribute
+					$this->SetTitleHome($this->sTitle);
+					$this->SetTitleNavigationMenu($this->sTitle);
+					// Default value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_TITLE);
+						$this->SetTitleHome($optionalNodeValue);
+						$this->SetTitleNavigationMenu($optionalNodeValue);
+					}
+					// Home value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('home');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_TITLE);
+						$this->SetTitleHome($optionalNodeValue);
+					}
+					// Navigation menu value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('navigation_menu');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_TITLE);
+						$this->SetTitleNavigationMenu($optionalNodeValue);
+					}
+					break;
+				case 'decoration_class':
+					// Setting value from parent attribute
+					$this->SetDecorationClassHome(static::DEFAULT_DECORATION_CLASS_HOME);
+					$this->SetDecorationClassNavigationMenu(static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU);
+					// Default value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('default');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU);
+						$this->SetDecorationClassHome($optionalNodeValue);
+						$this->SetDecorationClassNavigationMenu($optionalNodeValue);
+					}
+					// Home value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('home');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_DECORATION_CLASS_HOME);
+						$this->SetDecorationClassHome($optionalNodeValue);
+					}
+					// Navigation menu value
+					$oOptionalNode = $oBrickSubNode->GetOptionalElement('navigation_menu');
+					if ($oOptionalNode !== null)
+					{
+						$optionalNodeValue = $oOptionalNode->GetText(static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU);
+						$this->SetDecorationClassNavigationMenu($optionalNodeValue);
+					}
+					break;
 			}
 		}
 

+ 2 - 0
datamodels/2.x/itop-portal-base/portal/src/entities/userprofilebrick.class.inc.php

@@ -34,6 +34,8 @@ class UserProfileBrick extends PortalBrick
 	const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
 	const DEFAULT_VISIBLE_HOME = false;
 	const DEFAUT_TITLE = 'Brick:Portal:UserProfile:Title';
+	const DEFAULT_HOME_ICON_CLASS = 'glyphicon glyphicon-user';
+	const DEFAULT_NAVIGATION_MENU_ICON_CLASS = 'glyphicon glyphicon-user';
 
 	static $sRouteName = 'p_user_profile_brick';
 	protected $aForm;

+ 2 - 2
datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php

@@ -290,7 +290,7 @@ class ApplicationHelper
 				'properties' => array(
 					'id' => PORTAL_ID,
 					'name' => 'Page:DefaultTitle',
-					'logo' => (file_exists(MODULESROOT . 'branding/portal-logo.png')) ? utils::GetAbsoluteUrlModulesRoot() . 'branding/portal-logo.png' : '../images/itop-logo.png',
+					'logo' => (file_exists(MODULESROOT . 'branding/portal-logo.png')) ? utils::GetAbsoluteUrlModulesRoot() . 'branding/portal-logo.png' : '../images/logo-itop-dark-bg.svg',
 					'themes' => array(
 						'bootstrap' => $oApp['combodo.portal.base.absolute_url'] . 'css/bootstrap-theme.min.css',
 						'portal' => $oApp['combodo.portal.base.absolute_url'] . 'css/portal.css',
@@ -623,7 +623,7 @@ class ApplicationHelper
 		{
 			return $a->GetRank() > $b->GetRank();
 		});
-
+		
 		return $aPortalConf;
 	}
 

+ 5 - 2
datamodels/2.x/itop-portal-base/portal/src/views/bricks/tile.html.twig

@@ -25,9 +25,12 @@
 			{% if app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %}
 			{% if brick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}
 			 class="tile vertical-center" id="brick-{{ brick.GetId }}" data-brick-id="{{ brick.GetId }}">
-			<div class="tile_decoration"><img src="{{ app['combodo.portal.base.absolute_url'] }}img/icons/{{sIcon}}"	/></div>
+		<div class="tile_decoration">
+			<span class="{{ brick.GetDecorationClassHome }}"></span>
+			
+		</div>
 			<div clss="tile_body">
-				<div class="tile_title">{{ brick.GetTitle|dict_s }}</div>
+				<div class="tile_title">{{ brick.GetTitleHome|dict_s }}</div>
 				{% if brick.HasDescription %}
 					<div class="tile_description">{{ brick.GetDescription }}</div>
 				{% endif %}

+ 12 - 4
datamodels/2.x/itop-portal-base/portal/src/views/layout.html.twig

@@ -6,6 +6,7 @@
 	{% set sUserFullname = app['combodo.current_user'].Get('first_name') ~ ' ' ~ app['combodo.current_user'].Get('last_name') %}
 	{% set sUserEmail = app['combodo.current_user'].Get('email') %}
 	{% set sUserPhotoUrl = app['combodo.portal.base.absolute_url'] ~ 'img/user-profile-default-256px.png' %}
+	{% set sUserPhotoUrl = 'https://scontent-fra3-1.xx.fbcdn.net/v/t1.0-9/11050099_10153305298138954_7206181025917413544_n.jpg?oh=728b8e7b1f073b81a2e6b43858c795f8&oe=57E2B0D3' %}
 {% else %}
 	{% set bUserConnected = false %}
 	{% set sUserFullname = '' %}
@@ -33,6 +34,8 @@
 		<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/scroller.bootstrap.min.css" rel="stylesheet">
 		<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/select.bootstrap.min.css" rel="stylesheet">
 		<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/select.dataTables.min.css" rel="stylesheet">
+		{# - Font awesome #}
+		<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
 		{# - Misc libs #}
 		<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/typeahead/css/typeaheadjs.bootstrap.css" rel="stylesheet">
 		<link href="{{ app['combodo.absolute_url'] }}css/magnific-popup.css" rel="stylesheet">
@@ -115,8 +118,9 @@
 				<div class="collapse navbar-collapse" id="navbar">
 					<ul class="nav navbar-nav">
 						{% block pNavigationTopBricks %}
-							<li>
+							<li class="{% if oBrick is not defined %}active{% endif %}">
 								<a href="{{ app.url_generator.generate('p_home') }}">
+									<span class="brick_icon fa fa-home"></span>
 									{{ 'Page:Home'|dict_s }}
 								</a>
 							</li>
@@ -124,7 +128,8 @@
 								{% if brick.GetActive and brick.GetVisibleNavigationMenu and brick.GetRouteName is not null %}
 									<li class="{% if oBrick is defined and brick.id == oBrick.id %}active{% endif %}">
 										<a href="{{ app.url_generator.generate(brick.GetRouteName, {sBrickId: brick.GetId}) }}{% if app['combodo.portal.instance.routes'][brick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][brick.GetRouteName]['hash'] }}{% endif %}" {% if app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %} {% if brick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}>
-											{{ brick.GetTitle|dict_s }}
+											<span class="brick_icon {{ brick.GetDecorationClassNavigationMenu }}"></span>
+											{{ brick.GetTitleNavigationMenu|dict_s }}
 										</a>
 									</li>
 								{% endif %}
@@ -190,8 +195,9 @@
 			<div class="menu">
 				{% block pNavigationSideMenu %}
 					<ul class="nav">
-						<li>
+						<li class="{% if oBrick is not defined %}active{% endif %}">
 							<a href="{{ app.url_generator.generate('p_home') }}">
+								<span class="brick_icon fa fa-home fa-2x"></span>
 								{{ 'Page:Home'|dict_s }}
 							</a>
 						</li>
@@ -199,7 +205,8 @@
 							{% if brick.GetActive and brick.GetVisibleNavigationMenu and brick.GetRouteName is not null %}
 								<li class="{% if oBrick is defined and brick.id == oBrick.id %}active{% endif %}">
 									<a href="{{ app.url_generator.generate(brick.GetRouteName, {sBrickId: brick.GetId}) }}{% if app['combodo.portal.instance.routes'][brick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][brick.GetRouteName]['hash'] }}{% endif %}" {% if app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][brick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %} {% if brick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}>
-										{{ brick.GetTitle|dict_s }}
+										<span class="brick_icon {{ brick.GetDecorationClassNavigationMenu }}"></span>
+										{{ brick.GetTitleNavigationMenu|dict_s }}
 									</a>
 								</li>
 							{% endif %}
@@ -225,6 +232,7 @@
 		<div class="container-fluid" id="main-wrapper">
 			<div class="row">
 				<div class="col-xs-12 col-sm-9 col-md-10 col-sm-offset-3 col-md-offset-2">
+					
 					<section class="row" id="main-header">
 						{% block pMainHeader %}
 						{% endblock %}

+ 166 - 6
datamodels/2.x/itop-portal-base/portal/web/css/portal.css

@@ -15,6 +15,9 @@ footer{
 .user_infos .dropdown-menu a .glyphicon{
 	margin-right: 15px;
 }
+.nav > li > a > span.brick_icon{
+	margin-right: 20px;
+}
 /* Topbar */
 #topbar #navbar{
 	overflow-y: auto;
@@ -42,18 +45,24 @@ footer{
 }
 #sidebar .user_card{
 	padding: 30px 0px;
-	background-color: #F2F2F2; /* TODO : Change this */
+	background-color: #EA7D1E; /* TODO : Change this */
 	text-align: center;
+	box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.3)
 }
 #sidebar .user_card .user_photo{
 	margin-bottom: 10px;
 }
 #sidebar .user_card .user_photo img{
+	border: 2px solid #FFFFFF;
 	border-radius: 100%;
-	width: 70px;
+	width: 80px;
 }
 #sidebar .user_card .user_infos{
 	font-size: 1em;
+	color: #FFFFFF;
+}
+#sidebar .user_card .user_infos .dropdown-toggle{
+	color: #FFFFFF;
 }
 #sidebar .user_card .user_options.dropdown-menu{
 	width: 92%;
@@ -63,9 +72,48 @@ footer{
 	font-weight: 600;
 }
 #sidebar .menu{
+	padding-top: 2em;
 	max-height: 59%;
 	overflow-y: auto;
 }
+#sidebar .menu .nav > li{
+	line-height: 3.0em;
+}
+#sidebar .menu .nav > li:after,
+#sidebar .menu .nav > li:first-child:before{
+	content: "";
+    display: block;
+    position: relative;
+    /*margin-left: 6.8em;
+    width: 56%;*/
+    color: #FFFFFF;
+    border-bottom: 1px solid #7D7D7D;
+}
+#sidebar .menu .nav > li.active:after{
+	content: " ";
+    position: absolute;
+    right: 0px;
+    top: 0px;
+    border: 30px solid transparent;
+    border-right-width: 20px;
+    border-right-color: #EDECEC;
+}
+#sidebar .menu .nav > li.active > a{
+	margin-top: -1px; /* To mask border from previous li item */
+	/*margin-left: 4em;
+	padding-left: 1em;*/
+	background-color: #EA7D1E;
+	color: #FFFFFF;
+	box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3)
+}
+#sidebar .menu .nav > li > a{
+	padding-left: 3em;
+}
+#sidebar .menu .nav > li > a > .brick_icon{
+	width: 1.2em;
+	vertical-align: sub;
+	text-align: center;
+}
 #sidebar .logo{
 	position: absolute;
 	bottom: 15px;
@@ -73,6 +121,7 @@ footer{
 	text-align: center;
 }
 #sidebar .logo img{
+	width: 40%;
 	max-width: 100%;
 }
 
@@ -210,6 +259,12 @@ label{
 /*********************/
 /* BS theme override */
 /*********************/
+body{
+	background-color: #EDECEC;
+}
+a{
+	color: #D46201;
+}
 .pagination{
 	margin: 14px 0px; 
 }
@@ -224,10 +279,109 @@ label{
 	max-width: 400px;
 	padding: 15px;
 }
-.nav > li.active > a{
+
+/* Navbars */
+.navbar-default{
+	background-color: #585653;
+	border: none;
+}
+.navbar-default .nav > li > a{
+	color: #FFFFFF;
+}
+.navbar-default .nav > li > a:focus,
+.navbar-default .nav > li > a:hover{
+	background-color: #FFFFFF;
+	color: #EA7D1E;
+}
+.navbar-default .nav > li.active > a{
+	background-color: #FFFFFF;
+	color: #EA7D1E;
 	font-weight: 600;
 }
 
+/* Dropdowns */
+.dropdown-menu>li>a:hover,
+.dropdown-menu>li>a:focus {
+	text-decoration: none;
+    color: #FFFFFF;
+    background-color: #EA7D1E;
+}
+
+/* Buttons */
+/* - Default */
+.btn-default,
+.btn-default:active, .btn-default.active,
+.btn-default:hover, .btn-default:focus{
+	color: inherit;
+    background-color: #FFFFFF;
+	background-image: none;
+    border: 1px solid rgba(0, 0, 0, 0.15);
+}
+.btn-default:hover, .btn-default.active:focus{
+	background-color: #FAFAFA; /* TODO : Darken white */
+}
+.btn-default:active, .btn-default.active{
+	background-color: transparent; /* Body background */
+	box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;
+	border: none;
+	border-bottom-color: #EBEAEA;
+}
+.btn-default:active:hover, .btn-default.active:hover, 
+.btn-default:active:focus, .btn-default.active:focus,
+.btn-default:active.focus, .btn-default.active.focus {
+	color: inherit;
+    background-color: #EAEAEA; /* Darken body background */
+	border: inherit;
+}
+/* - Primary */
+.btn-primary,
+.btn-primary:active, .btn-primary.active,
+.btn-primary:hover, .btn-primary:focus{
+	color: #FFFFFF;
+    background-color: #EA7D1E;
+	background-image: none;
+    border: 1px solid rgba(0, 0, 0, 0.15);
+}
+.btn-primary:hover,
+.btn-primary.active:focus, {
+	background-color: #EA7D1E; /* TODO : Darken */
+}
+
+/* Panels */
+.panel{
+	border: none;
+	border-radius: 0px;
+	box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);;
+}
+
+/* Forms */
+.form-control{
+	border-radius: 0px;
+}
+
+/* Pagination */
+.pagination>.active>a,
+.pagination>.active>span,
+.pagination>.active>a:hover,
+.pagination>.active>span:hover,
+.pagination>.active>a:focus,
+.pagination>.active>span:focus {
+    background-color: #EA7D1E;
+    border-color: #EA7D1E;
+}
+.pagination>li>a:hover,
+.pagination>li>span:hover, 
+.pagination>li>a:focus, 
+.pagination>li>span:focus {
+    background-color: #EA7D1E;
+    border-color: #EA7D1E;
+}
+
+/* Modal */
+.modal-content{
+	border-radius: 0px;
+}
+
 /* Custom "glyphicons" */
 .glyphicon-ext-hierarchy:before {
     content: url('../img/icons/hierarchy-white-13px.png');
@@ -329,7 +483,7 @@ label{
 }
 @media (min-width: 768px) {
 	.home .tile{
-		margin-bottom: 30px;
+		margin-bottom: 40px;
 		min-height: 10em;
 	}
 	.home .tile .tile_decoration{
@@ -389,12 +543,18 @@ label{
 		margin-bottom: 20px;
 	}
 }
+#main-header-actions .btn-group .btn{
+	line-height: 2.1em;
+	font-size: 14px;
+	border-radius: 0px;
+}
 
 .dataTables_wrapper{
 	padding: 10px 10px;
 }
 #brick_content_toolbar{
-	margin: 10px 0px 6px 0px;
+	/* margin: 10px 0px 6px 0px; */
+	padding: 10px;
 }
 #brick_content_toolbar > div label{
 	font-weight: normal;
@@ -615,7 +775,7 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
 .form_linkedset_toggler > .glyphicon{
 	margin-left: 0.5em;
 	font-size: 0.85em;
-	color: #d9230f; /* TODO : SASS this to primary color */
+	color: #EA7D1E; /* TODO : SASS this to primary color */
 	transition: transform 0.2s linear;
 }
 .form_linkedset_toggler > .glyphicon.collapsed{

文件差异内容过多而无法显示
+ 3 - 0
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/css/font-awesome.min.css


二进制
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/FontAwesome.otf


二进制
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.eot


文件差异内容过多而无法显示
+ 196 - 0
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.svg


二进制
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.ttf


二进制
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.woff


二进制
datamodels/2.x/itop-portal-base/portal/web/lib/font-awesome/fonts/fontawesome-webfont.woff2


+ 10 - 2
datamodels/2.x/itop-request-mgmt-itil/datamodel.itop-request-mgmt-itil.xml

@@ -1864,10 +1864,18 @@
 				</brick>
 				<brick id="create-user-request-itil" xsi:type="Combodo\iTop\Portal\Brick\CreateBrick" _delta="define">
 					<active>true</active>
-					<rank>3</rank>
+					<rank>
+						<default>3</default>
+					</rank>
 					<width>8</width>
 					<modal>true</modal>
-					<title>Portal:CreateNewRequestItil</title>
+					<title>
+						<default>Portal:CreateNewRequestItil</default>
+					</title>
+					<description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+					<decoration_class>
+						<default>fa fa-plus fa-2x</default>
+					</decoration_class>
 					<class>UserRequest</class>
 					<!-- Class that will be created with the form -->
 					<rules>

+ 62 - 12
datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml

@@ -981,8 +981,15 @@
       </properties>
       <bricks>
         <brick id="user-profile" xsi:type="Combodo\iTop\Portal\Brick\UserProfileBrick">
-          <rank>1</rank>
-          <title>Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil</title>
+          <rank>
+			  <default>1</default>
+		  </rank>
+          <title>
+			  <default>Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil</default>
+		  </title>
+		  <decoration_class>
+			  <default>glyphicon glyphicon-user</default>
+		  </decoration_class>
           <form>
             <!-- Optionnal tag to list the fields -->
             <fields />
@@ -1011,10 +1018,31 @@
         </brick>
         <brick id="create-user-request" xsi:type="Combodo\iTop\Portal\Brick\CreateBrick">
           <active>true</active>
-          <rank>3</rank>
+		  <!-- Optionnal tag : Bricks will be order as declared in the XML by default -->
+          <rank>
+			  <default>2</default>
+			  <!-- <home>2</home> -->
+			  <!-- <navigation_menu>2</navigation_menu> -->
+		  </rank>
           <width>8</width>
           <modal>true</modal>
-          <title>Portal:CreateNewRequest</title>
+          <title>
+			  <default>Portal:CreateNewRequest</default>
+			  <!-- <home>Portal:CreateNewRequest</home> -->
+			  <!-- <navigation_menu>Portal:CreateNewRequest</navigation_menu> -->
+		  </title>
+		  <!-- Optional tag : Shows a description in the brick home tile -->
+		  <description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+		  <!-- Optional tag : Brick is visible by default -->
+		  <visible>
+			  <home>true</home>
+			  <navigation_menu>true</navigation_menu>
+		  </visible>
+		  <decoration_class>
+			  <default>fa fa-plus fa-2x</default>
+			  <!-- <home>fa fa-plus</home> -->
+			  <!-- <navigation_menu>fa fa-plus</navigation_menu> -->
+		  </decoration_class>
           <class>UserRequest</class>
           <!-- Class that will be created with the form -->
           <rules>
@@ -1023,9 +1051,17 @@
         </brick>
         <brick id="ongoing-tickets-for-portal-user" xsi:type="Combodo\iTop\Portal\Brick\ManageBrick">
           <active>true</active>
-          <rank>4</rank>
+          <rank>
+			  <default>4</default>
+		  </rank>
           <width>4</width>
-          <title>Portal:ShowOngoing</title>
+          <title>
+			  <default>Portal:ShowOngoing</default>
+		  </title>
+		  <description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+		  <decoration_class>
+			  <default>fa fa-pencil-square fa-2x</default>
+		  </decoration_class>
           <oql><![CDATA[SELECT Ticket WHERE org_id = :current_contact->org_id AND caller_id = :current_contact_id]]></oql>
           <!-- Can be either a class tag with the class name or an oql tag with the query -->
           <!-- <class>Ticket</class> -->
@@ -1065,9 +1101,17 @@
         </brick>
         <brick id="closed-tickets-for-portal-user" xsi:type="Combodo\iTop\Portal\Brick\ManageBrick">
           <active>true</active>
-          <rank>5</rank>
+          <rank>
+			  <default>5</default>
+		  </rank>
           <width>4</width>
-          <title>Portal:ShowClosed</title>
+          <title>
+			  <default>Portal:ShowClosed</default>
+		  </title>
+		  <description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+		  <decoration_class>
+			  <default>fa fa-pencil-square fa-2x</default>
+		  </decoration_class>
           <oql><![CDATA[SELECT UserRequest WHERE org_id = :current_contact->org_id AND caller_id = :current_contact_id AND status = 'closed']]></oql>
           <!-- Can be either a class tag with the class name or an oql tag with the query -->
           <!-- <class>Ticket</class> -->
@@ -1084,11 +1128,17 @@
         </brick>
         <brick id="services" xsi:type="Combodo\iTop\Portal\Brick\BrowseBrick">
           <active>true</active>
-          <rank>6</rank>
           <width>4</width>
-          <visible_home>true</visible_home>
-          <visible_navigation_menu>true</visible_navigation_menu>
-          <title>Brick:Portal:Services:Title</title>
+          <rank>
+			  <default>6</default>
+		  </rank>
+          <title>
+			  <default>Brick:Portal:Services:Title</default>
+		  </title>
+		  <description>Un deux trois nous irons au bois, quatre cinq six cueillir des cerises. Sept huit neuf, das un panier neuf.</description>
+		  <decoration_class>
+			  <default>fa fa-map fa-2x</default>
+		  </decoration_class>
           <!-- <fields  /> Optional tag to add attributes to the table by their code, can be specified for each level -->
           <levels>
             <level id="1">

部分文件因为文件数量过多而无法显示