Customer portal : Fixed some bugs and rectified some default configuration parameters

- Form, ExternalKey autocomplete & regular search
- Portal power user being able to see all its silo tickets
- Worked on the UI

SVN:trunk[4118]
This commit is contained in:
Guillaume Lajarige
2016-05-23 15:31:02 +00:00
parent 7761404755
commit bc6f73b9ec
20 changed files with 216 additions and 117 deletions

View File

@@ -395,7 +395,7 @@ class ObjectController extends AbstractController
// But it would not be a security issue as it only presets values in the form.
$sActionRulesToken = $oRequest->get('ar_token');
$aActionRules = ($sActionRulesToken !== null) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : array();
// Preparing object
if ($sObjectId === null)
{
@@ -606,6 +606,14 @@ class ObjectController extends AbstractController
else
{
$oHostObject = MetaModel::NewObject($sHostObjectClass);
// Retrieving action rules
//
// Note : The action rules must be a base64-encoded JSON object, this is just so users are tempted to changes values.
// But it would not be a security issue as it only presets values in the form.
$sActionRulesToken = $oRequest->get('ar_token');
$aActionRules = ($sActionRulesToken !== null) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : array();
// Preparing object
$oApp['context_manipulator']->PrepareObject($aActionRules, $oHostObject);
}
// Building search query
@@ -617,7 +625,7 @@ class ObjectController extends AbstractController
// - Adding query condition
$oSearch->AddConditionExpression(new BinaryExpression(new FieldExpression('friendlyname', $oSearch->GetClassAlias()), 'LIKE', new VariableExpression('ac_query')));
// - Intersecting with scope constraints
$oSearch->Intersect($oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ));
$oSearch = $oSearch->Intersect($oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ));
// Retrieving results
// - Preparing object set
@@ -628,7 +636,7 @@ class ObjectController extends AbstractController
// - Retrieving objects
while ($oItem = $oSet->Fetch())
{
$aData['results']['items'][] = array('id' => $oItem->GetKey(), 'name' => $oItem->GetName());
$aData['results']['items'][] = array('id' => $oItem->GetKey(), 'name' => html_entity_decode($oItem->GetName(), ENT_QUOTES, 'UTF-8'));
$aData['results']['count'] ++;
}
@@ -661,7 +669,8 @@ class ObjectController extends AbstractController
'sMode' => 'search_regular',
'sTargetAttCode' => $sTargetAttCode,
'sHostObjectClass' => $sHostObjectClass,
'sHostObjectId' => $sHostObjectId
'sHostObjectId' => $sHostObjectId,
'sActionRulesToken' => $oRequest->get('ar_token')
);
// Checking security layers
@@ -678,6 +687,13 @@ class ObjectController extends AbstractController
else
{
$oHostObject = MetaModel::NewObject($sHostObjectClass);
// Retrieving action rules
//
// Note : The action rules must be a base64-encoded JSON object, this is just so users are tempted to changes values.
// But it would not be a security issue as it only presets values in the form.
$aActionRules = ($aData['sActionRulesToken'] !== null) ? ContextManipulatorHelper::DecodeRulesToken($aData['sActionRulesToken']) : array();
// Preparing object
$oApp['context_manipulator']->PrepareObject($aActionRules, $oHostObject);
}
// Retrieving request parameters
@@ -780,7 +796,7 @@ class ObjectController extends AbstractController
}
// - Intersecting with scope constraints
$oSearch->Intersect($oScopeSearch);
$oSearch = $oSearch->Intersect($oScopeSearch);
// Retrieving results
// - Preparing object set
@@ -999,7 +1015,7 @@ class ObjectController extends AbstractController
// $aInternalParams['re_query'] = '%' . $sQuery . '%';
// }
// - Intersecting with scope constraints
$oSearch->Intersect($oScopeSearch);
$oSearch = $oSearch->Intersect($oScopeSearch);
// Retrieving results
// - Preparing object set

View File

