diff --git a/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php index 78c43c713..8cf008288 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php @@ -23,6 +23,7 @@ use AttributeDate; use AttributeDateTime; use AttributeDefinition; use AttributeImage; +use AttributeTagSet; use BinaryExpression; use CMDBSource; use Combodo\iTop\Portal\Brick\AbstractBrick; @@ -585,6 +586,7 @@ class ManageBrickController extends BrickController if ($oAttDef->IsExternalKey()) { $sValue = $oCurrentRow->GetAsHTML($sItemAttr.'_friendlyname'); + $sSortValue = $oCurrentRow->Get($sItemAttr.'_friendlyname'); // Adding a view action on the external keys if ($oCurrentRow->Get($sItemAttr) !== $oAttDef->GetNullValue()) @@ -614,24 +616,28 @@ class ManageBrickController extends BrickController $sUrl = $oAttDef->Get('default_image'); } $sValue = ''; + $sSortValue = null; } - elseif ($oAttDef instanceof \AttributeTagSet) + elseif ($oAttDef instanceof AttributeTagSet) { /** @var \ormTagSet $oSetValues */ $oSetValues = $oCurrentRow->Get($sItemAttr); $aCodes = $oSetValues->GetTags(); /** @var \AttributeTagSet $oAttDef */ $sValue = $oAttDef->GenerateViewHtmlForValues($aCodes, '', false); + $sSortValue = implode(' ', $aCodes); } else { $sValue = $oAttDef->GetAsHTML($oCurrentRow->Get($sItemAttr)); + $sSortValue = $oCurrentRow->Get($sItemAttr); } unset($oAttDef); $aItemAttrs[$sItemAttr] = array( 'att_code' => $sItemAttr, 'value' => $sValue, + 'sort_value' => $sSortValue, 'actions' => $aActions ); } diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig index 8872e9924..80a14a764 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig @@ -39,8 +39,7 @@ {% endif %}
-
+
{% endif %} @@ -68,12 +67,12 @@ var columnsProperties = { {% for aAreaData in aGroupingAreasData %} - '{{ aAreaData.sId }}': {{ aAreaData.aColumnsDefinition|json_encode()|raw }}, + '{{ aAreaData.sId }}': {{ aAreaData.aColumnsDefinition|json_encode()|raw }}, {% endfor %} }; var rawData = { {% for aAreaData in aGroupingAreasData %} - '{{ aAreaData.sId }}': {{ aAreaData.aItems|json_encode()|raw }}, + '{{ aAreaData.sId }}': {{ aAreaData.aItems|json_encode()|raw }}, {% endfor %} }; @@ -107,43 +106,48 @@ "defaultContent": "", "type": "html", "data": "attributes." + key + ".att_code", - "render": function (att_code, type, row) { - var cellElem; - var itemActions; - var itemPrimarayAction; + "render": { + _: function (att_code, type, row) { + var cellElem; + var itemActions; + var itemPrimarayAction; - // Preparing action on the cell - // Note : For now we will use only one action, the secondary actions are therefore not implemented. Only the data structure is done. - itemActions = row.attributes[att_code].actions; + // Preparing action on the cell + // Note : For now we will use only one action, the secondary actions are therefore not implemented. Only the data structure is done. + itemActions = row.attributes[att_code].actions; - // Preparing the cell data - cellElem = (itemActions.length > 0) ? $('') : $(''); - cellElem.html(row.attributes[att_code].value); - // Building actions - if (itemActions.length > 0) { - // - Primary action - itemPrimaryAction = itemActions[0]; - switch (itemPrimaryAction.type) { - case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_VIEW') }}': - url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id); - break; - case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_EDIT') }}': - url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id); - break; - default: - url = '#'; - //console.log('Action "'+itemPrimaryAction+'" not implemented'); - break; - } - SetActionUrl(cellElem, url); - SetActionOpeningTarget(cellElem, itemPrimaryAction.opening_target); + // Preparing the cell data + cellElem = (itemActions.length > 0) ? $('') : $(''); + cellElem.html(row.attributes[att_code].value); + // Building actions + if (itemActions.length > 0) { + // - Primary action + itemPrimaryAction = itemActions[0]; + switch (itemPrimaryAction.type) { + case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_VIEW') }}': + url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id); + break; + case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_EDIT') }}': + url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id); + break; + default: + url = '#'; + //console.log('Action "'+itemPrimaryAction+'" not implemented'); + break; + } + SetActionUrl(cellElem, url); + SetActionOpeningTarget(cellElem, itemPrimaryAction.opening_target); - // - Secondary actions - // Not done for now, only the data structure is ready in case we need it later - } + // - Secondary actions + // Not done for now, only the data structure is ready in case we need it later + } - return cellElem.prop('outerHTML'); - }, + return cellElem.prop('outerHTML'); + }, + sort: function (att_code, type, row) { + return row.attributes[att_code].sort_value; + }, + }, }); } // UI extensions buttons @@ -221,115 +225,116 @@ $(document).ready(function () { {% for aAreaData in aGroupingAreasData %} - {% set sAreaId = aAreaData.sId %} + {% set sAreaId = aAreaData.sId %} - $(function () { - $('[data-toggle="tooltip"]').tooltip() - }); - - showTableLoader($('#table-{{ sAreaId }}')); - var oTable{{ sAreaId }} = $('#table-{{ sAreaId }}').DataTable({ - "language": { - "processing": "{{ 'Portal:Datatables:Language:Processing'|dict_s }}", - "search": "{{ 'Portal:Datatables:Language:Search'|dict_s }}", - "lengthMenu": "{{ 'Portal:Datatables:Language:LengthMenu'|dict_s }}", - "zeroRecords": "{{ 'Portal:Datatables:Language:ZeroRecords'|dict_s }}", - "info": "{{ 'Portal:Datatables:Language:Info'|dict_s }}", - "infoEmpty": "{{ 'Portal:Datatables:Language:InfoEmpty'|dict_s }}", - "infoFiltered": "({{ 'Portal:Datatables:Language:InfoFiltered'|dict_s }})", - "emptyTable": "{{ 'Portal:Datatables:Language:EmptyTable'|dict_s }}", - "paginate": { - "first": "{{ 'Portal:Datatables:Language:Paginate:First'|dict_s }}", - "previous": "{{ 'Portal:Datatables:Language:Paginate:Previous'|dict_s }}", - "next": "{{ 'Portal:Datatables:Language:Paginate:Next'|dict_s }}", - "last": "{{ 'Portal:Datatables:Language:Paginate:Last'|dict_s }}" + showTableLoader($('#table-{{ sAreaId }}')); + var oTable{{ sAreaId }} = $('#table-{{ sAreaId }}').DataTable({ + "language": { + "processing": "{{ 'Portal:Datatables:Language:Processing'|dict_s }}", + "search": "{{ 'Portal:Datatables:Language:Search'|dict_s }}", + "lengthMenu": "{{ 'Portal:Datatables:Language:LengthMenu'|dict_s }}", + "zeroRecords": "{{ 'Portal:Datatables:Language:ZeroRecords'|dict_s }}", + "info": "{{ 'Portal:Datatables:Language:Info'|dict_s }}", + "infoEmpty": "{{ 'Portal:Datatables:Language:InfoEmpty'|dict_s }}", + "infoFiltered": "({{ 'Portal:Datatables:Language:InfoFiltered'|dict_s }})", + "emptyTable": "{{ 'Portal:Datatables:Language:EmptyTable'|dict_s }}", + "paginate": { + "first": "{{ 'Portal:Datatables:Language:Paginate:First'|dict_s }}", + "previous": "{{ 'Portal:Datatables:Language:Paginate:Previous'|dict_s }}", + "next": "{{ 'Portal:Datatables:Language:Paginate:Next'|dict_s }}", + "last": "{{ 'Portal:Datatables:Language:Paginate:Last'|dict_s }}" + }, + "aria": { + "sortAscending": ": {{ 'Portal:Datatables:Language:Sort:Ascending'|dict_s }}", + "sortDescending": ": {{ 'Portal:Datatables:Language:Sort:Descending'|dict_s }}" + } }, - "aria": { - "sortAscending": ": {{ 'Portal:Datatables:Language:Sort:Ascending'|dict_s }}", - "sortDescending": ": {{ 'Portal:Datatables:Language:Sort:Descending'|dict_s }}" - } - }, - "lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "{{ 'Portal:Datatables:Language:DisplayLength:All'|dict_s }}"]], - "displayLength": {{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::DEFAULT_LIST_LENGTH') }}, - "dom": '<"row"<"col-sm-6"l><"col-sm-6"<"visible-xs"p>>>t<"row"<"col-sm-6"i><"col-sm-6"p>>', - "columns": getColumnsDefinition('{{ sAreaId }}'), - "order": [], - "rowCallback": function (oRow, oData) { - if (oData.highlight_class !== undefined) { - var sHighlightClass = oData.highlight_class; - var sBSHiglightClass = ''; + "lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "{{ 'Portal:Datatables:Language:DisplayLength:All'|dict_s }}"]], + "displayLength": {{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::DEFAULT_LIST_LENGTH') }}, + "dom": '<"row"<"col-sm-6"l><"col-sm-6"<"visible-xs"p>>>t<"row"<"col-sm-6"i><"col-sm-6"p>>', + "columns": getColumnsDefinition('{{ sAreaId }}'), + "order": [], + "rowCallback": function (oRow, oData) { + if (oData.highlight_class !== undefined) { + var sHighlightClass = oData.highlight_class; + var sBSHiglightClass = ''; - // Adding classic iTop class - $(oRow).addClass(sHighlightClass); - // Adding mapped BS class - if (sHighlightClass === '{{ constant('HILIGHT_CLASS_CRITICAL') }}') { - sBSHiglightClass = 'danger'; + // Adding classic iTop class + $(oRow).addClass(sHighlightClass); + // Adding mapped BS class + if (sHighlightClass === '{{ constant('HILIGHT_CLASS_CRITICAL') }}') { + sBSHiglightClass = 'danger'; + } + else if (sHighlightClass === '{{ constant('HILIGHT_CLASS_WARNING') }}') { + sBSHiglightClass = 'warning'; + } + else if (sHighlightClass === '{{ constant('HILIGHT_CLASS_OK') }}') { + sBSHiglightClass = 'success'; + } + $(oRow).addClass(sBSHiglightClass); } - else if (sHighlightClass === '{{ constant('HILIGHT_CLASS_WARNING') }}') { - sBSHiglightClass = 'warning'; + }, + "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 if (sHighlightClass === '{{ constant('HILIGHT_CLASS_OK') }}') { - sBSHiglightClass = 'success'; + else { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show(); } - $(oRow).addClass(sBSHiglightClass); - } - }, - "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 %} - "processing": true, - "serverSide": true, - {#"searchDelay": 1000, // can be used to increase time between server calls when typing search query#} - "ajax": { - "url": "{{ app.url_generator.generate('p_manage_brick_lazy', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': sAreaId})|raw }}", - "data": function (d) { - d.iPageNumber = Math.floor(d.start / d.length) + 1; - d.iListLength = d.length; - d.columns = null; - d.orders = null; + }, + {% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %} + "data": rawData['{{ sAreaId }}'], + {% else %} + "processing": true, + "serverSide": true, + {#"searchDelay": 1000, // can be used to increase time between server calls when typing search query#} + "ajax": { + "url": "{{ app.url_generator.generate('p_manage_brick_lazy', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': sAreaId})|raw }}", + "data": function (d) { + d.iPageNumber = Math.floor(d.start / d.length) + 1; + d.iListLength = d.length; + d.columns = null; + d.orders = null; - {% if sSearchValue is not null %} - // Sets default filter value - if (d.draw === 1) { - $('#table-{{ sAreaId }}_filter input').val('{{ sSearchValue }}'); - d.search.value = $('#table-{{ sAreaId }}_filter input').val(); - } - {% endif %} - if (d.search.value) { - d.sSearchValue = d.search.value; + {% if sSearchValue is not null %} + // Sets default filter value + if (d.draw === 1) { + $('#table-{{ sAreaId }}_filter input').val('{{ sSearchValue }}'); + d.search.value = $('#table-{{ sAreaId }}_filter input').val(); + } + {% endif %} + if (d.search.value) { + d.sSearchValue = d.search.value; + } } } - } - {% endif %} - }); + {% endif %} + }); - // Overrides filter input to apply throttle. Otherwise, an ajax request is send each time a key is pressed - // Also removes accents from search string - // Note : The '.off()' call is to unbind event from DataTables that where triggered before we could intercept anything - $('#table-{{ sAreaId }}_filter input').off().on('keyup', function () { - var me = this; + // Overrides filter input to apply throttle. Otherwise, an ajax request is send each time a key is pressed + // Also removes accents from search string + // Note : The '.off()' call is to unbind event from DataTables that where triggered before we could intercept anything + $('#table-{{ sAreaId }}_filter input').off().on('keyup', function () { + var me = this; - clearTimeout(oKeyTimeout); - oKeyTimeout = setTimeout(function () { - oTable{{ sAreaId }}.search(me.value.latinise()).draw(); - }, iSearchThrottle); - });// Shows a loader in the table when processing - $('#table-{{ sAreaId }}').on('processing.dt', function (event, settings, processing) { + clearTimeout(oKeyTimeout); + oKeyTimeout = setTimeout(function () { + oTable{{ sAreaId }}.search(me.value.latinise()).draw(); + }, iSearchThrottle); + });// Shows a loader in the table when processing + $('#table-{{ sAreaId }}').on('processing.dt', function (event, settings, processing) { if (processing === true) { showTableLoader($(this)); } }); {% endfor %} + // Enable tooltips + $(function () { + $('[data-toggle="tooltip"]').tooltip() + }); + // Auto collapse item actions popup $('body').click(function () { $('table .item-action-wrapper.collapse.in').collapse('hide');