diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 857dfbaff3..89e306d576 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1787,6 +1787,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], + 'audit.filter' => [ + 'type' => 'array', + 'description' => 'Array to use in filter "field" => ["label" =>"my_label", "values" => "array_of_values","oql"=>"my_oql"]', + 'default' => [], + 'value' => [], + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], 'application.secret' => [ 'type' => 'string', 'description' => 'Application secret, uses this value for encrypting the cookies used in the remember me functionality and for creating signed URIs when using ESI (Edge Side Includes).', diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index e3d5dcd585..125b9f03a7 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -778,6 +778,8 @@ 'UI:Audit:Dashboard:ObjectsInError' => 'Objects in errors', 'UI:Audit:Dashboard:ObjectsValidated' => 'Objects validated', 'UI:Audit:AuditCategory:Subtitle' => '%1$s errors ouf of %2$s - %3$s%% of the object are valid', + 'UI:Audit:Interactive:Selection:SubTitleParams' => 'Please select the following parameters: ', + 'UI:Audit:Interactive:FilterList' => 'With following parameters: ', 'UI:RunQuery:Title' => ITOP_APPLICATION_SHORT.' - OQL Query Evaluation', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index a1a1238412..54e7edeb68 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -470,7 +470,9 @@ 'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Tentative de modification du champ en lecture seule: %1$s', 'UI:AttemptingToSetASlaveAttribute_Name' => 'Le champ %1$s (%2$s) ne peut pas être modifié car il est géré par une synchronisation avec une source de données. Valeur ignorée.', 'UI:Audit:AuditCategory:Subtitle' => '%1$s en erreur sur %2$s - %3$s%% des objets sont valides', - 'UI:Audit:AuditErrors' => 'Audit Errors~~', + 'UI:Audit:Interactive:Selection:SubTitleParams' => 'Veuillez sélectionner les paramètres suivant : ', + 'UI:Audit:Interactive:FilterList' => 'Avec les paramètres suivants : ', + 'UI:Audit:AuditErrors' => 'Audit Errors~~', 'UI:Audit:Dashboard:ObjectsAudited' => 'Objets audités', 'UI:Audit:Dashboard:ObjectsInError' => 'Objets en erreur', 'UI:Audit:Dashboard:ObjectsValidated' => 'Objets valides', diff --git a/pages/audit.php b/pages/audit.php index ed952ebbff..2c89601c6d 100644 --- a/pages/audit.php +++ b/pages/audit.php @@ -9,14 +9,23 @@ use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletContainer; use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletFactory; use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory; +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\Input\Select\SelectOptionUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory; 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\Text\Text; use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn; use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow; +use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory; use Combodo\iTop\Application\WebPage\CSVPage; use Combodo\iTop\Application\WebPage\ErrorPage; use Combodo\iTop\Application\WebPage\iTopWebPage; +use Combodo\iTop\Core\MetaModel\FriendlyNameType; +use Combodo\iTop\Form\Field\SelectObjectField; /** * Adds the context parameters to the audit rule query @@ -97,11 +106,12 @@ function FilterByContext(DBSearch &$oFilter, ApplicationContext $oAppContext) * @throws \CoreException * @throws \OQLException */ -function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) +function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext, $aParams = []) { $oRule = MetaModel::GetObject('AuditRule', $iRuleId); $sOql = $oRule->Get('query'); - $oRuleFilter = DBObjectSearch::FromOQL($sOql); + $oRuleFilter = DBObjectSearch::FromOQL($sOql, $aParams); + $oRuleFilter->UpdateContextFromUser(); FilterByContext($oRuleFilter, $oAppContext); // Not needed since this filter is a subset of the definition filter, but may speedup things @@ -122,6 +132,7 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) } /** @var \DBObjectSearch $oFilter */ $oFilter = $oDefinitionFilter->DeepClone(); + if (count($aValidIds) > 0) { $aInDefSet = array(); @@ -143,6 +154,324 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) return $oFilter; } +function MakeSelectField($oPage, string $sLabel, string $sFieldName, string $sOql, string $sCurrentValue) +{ + $oSearch = DBObjectSearch::FromOQL($sOql); + $oAllowedValues = new DBObjectSet($oSearch); + $oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData()); + $iMaxComboLength = MetaModel::GetConfig()->Get('max_combo_length'); + + $bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength); + $sWrapperCssClass = $bIsAutocomplete ? 'ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper'; + $sHTMLValue = "
"; + + // We just need to compare the number of entries with MaxComboLength, so no need to get the real count. + if (!$bIsAutocomplete) { + // Discrete list of values, use a SELECT or RADIO buttons depending on the config + $sHelpText = ''; + $aOptions = []; + $aOptions['value'] = ""; + $aOptions['label'] = Dict::S('UI:SelectOne'); + + $oAllowedValues->Rewind(); + $sClassAllowed = $oAllowedValues->GetClass(); + $bAddingValue = false; + + $aFieldsToLoad = []; + + $aComplementAttributeSpec = MetaModel::GetNameSpec($oAllowedValues->GetClass(), FriendlyNameType::COMPLEMENTARY); + $sFormatAdditionalField = $aComplementAttributeSpec[0]; + $aAdditionalField = $aComplementAttributeSpec[1]; + + if (count($aAdditionalField) > 0) { + $bAddingValue = true; + $aFieldsToLoad[$sClassAllowed] = $aAdditionalField; + } + $sObjectImageAttCode = MetaModel::GetImageAttributeCode($sClassAllowed); + if (!empty($sObjectImageAttCode)) { + $aFieldsToLoad[$sClassAllowed][] = $sObjectImageAttCode; + } + $aFieldsToLoad[$sClassAllowed][] = 'friendlyname'; + $oAllowedValues->OptimizeColumnLoad($aFieldsToLoad); + + $oSelect = SelectUIBlockFactory::MakeForSelect($sFieldName, $sFieldName); + $oSelect->AddCSSClass('ibo-input-field-wrapper'); + + while ($oChoiceItem = $oAllowedValues->Fetch()) { + + $sOptionName = utils::HtmlEntityDecode($oChoiceItem->GetName()); + + if ($bAddingValue) { + $aArguments = []; + foreach ($aAdditionalField as $sAdditionalField) { + array_push($aArguments, $oAllowedValues->Get($sAdditionalField)); + } + $sOptionName.='
'.utils::HtmlEntities(vsprintf($sFormatAdditionalField, $aArguments)).''; ; + } + if (!empty($sObjectImageAttCode)) { + // Try to retrieve image for contact + /** @var \ormDocument $oImage */ + $oImage = $oAllowedValues->Get($sObjectImageAttCode); + if (!$oImage->IsEmpty()) { + $sPicturepictureUrl = $oImage->GetDisplayURL($sClassAllowed, $oChoiceItem->GetKey(), $sObjectImageAttCode); + $sOptionName.=' '; + } else { + $sInitials = utils::FormatInitialsForMedallion(utils::ToAcronym($oChoiceItem->Get('friendlyname'))); + $sOptionName.=' '.$sInitials.''; + } + } + $oOption = SelectOptionUIBlockFactory::MakeForSelectOption($oChoiceItem->GetKey(), $sOptionName, ($sCurrentValue == $oChoiceItem->GetKey())); + $oSelect->AddOption($oOption); + } + $sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_DECORATED; + + $sJsonOptions = str_replace("'", "\'", str_replace('\\', '\\\\', json_encode($aOptions))); + $oPage->add_ready_script( + <<GetFilter(); + $oSearch->AddCondition('id', $sCurrentValue); + $oSet = new DBObjectSet($oSearch); + $sClass = $oSet->GetClass(); + if ($oSet->Count() == 0) + { + $sCurrentValue = null; + } + + if (is_null($sCurrentValue) || ($sCurrentValue == 0)) // Null values are displayed as '' + { + $sDisplayValue = ''; + } else { + $sDisplayValue = MetaModel::GetObject($sClass, $sCurrentValue)->GetName(); + } + $iMinChars = MetaModel::GetConfig()->Get('min_autocomplete_chars'); //@@@ $this->oAttDef->GetMinAutoCompleteChars(); + + // the input for the auto-complete + $sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_AUTOCOMPLETE; + $sHTMLValue .= ""; + + // another hidden input to store & pass the object's Id + $sHTMLValue .= "\n"; + + // Scripts to start the autocomplete and bind some events to it + $oPage->add_ready_script( + <<= 0 && cache[this.previous] != null && cache[this.previous].length < 120) { + //we have already all the possibility in cache + var data = []; + $.each(cache[this.previous], function (key, value) { + if (value.label.toLowerCase().latinise().replace(/[\u0300-\u036f]/g, "").indexOf(term) >= 0) { + data.push(value); + } + }); + cache[term] = data; + response(data); + } else { + $.post({ + url: GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', + dataType: "json", + data: { + q: request.term, + operation: 'ac_extkey', + sTargetClass: '$sClass', + sFilter: '$sOql', + bSearchMode: true, + sOutputFormat: 'json', + json: function () { + return ''; + } + }, + success: function (data) { + cache[term] = data; + response(data); + } + }); + + } + }, + autoFocus: true, + minLength: $iMinChars, + focus: function (event, ui) { + return false; + }, + select: function (event, ui) { + $('#$sFieldName').val(ui.item.value); + let labelValue = $('
').html(ui.item.label).text(); + $('#label_$sFieldName').val(labelValue); + $('#label_$sFieldName').data('selected_value', labelValue); + $('#label_$sFieldName').attr('title',labelValue); + return false; + }, + open: function (event, ui) { + // dialog tries to move above every .ui-front with _moveToTop(), we want to be above our parent dialog + var dialog = $(this).closest('.ui-dialog'); + if (dialog.length > 0) { + $('.ui-autocomplete.ui-front').css('z-index', parseInt(dialog.css("z-index"))+1); + } + // UpdateDropdownPosition = function (oControlElem, oDropdownElem) { + // First fix width to ensure it's not too long + const fControlWidth = $(this).outerWidth(); + $('.ui-autocomplete.selectize-dropdown:visible').css('width', fControlWidth); + + // Then, fix height / position to ensure it's within the viewport + const fWindowHeight = window.innerHeight; + + const fControlTopY = $(this).offset().top; + const fControlHeight = $(this).outerHeight(); + + const fDropdownTopY = $('.ui-autocomplete.selectize-dropdown:visible').offset().top; + // This one is "let" as it might be updated if necessary + let fDropdownHeight = $('.ui-autocomplete.selectize-dropdown:visible').outerHeight(); + const fDropdownBottomY = fDropdownTopY + fDropdownHeight; + + if (fDropdownBottomY > fWindowHeight) { + // Set dropdown max-height to 1/3 of the screen, this way we are sure the dropdown will fit in either the top / bottom half of the screen + $('.ui-autocomplete.selectize-dropdown:visible').css('max-height', '30vh'); + fDropdownHeight = $('.ui-autocomplete.selectize-dropdown:visible').outerHeight(); + + // Position dropdown above input if not enough space on the bottom part of the screen + if ((fDropdownTopY / fWindowHeight) > 0.6) { + $('.ui-autocomplete.selectize-dropdown:visible').css('top', fDropdownTopY - fDropdownHeight - fControlHeight); + } + } + // this.ManageScroll = function () { + if ($('#label_$sFieldName').scrollParent()[0].tagName != 'HTML') { + $('#label_$sFieldName').scrollParent().on(['scroll.$sFieldName', 'resize.$sFieldName'].join(" "), function () { + setTimeout(function () { + me.ManageScrollInElement(); + }, 50); + }); + if ($('#label_$sFieldName').scrollParent().scrollParent()[0].tagName != 'HTML') { + $('#label_$sFieldName').scrollParent().scrollParent().on(['scroll.$sFieldName', 'resize.$sFieldName'].join(" "), function () { + setTimeout(function () { + me.ManageScrollInElement(); + }, 50); + }); + } + } + }, + close: function (event, ui) { + if ($('#label_$sFieldName').scrollParent()[0].tagName != 'HTML') { + $('#label_$sFieldName').scrollParent().off('scroll.$sFieldName'); + $('#label_$sFieldName').scrollParent().off('resize.$sFieldName'); + if ($('#label_$sFieldName').scrollParent().scrollParent()[0].tagName != 'HTML') { + $('#label_$sFieldName').scrollParent().scrollParent().off('scroll.$sFieldName'); + $('#label_$sFieldName').scrollParent().scrollParent().off('resize.$sFieldName'); + } + } + } + }) + .autocomplete("instance")._renderItem = function (ul, item) { + $(ul).addClass('selectize-dropdown'); + let term = this.term.replace("/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi", "\\$1"); + let val = ''; + if (item.initials != undefined) { + if (item.picture_url != undefined) { + val = ''+item.initials+''; + } else { + val = ''+item.initials+''; + } + } + val = val+'
'; + if (item.obsolescence_flag == '1') { + val = val+' '; + } + let labelValue = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term+")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + val = val+labelValue; + if (item.additional_field != undefined) { + val = val+'
'+item.additional_field+''; + } + val = val+'
'; + return $("
  • ") + .append("
    "+val+"
    ") + .appendTo(ul); + }; + + $('#label_$sFieldName').on('focus', function () { + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).on('blur', function () { + hasFocus = 0; + if ($('#label_$sFieldName').val().length == 0) { + $('#$sFieldName').val(''); + $('#label_$sFieldName').val(''); + $('#label_$sFieldName').data('selected_value', ''); + } else { + $('#label_$sFieldName').val($('#label_$sFieldName').data('selected_value')); + } + }).on('click', + function () { + hasFocus++; + $('#label_$sFieldName').autocomplete("search"); + }).on('keyup',function () { + if ($('#label_$sFieldName').val().length == 0) { + if (!$('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').hasClass('ibo-is-hidden')) { + $('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').addClass('ibo-is-hidden'); + } + } else { + if ($('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').hasClass('ibo-is-hidden')) { + $('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').removeClass('ibo-is-hidden'); + } + } + }); + + var iPaddingRight = $('#$sFieldName').parent().find('.ibo-input-select--action-buttons')[0].childElementCount * 20+15; + $('#$sFieldName').parent().find('.ibo-input-select').css('padding-right', iPaddingRight); + + + + if ($('#ac_dlg_{$sFieldName}').length == 0) + { + $('body').append('
    '); + } +JS + ); + $sHTMLValue .= "
    "; + $sHTMLValue .= ""; + } + /* if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) { + $sHTMLValue .= "iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\" data-tooltip-content='".Dict::S('UI:Button:SearchInHierarchy')."'>"; + $oPage->add_ready_script( + <<
    '); + } +JS + ); + } + if ($oAllowedValues->CountExceeds($iMaxComboLength)) { + $sHTMLValue .= " iId}\" onClick=\"oACWidget_{$this->iId}.Search();\" data-tooltip-content='".Dict::S('UI:Button:Search')."'>"; + }*/ + $sHTMLValue .= "
  • "; + $sHTMLValue .= "
    "; + + return new Html( $sHTMLValue); +} try { require_once('../approot.inc.php'); @@ -152,6 +481,11 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $bSelectionAuditRulesByDefault = utils::GetConfig()->Get('audit.enable_selection_landing_page'); $operation = utils::ReadParam('operation', $bSelectionAuditRulesByDefault ? 'selection' : 'audit'); + $aAuditFilter = utils::GetConfig()->Get('audit.filter'); + if ($aAuditFilter == null){ + $aAuditFilter = []; + } + $oAppContext = new ApplicationContext(); require_once(APPROOT.'/application/loginwebpage.class.inc.php'); @@ -167,19 +501,32 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) // Therefore we don't use the standard "search_oql" operation of UI.php to display the CSV $iCategory = utils::ReadParam('category', ''); $iRuleIndex = utils::ReadParam('rule', 0); - - $oAuditCategory = MetaModel::GetObject('AuditCategory', $iCategory); - $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); + + $aFilterParams = []; + $sAddingParams = ''; + if($aAuditFilter !=[] ){ + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + $sCurrentValue = utils::ReadParam($sFieldName, ''); + $sAddingParams .= "&$sFieldName=$sCurrentValue"; + $aFilterParams[$sFieldName] = $sCurrentValue; + } + } + + $oAuditCategory = MetaModel::GetObject('AuditCategory', $iCategory); + $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'),$aFilterParams); $oDefinitionFilter->UpdateContextFromUser(); FilterByContext($oDefinitionFilter, $oAppContext); $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); - $oFilter = GetRuleResultFilter($iRuleIndex, $oDefinitionFilter, $oAppContext); + $oFilter = GetRuleResultFilter($iRuleIndex, $oDefinitionFilter, $oAppContext, $aFilterParams); $oErrorObjectSet = new CMDBObjectSet($oFilter); $oAuditRule = MetaModel::GetObject('AuditRule', $iRuleIndex); $sFileName = utils::ReadParam('filename', null, true, 'string'); $bAdvanced = utils::ReadParam('advanced', false); $sAdvanced = $bAdvanced ? '&advanced=1' : ''; - + + + + if ($sFileName != null) { $oP = new CSVPage("iTop - Export"); @@ -224,7 +571,7 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $oP->p(""); // Adjust the size of the Textarea containing the CSV to fit almost all the remaining space $oP->add_ready_script(" $('#1>textarea').height(400);"); // adjust the size of the block - $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey(); + $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey().$sAddingParams; $oDownloadButton = ButtonUIBlockFactory::MakeForAlternativePrimaryAction('fas fa-chevron-left', Dict::S('UI:Audit:InteractiveAudit:Back'), "./audit.php?".$oAppContext->GetForLink()); $oP->add_ready_script("$('a[href*=\"webservices/export.php?expression=\"]').attr('href', '".$sExportUrl."&filename=audit.csv".$sAdvanced."');"); @@ -237,12 +584,34 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $iCategory = utils::ReadParam('category', ''); $iRuleIndex = utils::ReadParam('rule', 0); + $aFilterParams = []; + $sAddingParams = ''; + $oPanel = PanelUIBlockFactory::MakeNeutral('',Dict::S('UI:Audit:Interactive:FilterList')); + if($aAuditFilter !=[] ){ + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + $sCurrentValue = utils::ReadParam($sFieldName, ''); + $sAddingParams .= "&$sFieldName=$sCurrentValue"; + $aFilterParams[$sFieldName] = $sCurrentValue; + $sName = ''; + if (array_key_exists('oql', $aFieldParam) && utils::IsNotNullOrEmptyString($aFieldParam['oql'])) { + $oSearch = new DBObjectSet(DBObjectSearch::FromOQL($aFieldParam['oql'])); + $sClass = $oSearch->GetClass(); + $oObject = MetaModel::GetObject($sClass, $sCurrentValue); + $sName = $oObject->GetName(); + } else {//this is a list of values + $sName = $aFieldParam['values'][$sCurrentValue]; + } + $sFilterText .= '
  • '.$aFieldParam['label'].': '.$sName.'
  • '; + } + $oPanel->AddSubBlock(new Html($sFilterText.'')); + } + $oAuditCategory = MetaModel::GetObject('AuditCategory', $iCategory); - $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); + $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'), $aFilterParams); $oDefinitionFilter->UpdateContextFromUser(); FilterByContext($oDefinitionFilter, $oAppContext); $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); - $oFilter = GetRuleResultFilter($iRuleIndex, $oDefinitionFilter, $oAppContext); + $oFilter = GetRuleResultFilter($iRuleIndex, $oDefinitionFilter, $oAppContext,$aFilterParams); $oErrorObjectSet = new CMDBObjectSet($oFilter); $oAuditRule = MetaModel::GetObject('AuditRule', $iRuleIndex); $sDescription = get_class($oAuditRule).": ".$oAuditRule->GetName(); @@ -251,12 +620,16 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $oBackButton = ButtonUIBlockFactory::MakeIconLink('fas fa-chevron-left', Dict::S('UI:Audit:Interactive:Button:Back'), "./audit.php?".$oAppContext->GetForLink()); $oP->AddUiBlock($oBackButton); $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage($sTitle.$oAuditRule->Get('description'))); + if($aAuditFilter !=[] ){ + $oP->AddUiBlock($oPanel); + $oP->AddUiBlock(new Html('
    ')); + } $sBlockId = 'audit_errors'; $oP->p("
    "); $oBlock = DisplayBlock::FromObjectSet($oErrorObjectSet, 'list', array('show_obsolete_data' => true)); $oBlock->Display($oP, 1); $oP->p("
    "); - $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey(); + $sExportUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey().$sAddingParams; $oP->add_ready_script("$('a[href*=\"pages/UI.php?operation=search\"]').attr('href', '".$sExportUrl."')"); break; @@ -267,7 +640,39 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $oP->AddUiBlock($oButton); } $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage(Dict::S('UI:Audit:Interactive:Selection:Title'))); - $oP->AddUiBlock(new Text(Dict::S('UI:Audit:Interactive:Selection:SubTitle'))); + + if($aAuditFilter !=[] ){ + $oPanel = PanelUIBlockFactory::MakeNeutral('',Dict::S('UI:Audit:Interactive:Selection:SubTitleParams')); + $oP->AddUiBlock($oPanel); + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + + $oBlock = FieldUIBlockFactory::MakeStandard($aFieldParam['label']); + $oBlock->SetAttLabel($aFieldParam['label']) + ->AddDataAttribute("input-id", $sFieldName) + ->AddDataAttribute("input-type", 'input-type'); + $oValue = UIContentBlockUIBlockFactory::MakeStandard("", ["form-field-content", "ibo-input-field-wrapper"]); + + $sCurrentValue = utils::ReadParam($sFieldName, ''); + + if (array_key_exists('oql', $aFieldParam) && utils::IsNotNullOrEmptyString($aFieldParam['oql'])) { + $oValue->AddSubBlock(MakeSelectField( $oP, $aFieldParam['label'], $sFieldName, $aFieldParam['oql'], $sCurrentValue)); + } else {//this is a list of values + $aListValues = $aFieldParam['values']; + $oSelect = SelectUIBlockFactory::MakeForSelect($sFieldName, $sFieldName); + $oSelect->AddCSSClass('ibo-input-field-wrapper'); + + foreach($aListValues as $sKey => $sValue) { + $oSelect->AddOption(SelectOptionUIBlockFactory::MakeForSelectOption($sKey, $sValue, ($sCurrentValue == $sKey))); + } + + $oValue->AddSubBlock($oSelect); + } + $oBlock->AddSubBlock($oValue); + $oPanel->AddSubBlock($oBlock); + } + + } + $oP->AddUiBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:Audit:Interactive:Selection:SubTitle'),2)); // Header block to select all audit categories $oCategoriesSet = new DBObjectSet(new DBObjectSearch('AuditCategory')); @@ -278,11 +683,23 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $oDashboardColumn = new DashboardColumn(false, true); $oDashboardRow->AddDashboardColumn($oDashboardColumn); $oAllCategoriesDashlet = new DashletContainer(); + + $sDomainUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=audit"; + if($aAuditFilter !=[] ) { + //modif URLLink In order to send params + $sGetParams = ''; + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + $sGetParams .= $sFieldName."=$('[name=$sFieldName]').val();"; + $sDomainUrl .= "&".$sFieldName."='+$sFieldName+'"; + } + $sDomainUrl = 'javascript:'.$sGetParams.' window.location = \''.$sDomainUrl.'\''; + } + $oAllCategoriesDashlet ->AddCSSClasses(['ibo-dashlet--is-inline', 'ibo-dashlet-badge']) ->AddSubBlock(DashletFactory::MakeForDashletBadge( utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-audit.svg', - utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=audit", + $sDomainUrl, $iCategoryCount, Dict::S('UI:Audit:Interactive:Selection:BadgeAll') )); @@ -311,14 +728,25 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $sIconUrl = $oImage->GetDisplayURL(get_class($oAuditDomain), $oAuditDomain->GetKey(), 'icon'); } $iCategoryCount = $oAuditDomain->Get('categories_list')->Count(); + + if($aAuditFilter !=[] ) { + //modif URLLink In order to send params + $sGetParams = ''; + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + $sGetParams .= $sFieldName."=$('[name=$sFieldName]').val();"; + $sDomainUrl .= "&".$sFieldName."='+$sFieldName+'"; + } + $sDomainUrl = 'javascript:'.$sGetParams.' window.location = \''.$sDomainUrl.'\''; + } + $oDomainBlock = DashletFactory::MakeForDashletBadge($sIconUrl, $sDomainUrl, $iCategoryCount, $oAuditDomain->Get('name')); $oDomainDashlet = new DashletContainer(); $oDomainDashlet->AddSubBlock($oDomainBlock)->AddCSSClasses(['ibo-dashlet--is-inline', 'ibo-dashlet-badge']); $oDashboardRow->GetSubBlocks()[$iDomainCnt % 3]->AddUIBlock($oDomainDashlet); // ; $iDomainCnt++; } + $oP->AddUiBlock($oDashboardRow); - $oP->AddUiBlock($oDashboardRow); break; case 'audit': @@ -355,6 +783,33 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $oBackButton = ButtonUIBlockFactory::MakeLinkNeutral("./audit.php?".$oAppContext->GetForLink(), Dict::S('UI:Audit:Interactive:Button:Back'), 'fas fa-chevron-left'); $oP->AddUiBlock($oBackButton); $oP->AddUiBlock(TitleUIBlockFactory::MakeForPage($sTitle)); + + + $aFilterParams = []; + $sAddingParams = ''; + if($aAuditFilter !=[] ){ + $oPanel = PanelUIBlockFactory::MakeNeutral('',Dict::S('UI:Audit:Interactive:FilterList')); + $oP->AddUiBlock($oPanel); + + foreach ($aAuditFilter as $sFieldName => $aFieldParam) { + $sCurrentValue = utils::ReadParam($sFieldName, ''); + $sAddingParams .= "&$sFieldName=$sCurrentValue"; + $aFilterParams[$sFieldName] = $sCurrentValue; + $sName = ''; + if (array_key_exists('oql', $aFieldParam) && utils::IsNotNullOrEmptyString($aFieldParam['oql'])) { + $oSearch = new DBObjectSet(DBObjectSearch::FromOQL($aFieldParam['oql'])); + $sClass = $oSearch->GetClass(); + $oObject = MetaModel::GetObject($sClass, $sCurrentValue); + $sName = $oObject->GetName(); + } else {//this is a list of values + $sName = $aFieldParam['values'][$sCurrentValue]; + } + $sFilterText .= '
  • '.$aFieldParam['label'].': '.$sName.'
  • '; + } + $oPanel->AddSubBlock(new Html($sFilterText.'')); + } + $oP->AddUiBlock(new Html('
    ')); + $oP->AddUiBlock(new Text($sSubTitle)); $oTotalBlock = DashletFactory::MakeForDashletBadge(utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-audit.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsAudited')); @@ -400,12 +855,12 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) // Add a button in the above toolbar $sAuditCategoryClass = get_class($oAuditCategory); if (UserRights::IsActionAllowed($sAuditCategoryClass, UR_ACTION_READ)) { - $oToolbar->AddSubBlock(ButtonUIBlockFactory::MakeIconLink('fas fa-wrench fa-lg', Dict::S('UI:Audit:ViewRules'), ApplicationContext::MakeObjectUrl($sAuditCategoryClass, $oAuditCategory->GetKey()).'&#ObjectProperties=tab_ClassAuditCategoryAttributerules_list'),); + $oToolbar->AddSubBlock(ButtonUIBlockFactory::MakeIconLink('fas fa-wrench fa-lg', Dict::S('UI:Audit:ViewRules'), ApplicationContext::MakeObjectUrl($sAuditCategoryClass, $oAuditCategory->GetKey()).$sAddingParams.'&#ObjectProperties=tab_ClassAuditCategoryAttributerules_list'),); } $aResults = array(); try { $iCount = 0; - $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); + $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'),$aFilterParams); $oDefinitionFilter->UpdateContextFromUser(); FilterByContext($oDefinitionFilter, $oAppContext); @@ -419,24 +874,28 @@ function GetRuleResultFilter($iRuleId, $oDefinitionFilter, $oAppContext) $iCount = $oDefinitionSet->Count(); $oRulesFilter = new DBObjectSearch('AuditRule'); $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '='); + foreach ($aFilterParams as $sFieldName => $sCurrentValue) { + $oRulesFilter->AddInternalParam($sFieldName, $sCurrentValue); + } + $oRulesSet = new DBObjectSet($oRulesFilter); while ($oAuditRule = $oRulesSet->fetch()) { $aRow = array(); $aRow['description'] = $oAuditRule->GetName(); if ($iCount == 0) { // nothing to check, really ! - $aRow['nb_errors'] = "GetKey()."&rule=".$oAuditRule->GetKey()."\">0"; + $aRow['nb_errors'] = "GetKey()."&rule=".$oAuditRule->GetKey().$sAddingParams."\">0"; $aRow['percent_ok'] = '100.00'; $aRow['class'] = $oAuditCategory->GetReportColor($iCount, 0); } else { try { - $oFilter = GetRuleResultFilter($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext); - $aErrors = $oFilter->SelectAttributeToArray('id'); + $oFilter = GetRuleResultFilter($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext, $aFilterParams); + $aErrors = $oFilter->SelectAttributeToArray('id'); $iErrorsCount = count($aErrors); foreach ($aErrors as $aErrorRow) { $aObjectsWithErrors[$aErrorRow['id']] = true; } - $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">"; + $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey().$sAddingParams."&".$oAppContext->GetForLink()."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey().$sAddingParams."&".$oAppContext->GetForLink()."\">"; $aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount)); $aRow['class'] = $oAuditCategory->GetReportColor($iCount, $iErrorsCount); }