@@ -135,7 +135,7 @@ abstract class PortalBrick extends AbstractBrick
*/
public function GetRankHome()
{
return $this->bRankHome;
return $this->fRankHome;
}
/**
@@ -145,7 +145,7 @@ abstract class PortalBrick extends AbstractBrick
*/
public function GetRankNavigationMenu()
{
return $this->bRankNavigationMenu;
return $this->fRankNavigationMenu;
}
/**

View File

@@ -487,7 +487,8 @@ class ObjectFormManager extends FormManager
$sSearchEndpoint = $this->oApp['url_generator']->generate('p_object_search_generic', array(
'sTargetAttCode' => $oAttDef->GetCode(),
'sHostObjectClass' => get_class($this->oObject),
'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey()
'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey(),
'ar_token' => $this->GetActionRulesToken(),
));
$oField->SetSearchEndpoint($sSearchEndpoint);
}

View File

@@ -619,11 +619,20 @@ class ApplicationHelper
}
}
// - Sorting bricks by rank
usort($aPortalConf['bricks'], function($a, $b)
$aPortalConf['bricks_ordering'] = array();
// - Home
$aPortalConf['bricks_ordering']['home'] = $aPortalConf['bricks'];
usort($aPortalConf['bricks_ordering']['home'], function($a, $b)
{
return $a->GetRank() > $b->GetRank();
return $a->GetRankHome() > $b->GetRankHome();
});
// - Navigation menu
$aPortalConf['bricks_ordering']['navigation_menu'] = $aPortalConf['bricks'];
usort($aPortalConf['bricks_ordering']['navigation_menu'], function($a, $b)
{
return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu();
});
return $aPortalConf;
}

View File

@@ -8,14 +8,10 @@
{% block pMainHeaderActions %}
{% if aBrowseButtons|length > 1 %}
<div class="row">
<div class="col-sm-12">
<div class="btn-group btn-group-justified btn-group-sm">
{% for sBrowseButton in aBrowseButtons %}
<a href="{{ app.url_generator.generate('p_browse_brick_mode', {'sBrickId': sBrickId, 'sBrowseMode': sBrowseButton}) }}" class="btn btn-default {% if sBrowseMode == sBrowseButton %}active{% endif %}">{{ ('Brick:Portal:Browse:Mode:'~sBrowseButton|capitalize)|dict_s }}</a>
{% endfor %}
</div>
</div>
<div class="btn-group btn-group-sm btn_group_explicit">
{% for sBrowseButton in aBrowseButtons %}
<a href="{{ app.url_generator.generate('p_browse_brick_mode', {'sBrickId': sBrickId, 'sBrowseMode': sBrowseButton}) }}" class="btn btn-default {% if sBrowseMode == sBrowseButton %}active{% endif %}">{{ ('Brick:Portal:Browse:Mode:'~sBrowseButton|capitalize)|dict_s }}</a>
{% endfor %}
</div>
{% endif %}
{% endblock %}

View File

@@ -241,6 +241,15 @@
"drawCallback": function(settings){
// Tooltip has to been created here, as the render callback only returns a string, not an object.
$(this).find('[data-toggle="tooltip"]').tooltip({container: 'body', html: true, trigger: 'hover', placement: 'right'}); // container option is necessary when in a table
// Hiding pagination if only one page
if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2)
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide();
}
else
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
}
},
{% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %}
"data": oRawDatas,

View File

@@ -12,13 +12,15 @@
{% endblock %}
{% block pMainHeader %}
<div class="col-sm-6 col-md-8" id="main-header-title">
<h2>{% block pMainHeaderTitle %}{% endblock %}</h2>
</div>
<div class="col-sm-6 col-md-4" id="main-header-actions">
{% block pMainHeaderActions %}
{% endblock %}
</div>
<div class="col-xs-12">
<div id="main-header-title">
<h2>{% block pMainHeaderTitle %}{% endblock %}</h2>
</div>
<div id="main-header-actions">
{% block pMainHeaderActions %}
{% endblock %}
</div>
</div>
{% endblock %}
{% block pMainContent %}

View File

@@ -7,17 +7,13 @@
{% endblock %}
{% block pMainHeaderActions %}
<div class="row">
<div class="col-sm-12">
{% if aGroupingTabsValues|length > 1 %}
<div class="btn-group btn-group-justified btn-group-sm">
{% for aGroupingTab in aGroupingTabsValues %}
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sGroupingTab': aGroupingTab.value}) }}" class="btn btn-default {% if sGroupingTab is defined and sGroupingTab == aGroupingTab.value %}active{% endif %}">{{ aGroupingTab.label|raw }}</a>
{% endfor %}
</div>
{% endif %}
</div>
{% if aGroupingTabsValues|length > 1 %}
<div class="btn-group btn-group-sm btn_group_explicit">
{% for aGroupingTab in aGroupingTabsValues %}
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sGroupingTab': aGroupingTab.value}) }}" class="btn btn-default {% if sGroupingTab is defined and sGroupingTab == aGroupingTab.value %}active{% endif %}">{{ aGroupingTab.label|raw }}</a>
{% endfor %}
</div>
{% endif %}
{% endblock %}
{% block pMainContentHolder%}
@@ -169,6 +165,17 @@
"dom": '<"row"<"col-sm-6"l><"col-sm-6"<f><"visible-xs"p>>>t<"row"<"col-sm-6"ri><"col-sm-6"p>>',
"columns": getColumnsDefinition('{{ sAreaId }}'),
"order": [[0, "desc"]],
"drawCallback": function(settings){
// Hiding pagination if only one page
if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2)
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide();
}
else
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
}
},
{% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %}
"data": rawData['{{ sAreaId }}'],
{% else %}

View File

@@ -135,10 +135,21 @@
$(oRow).find('td:first-child input').prop('checked', true);
}
},
"drawCallback": function(settings){
// Hiding pagination if only one page
if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2)
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide();
}
else
{
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
}
},
"processing": true,
"serverSide": true,
"ajax": {
"url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId})|raw }}",
"url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}",
"data": function(d){
d.aObjectIdsToIgnore = {{ aSource.aObjectIdsToIgnore|json_encode()|raw }};
d.iPageNumber = Math.floor(d.start/d.length) + 1;
@@ -165,7 +176,7 @@
var iItemId = aData[i].id;
if(!(iItemId in oSelectedItems))
{
oSelectedItems[iItemId] = aData[i].name;
oSelectedItems[iItemId] = $('<textarea />').html(aData[i].name).text();
}
}
});

View File

@@ -8,7 +8,7 @@
{% block pFormButtons %}
{% if tIsModal is defined and tIsModal == true %}
<div class="form_btn_regular">
<input class="btn btn-default form_btn_cancel" type="button" value="{{ 'Portal:Button:Close'|dict_s }}" data-dismiss="modal">
<input class="btn btn-primary form_btn_cancel" type="button" value="{{ 'Portal:Button:Close'|dict_s }}" data-dismiss="modal">
</div>
{% endif %}
{% endblock %}

View File

@@ -6,12 +6,12 @@
<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 %}
class="tile vertical-center" id="brick-{{ brick.GetId }}" data-brick-id="{{ brick.GetId }}">
class="tile{# vertical-center#}" id="brick-{{ brick.GetId }}" data-brick-id="{{ brick.GetId }}">
<div class="tile_decoration">
<span class="{{ brick.GetDecorationClassHome }}"></span>
<span class="icon {{ brick.GetDecorationClassHome }}"></span>
</div>
<div clss="tile_body">
<div class="tile_body">
<div class="tile_title">{{ brick.GetTitleHome|dict_s }}</div>
{% if brick.HasDescription %}
<div class="tile_description">{{ brick.GetDescription|dict_s }}</div>

View File

@@ -79,7 +79,7 @@
</div>
</form>
{% else %}
pas le droit
{{ 'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator'|dict_s }}
{% endif %}
</div>
</div>

View File

@@ -25,7 +25,7 @@
<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 tiles_wrapper">
{% for brick in app['combodo.portal.instance.conf'].bricks %}
{% for brick in app['combodo.portal.instance.conf'].bricks_ordering.home %}
{% if brick.GetVisibleHome %}
{% include '' ~ brick.GetTileTemplatePath with {brick: brick} %}
{% endif %}

View File

@@ -124,7 +124,7 @@
{{ 'Page:Home'|dict_s }}
</a>
</li>
{% for brick in app['combodo.portal.instance.conf'].bricks %}
{% for brick in app['combodo.portal.instance.conf'].bricks_ordering.navigation_menu %}
{% 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 %}>
@@ -201,7 +201,7 @@
{{ 'Page:Home'|dict_s }}
</a>
</li>
{% for brick in app['combodo.portal.instance.conf'].bricks %}
{% for brick in app['combodo.portal.instance.conf'].bricks_ordering.navigation_menu %}
{% 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 %}>

View File

@@ -1,6 +1,13 @@
/*******************/
/* Global settings */
/*******************/
@font-face {
font-family: 'Combodo';
src: url('../fonts/fontawesome-webfont.woff') format('woff'), url('../fonts/fontawesome-webfont.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@media (max-width: 768px){
body{
padding-top: 60px;
@@ -47,7 +54,7 @@ footer{
padding: 30px 0px;
background-color: #EA7D1E; /* TODO : Change this */
text-align: center;
box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.3)
box-shadow: -3px 2px 3px rgba(0, 0, 0, 0.4);
}
#sidebar .user_card .user_photo{
margin-bottom: 10px;
@@ -72,15 +79,13 @@ 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{
#sidebar .menu .nav > li:after{
content: "";
display: block;
position: relative;
@@ -89,6 +94,9 @@ footer{
color: #FFFFFF;
border-bottom: 1px solid #7D7D7D;
}
#sidebar .menu .nav > li.active{
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.8) inset;
}
#sidebar .menu .nav > li.active:after{
content: " ";
position: absolute;
@@ -102,9 +110,6 @@ footer{
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;
@@ -125,6 +130,13 @@ footer{
max-width: 100%;
}
/* Main content */
@media (min-width: 768px) {
#main-wrapper{
margin-top: 20px;
}
}
/* Overlays*/
.global_overlay{
z-index: 9999;
@@ -167,31 +179,6 @@ footer{
/******************/
/* Global classes */
/******************/
/*@media (min-width: 768px) {
.row-eq-height-sm {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
}
@media (min-width: 992px) {
.row-eq-height-md {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
}
@media (min-width: 1200px) {
.row-eq-height-lg {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
}*/
.vertical-center {
/* Make it a flex container */
display: -webkit-box;
@@ -293,9 +280,9 @@ a{
background-color: #FFFFFF;
color: #EA7D1E;
}
.navbar-default .nav > li.active > a{
background-color: #FFFFFF;
color: #EA7D1E;
.navbar-default .nav > li.active{
background-color: #292827; /* TODO Darken #585653 */
color: #FFFFFF;
font-weight: 600;
}
@@ -343,15 +330,37 @@ a{
border: 1px solid rgba(0, 0, 0, 0.15);
}
.btn-primary:hover,
.btn-primary.active:focus, {
background-color: #EA7D1E; /* TODO : Darken */
.btn-primary:active:hover, .btn-primary.active:hover,
.btn-primary:active:focus, .btn-primary.active:focus,
.btn-primary:active.focus, .btn-primary.active.focus{
background-color: #DA751C; /* TODO : Darken #EA7D1E */
}
/* Button groups */
.btn-group.btn_group_explicit{
padding: 7px;
background-color: #292827;
border: 1px solid #EBEAEA;
border-radius: 30px;
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.4) inset;
}
.btn-group.btn_group_explicit .btn{
color: #FFFFFF;
background-color: transparent;
border: none;
}
.btn-group.btn_group_explicit .btn.active{
color: #6B6965;
background-color: #EDECEC;
border-radius: 37px !important;
box-shadow: -1px 1px 2px rgba(0, 0, 0, 0.4);
}
/* Panels */
.panel{
border: none;
border-radius: 0px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
/* Forms */
@@ -458,11 +467,12 @@ a{
min-height: 4em;
background-color: #FFFFFF;
background-image: none;
border: 1px solid #8A8A8A;
border-radius: 0px;
border: none;
border-radius: 0px;
text-align: center;
text-decoration: none;
white-space: normal;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
}
.home .tile .tile_decoration{
position: absolute;
@@ -483,38 +493,41 @@ a{
}
@media (min-width: 768px) {
.home .tile{
display: block;
margin-bottom: 40px;
min-height: 10em;
text-align: left;
}
.home .tile .tile_decoration{
position: absolute;
top: -30px;
left: 0px;
width: 100%;
position: relative;
top: initial;
left: initial;
width: 150px;
text-align: center;
}
.home .tile .tile_decoration > img{
width: 55px;
max-height: 55px;
}
.home .tile .tile_body{
text-align: left
}
.home .tile .tile_title{
font-size: 1.0em;
}
.home .tile .tile_description{
display: block;
margin: 15px 20px 0px 20px;
margin-top: 15px;
text-align: justify;
}
}
@media (min-width: 992px) {
.home .tile{
min-height: 15em;
padding-right: 50px;
}
.home .tile .tile_decoration{
top: -35px;
}
.home .tile .tile_decoration > img{
width: 85px;
max-height: 85px;
.home .tile .tile_decoration > span.icon{
font-size: 5em;
}
.home .tile .tile_title{
font-size: 1.4em;
@@ -525,29 +538,36 @@ a{
/* Modules settings */
/********************/
#main-header-title{
#main-header{
text-align: center;
}
#main-header-title{
margin-bottom: 15px;
}
#main-header-actions{
margin-bottom: 15px;
}
#main-header-actions .btn-group .btn{
padding: 0em 1.5em;
line-height: 2.8em;
font-size: 14px;
}
@media (min-width: 768px) {
#main-header:after{
clear: both;
}
#main-header-title{
float: left;
margin-bottom: 0px;
min-height: 6em;
text-align: left;
}
}
#main-header-actions > .row{
margin-top: 20px;
}
@media(max-width: 768px){
#main-header-actions{
margin-bottom: 20px;
float: right;
margin-bottom: 0px;
}
}
#main-header-actions .btn-group .btn{
line-height: 2.1em;
font-size: 14px;
border-radius: 0px;
}
.dataTables_wrapper{
padding: 10px 10px;

View File

@@ -1106,7 +1106,7 @@
<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>
<oql><![CDATA[SELECT Ticket]]></oql>
<!-- Can be either a class tag with the class name or an oql tag with the query -->
<!-- <class>Ticket</class> -->
<fields>
@@ -1146,7 +1146,7 @@
<brick id="closed-tickets-for-portal-user" xsi:type="Combodo\iTop\Portal\Brick\ManageBrick">
<active>true</active>
<rank>
<menu>50</menu>
<navigation_menu>50</navigation_menu>
</rank>
<visible>
<home>false</home>
@@ -1318,6 +1318,31 @@
<mode id="edit"/>
</modes>
</form>
<form id="service-view">
<class>Service</class>
<fields></fields>
<twig>
<div class="row">
<div class="col-sm-6">
<div class="form_field" data-field-id="name">
</div>
<div class="form_field" data-field-id="description">
</div>
</div>
<div class="col-sm-6">
<div class="form_field" data-field-id="org_id">
</div>
<div class="form_field" data-field-id="servicefamily_id">
</div>
<div class="form_field" data-field-id="status">
</div>
</div>
</div>
</twig>
<modes>
<mode id="view" />
</modes>
</form>
</forms>
<classes>
<!-- Note : A class (or one of its ancestors) MUST be declared here to be displayed in the portal -->
@@ -1352,10 +1377,6 @@
</class>
<class id="Person">
<scopes>
<scope id="all">
<oql_view><![CDATA[SELECT Person AS P WHERE P.org_id = :current_contact->org_id OR P.id = :current_contact_id]]></oql_view>
<oql_edit><![CDATA[SELECT Person AS P WHERE P.id = :current_contact_id]]></oql_edit>
</scope>
<scope id="administrator">
<oql_view><![CDATA[SELECT Person AS P]]></oql_view>
<allowed_profiles>

View File

@@ -184,6 +184,13 @@ EOF
me.element.find('#{$this->oField->GetGlobalId()}').val(sItemId);
me.element.find('#{$sAutocompleteFieldId}').val(sItemName);
oAutocompleteSource_{$this->oField->GetId()}.index.datums[sItemId] = {id: sItemId, name: sItemName};
// Triggering field change event
me.element.closest(".field_set").trigger("field_change", {
id: me.element.find('#{$this->oField->GetGlobalId()}').attr("id"),
name: me.element.find('#{$this->oField->GetGlobalId()}').attr("name"),
value: me.element.find('#{$this->oField->GetGlobalId()}').val()
});
}
});
EOF