From 1527aaf4d65a784e01c32f8c54a4e3870a763727 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Sat, 2 Sep 2023 01:47:06 -0400 Subject: [PATCH] move some rules ui to twig (#15360) * move some rules ui to twig * lint * improve preview * remove size attr --- front/rule.php | 12 +- .../View/Extension/PhpExtension.php | 4 +- src/Rule.php | 2 +- src/RuleCollection.php | 509 +++++------------- src/RuleCriteria.php | 6 +- .../form/basic_inputs_macros.html.twig | 6 +- .../pages/admin/rules/backup_header.html.twig | 44 ++ .../collections_list.html.twig} | 11 +- .../rules/engine_preview_criteria.html.twig | 74 +++ .../rules/engine_preview_results.html.twig | 73 +++ .../admin/rules/engine_summary.html.twig | 48 ++ templates/pages/admin/rules/import.html.twig | 48 ++ .../admin/rules/import_preview.html.twig | 135 +++++ 13 files changed, 578 insertions(+), 394 deletions(-) create mode 100644 templates/pages/admin/rules/backup_header.html.twig rename templates/pages/admin/{rules_list.html.twig => rules/collections_list.html.twig} (83%) create mode 100644 templates/pages/admin/rules/engine_preview_criteria.html.twig create mode 100644 templates/pages/admin/rules/engine_preview_results.html.twig create mode 100644 templates/pages/admin/rules/engine_summary.html.twig create mode 100644 templates/pages/admin/rules/import.html.twig create mode 100644 templates/pages/admin/rules/import_preview.html.twig diff --git a/front/rule.php b/front/rule.php index 3b4d3211f73..7406e9498d5 100644 --- a/front/rule.php +++ b/front/rule.php @@ -41,16 +41,6 @@ Html::header(Rule::getTypeName(Session::getPluralNumber()), $_SERVER['PHP_SELF'], "admin", "rule", -1); -echo TemplateRenderer::getInstance()->render( - 'pages/admin/rules_list.html.twig', - [ - 'rules_group' => [ - [ - 'type' => __('Rule type'), - 'entries' => RuleCollection::getRules(), - ], - ] - ] -); +RuleCollection::showCollectionsList(); Html::footer(); diff --git a/src/Application/View/Extension/PhpExtension.php b/src/Application/View/Extension/PhpExtension.php index 913a8b33de4..6877bfa316f 100644 --- a/src/Application/View/Extension/PhpExtension.php +++ b/src/Application/View/Extension/PhpExtension.php @@ -80,12 +80,12 @@ public function phpConfig(string $name) /** * Call function of static method. * - * @param string $callable + * @param string|array $callable * @param array $parameters * * @return mixed */ - public function call(string $callable, array $parameters = []) + public function call(string|array $callable, array $parameters = []) { if (is_callable($callable)) { return call_user_func_array($callable, $parameters); diff --git a/src/Rule.php b/src/Rule.php index af40922d44e..b76e08aa04b 100644 --- a/src/Rule.php +++ b/src/Rule.php @@ -2642,7 +2642,7 @@ public function displayCriteriaSelectPattern($name, $ID, $condition, $value = "" !$display && ($rc = getItemForItemtype($this->rulecriteriaclass)) ) { - echo Html::input($name, ['value' => $value, 'size' => '70']); + echo Html::input($name, ['value' => $value]); } } diff --git a/src/RuleCollection.php b/src/RuleCollection.php index 35698f3dcf1..9c218b11812 100644 --- a/src/RuleCollection.php +++ b/src/RuleCollection.php @@ -33,6 +33,7 @@ * --------------------------------------------------------------------- */ +use Glpi\Application\View\TemplateRenderer; use Glpi\DBAL\QueryExpression; use Glpi\Event; @@ -60,8 +61,10 @@ class RuleCollection extends CommonDBTM public static $rightname = 'config'; - - /// Tab orientation : horizontal or vertical + /** + * @var string Tab orientation : horizontal or vertical + * @phpstan-var 'horizontal'|'vertical' + */ public $taborientation = 'horizontal'; public static function getTable($classname = null) @@ -69,7 +72,6 @@ public static function getTable($classname = null) return parent::getTable('Rule'); } - /** * @param $entity (default 0) **/ @@ -78,19 +80,16 @@ public function setEntity($entity = 0) $this->entity = $entity; } - public function canList() { return static::canView(); } - public function isEntityAssign() { return false; } - /** * Get Collection Size : retrieve the number of rules * @@ -118,7 +117,6 @@ public function getCollectionSize( return count($iterator); } - /** * Get rules list criteria * @@ -247,7 +245,6 @@ public function getCollectionPart($options = []) } } - /** * Get Collection Datas : retrieve descriptions and rules * @@ -298,7 +295,6 @@ public function getCollectionDatas($retrieve_criteria = 0, $retrieve_action = 0, } } - public function getRuleClassName() { @@ -308,7 +304,6 @@ public function getRuleClassName() return ""; } - /** * Get a instance of the class to manipulate rule of this collection **/ @@ -322,7 +317,6 @@ public function getRuleClass() return null; } - /** * Is a confirmation needed before replay on DB ? * If needed need to send 'replay_confirm' in POST @@ -336,7 +330,6 @@ public function warningBeforeReplayRulesOnExistingDB($target) return false; } - /** * Replay Collection on DB * @@ -352,7 +345,6 @@ public function replayRulesOnExistingDB($offset = 0, $maxtime = 0, $items = [], return false; } - /** * Get title used in list of rules * @@ -363,7 +355,6 @@ public function getTitle() return __('Rules list'); } - /** * Indicates if the rule can be affected to an entity or if it's global **/ @@ -374,7 +365,6 @@ public function isRuleEntityAssigned() return $rule->isEntityAssign(); } - /** * Indicates if the rule can be affected to an entity or if it's global **/ @@ -390,7 +380,6 @@ public function isRuleRecursive() **/ public function isRuleUseConditions() { - $rule = $this->getRuleClass(); return $rule->useConditions(); } @@ -412,36 +401,22 @@ public function getDefaultRuleConditionForList() public function showEngineSummary() { - - echo ""; - echo "
"; - - //Display information about the how the rules engine process the rules - if ($this->stop_on_first_match) { - //The engine stop on the first matched rule - echo "" . __('The engine stops on the first checked rule.') . - "
"; - } else { - //The engine process all the rules - echo "" . __('The engine treats all the rules.') . "
"; - } - - if ($this->use_output_rule_process_as_next_input) { - //The engine keep the result of a rule to be processed further - echo "" . - __('The engine passes the result of a rule to the following one.') . "
"; - } - - if ($this->isRuleUseConditions()) { - //The engine keep the result of a rule to be processed further - echo "" . - __('Rules are conditionals. Each one can be used on multiple actions.'); - echo "
"; - } - - echo "
\n"; + TemplateRenderer::getInstance()->display('pages/admin/rules/engine_summary.html.twig', [ + 'collection' => $this + ]); } + final public static function showCollectionsList(): void + { + TemplateRenderer::getInstance()->display('pages/admin/rules/collections_list.html.twig', [ + 'rules_group' => [ + [ + 'type' => __('Rule type'), + 'entries' => self::getRules(), + ], + ] + ]); + } /** * Show the list of rules @@ -694,7 +669,6 @@ public function showListRules($target, $options = []) echo ""; } - /** * Show the list of rules * @@ -706,7 +680,6 @@ public function showAdditionalInformationsInForm($target) { } - /** * Modify rule's ranking and automatically reorder all rules * @@ -829,7 +802,6 @@ public function changeRuleOrder($ID, $action, $condition = 0) return false; } - /** * Update Rule Order when deleting a rule * @@ -854,7 +826,6 @@ public function deleteRuleOrder($ranking) return $result; } - /** * Move a rule in an ordered collection * @@ -948,34 +919,19 @@ public function moveRule($ID, $ref_ID, $type = self::MOVE_AFTER) return ($result ? true : false); } - /** * Print a title for backup rules * * @since 0.85 * * @return void + * @todo Not used in GLPI core. Used by glpiinventory plugin **/ public static function titleBackup() { - global $CFG_GLPI; - - $base_url = "{$CFG_GLPI["root_doc"]}/front/rule.backup.php"; - $buttons = [ - "{$base_url}?action=import" => - "" . _x('button', 'Import') . "", - "{$base_url}?action=export" => - "" . _x('button', 'Export') . "", - ]; - - echo "
"; - foreach ($buttons as $key => $val) { - echo "" . $val . ""; - } - echo "
"; + TemplateRenderer::getInstance()->display('pages/admin/rules/backup_header.html.twig'); } - /** * Export rules in a xml format * @@ -1097,7 +1053,6 @@ public static function exportRulesToXML($items = []) //exit; } - /** * Print a form to select a xml file for import rules * @@ -1107,23 +1062,9 @@ public static function exportRulesToXML($items = []) **/ public static function displayImportRulesForm() { - - echo "
"; - echo "
"; - - echo "

" . __("Import rules from a XML file") . "

"; - echo " "; - echo ""; - echo ""; - - // Close for Form - echo "
"; - Html::closeForm(); + TemplateRenderer::getInstance()->display('pages/admin/rules/import.html.twig'); } - /** * * Check if a criterion is a dropdown or not @@ -1151,13 +1092,12 @@ public static function isCriteraADropdown($available_criteria, $condition, $crit && ($type == 'dropdown')); } - /** * Print a form to inform user when conflicts appear during the import of rules from a xml file * * @since 0.85 * - * @return true if all ok + * @return boolean true if all ok **/ public static function previewImportRules() { @@ -1171,35 +1111,45 @@ public static function previewImportRules() Session::addMessageAfterRedirect(__("No file was uploaded")); return false; } - //get xml file content + // get xml file content $xml = file_get_contents($_FILES["xml_file"]["tmp_name"]); - //convert a xml string into a SimpleXml object + // convert a xml string into a SimpleXml object if (!$xmlE = simplexml_load_string($xml)) { Session::addMessageAfterRedirect(__('Unauthorized file type'), false, ERROR); } - //convert SimpleXml object into an array and store it in session + $errors = libxml_get_errors(); + // convert SimpleXml object into an array and store it in session $rules = json_decode(json_encode((array) $xmlE), true); - //check rules (check if entities, criterias and actions is always good in this glpi) + // check rules (check if entities, criterias and actions is always good in this glpi) $entity = new Entity(); $rules_refused = []; + /** @var array, Rule> $rule_subtypes Cache of rule subtype instances */ + $rule_subtypes = []; - //In case there's only one rule to import, recreate an array with key => value + // In case there's only one rule to import, recreate an array with key => value if (isset($rules['rule']['entities_id'])) { $rules['rule'] = [0 => $rules['rule']]; } foreach ($rules['rule'] as $k_rule => &$rule) { - $tmprule = new $rule['sub_type'](); - //check entities + $tmprule = $rule_subtypes[$rule['sub_type']] ?? new $rule['sub_type'](); + $rule_subtypes[$rule['sub_type']] ??= $tmprule; + $refused_rule = [ + 'uuid' => $rule['uuid'], + 'rule_name' => $rule['name'], + 'type_title' => $tmprule->getTitle(), + 'reasons' => [], + ]; + // check entities if ($tmprule->isEntityAssign()) { $rule['entities_id'] = $DB->escape(Html::entity_decode_deep($rule['entities_id'])); $entities_found = $entity->find(['completename' => $rule['entities_id']]); if (empty($entities_found)) { - $rules_refused[$k_rule]['entity'] = true; + $refused_rule['reasons'][] = ['entity' => $rule['entities_id']]; } } - //process direct attributes + // process direct attributes foreach ($rule as &$val) { if ( is_array($val) @@ -1208,10 +1158,11 @@ public static function previewImportRules() $val = ""; } } + unset($val); - //check criterias + // check criterias if (isset($rule['rulecriteria'])) { - //check and correct criterias array format + // check and correct criterias array format if (isset($rule['rulecriteria']['criteria'])) { $rule['rulecriteria'] = [$rule['rulecriteria']]; } @@ -1224,7 +1175,7 @@ public static function previewImportRules() $available_criteria = $tmprule->getCriterias(); $crit = $criteria['criteria']; - //check FK (just in case of "is", "is_not" and "under" criteria) + // check FK (just in case of "is", "is_not" and "under" criteria) if ( self::isCriteraADropdown( $available_criteria, @@ -1240,7 +1191,13 @@ public static function previewImportRules() $found = $item->find(['name' => $criteria['pattern']]); } if (empty($found)) { - $rules_refused[$k_rule]['criterias'][] = $k_crit; + $criteria = $rules['rule'][$k_rule]['rulecriteria'][$k_crit]; + $refused_rule['reasons']['criteria'][] = [ + 'id' => $k_crit, + 'name' => $tmprule->getCriteriaName($criteria["criteria"]), + 'label' => RuleCriteria::getConditionByID($criteria["condition"], $itemtype, $criteria["criteria"]), + 'pattern' => $criteria["pattern"], + ]; } else { $tmp = array_pop($found); $rules['rule'][$k_rule]['rulecriteria'][$k_crit]['pattern'] = $tmp['id']; @@ -1249,9 +1206,9 @@ public static function previewImportRules() } } - //check actions + // check actions if (isset($rule['ruleaction'])) { - //check and correct actions array format + // check and correct actions array format if (isset($rule['ruleaction']['field'])) { $rule['ruleaction'] = [$rule['ruleaction']]; } @@ -1265,9 +1222,9 @@ public static function previewImportRules() $act = $action['field']; if ( - ($action['action_type'] == "assign") + ($action['action_type'] === "assign") && (isset($available_actions[$act]['type']) - && ($available_actions[$act]['type'] == 'dropdown')) + && ($available_actions[$act]['type'] === 'dropdown')) ) { //pass root entity and empty array (N/A value) if ( @@ -1286,7 +1243,13 @@ public static function previewImportRules() $found = $item->find(['name' => $action['value']]); } if (empty($found)) { - $rules_refused[$k_rule]['actions'][] = $k_action; + $action = $rule['ruleaction'][$k_action]; + $refused_rule['reasons']['actions'][] = [ + 'id' => $k_action, + 'name' => $tmprule->getActionName($action["field"]), + 'label' => RuleAction::getActionByID($action["action_type"]), + 'value' => $action["value"] ?? '', + ]; } else { $tmp = array_pop($found); $rules['rule'][$k_rule]['ruleaction'][$k_action]['value'] = $tmp['id']; @@ -1294,153 +1257,48 @@ public static function previewImportRules() } } } - } - - //save rules for ongoing processing - $_SESSION['glpi_import_rules'] = $rules; - $_SESSION['glpi_import_rules_refused'] = $rules_refused; - - //if no conflict detected, we can directly process the import - if (!count($rules_refused)) { - Html::redirect("rule.backup.php?action=process_import"); - } - //print report - echo ""; - echo "
"; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - $odd = true; - foreach ($rules_refused as $k_rule => $refused) { - $odd = !$odd; - if ($odd) { - $class = " class='tab_bg_1' "; - } else { - $class = " class='tab_bg_2' "; + if (count($refused_rule['reasons'])) { + $rules_refused[$k_rule] = $refused_rule; } + } + unset($rule); - $sub_type = $rules['rule'][$k_rule]['sub_type']; - $item = new $sub_type(); - - echo ""; - echo ""; - echo ""; - echo ""; + $rules_refused_for_session[$k] = $r; } - //display buttons - $class = ($odd ? " class='tab_bg_1' " : " class='tab_bg_2' "); - echo ""; + $_SESSION['glpi_import_rules_refused'] = $rules_refused_for_session; - // Close for Form - echo "
" . __('Rules refused') . "
" . _n('Type', 'Type', 1) . "" . __('Name') . "" . __('Reason of rejection') . "
" . $item->getTitle() . "" . $rules['rule'][$k_rule]['name'] . ""; - - echo ""; - //show entity select - if (!isset($refused['criterias']) && !isset($refused['actions'])) { - if (isset($refused['entity'])) { - echo ""; - echo ""; - echo ""; - echo ""; - } + // save rules for ongoing processing + $_SESSION['glpi_import_rules'] = $rules; + $rules_refused_for_session = []; + foreach ($rules_refused as $k => $rule) { + $r = []; + if (isset($rule['reasons']['entity'])) { + $r['entity'] = true; } - - //show criterias refused for this rule - if (isset($refused['criterias'])) { - echo ""; - echo ""; - echo ""; - echo ""; + if (isset($rule['reasons']['criteria'])) { + $r['criterias'] = array_map(static function ($c) { + return $c['id']; + }, $rule['reasons']['criteria']); } - - //show actions refused for this rule - if (isset($refused['actions'])) { - echo ""; - echo ""; - echo ""; - echo ""; + if (isset($rule['reasons']['actions'])) { + $r['actions'] = array_map(static function ($c) { + return $c['id']; + }, $rule['reasons']['actions']); } - echo "
"; - printf( - __('%1$s (%2$s)'), - __('Entity not found'), - $rules['rule'][$k_rule]['entities_id'] - ); - echo ""; - echo __('Select the desired entity') . " "; - Dropdown::show( - 'Entity', - ['comments' => false, - 'name' => "new_entities[" . - $rules['rule'][$k_rule]['uuid'] . "]" - ] - ); - echo "
" . __('Criteria refused') . ""; - - echo ""; - echo ""; - echo "\n"; - echo "\n"; - echo "\n"; - echo "\n"; - foreach ($refused['criterias'] as $k_criteria) { - $criteria = $rules['rule'][$k_rule]['rulecriteria'][$k_criteria]; - - //fix empty empty array values - if (empty($criteria['value'])) { - $criteria['value'] = null; - } - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - } - echo "
" . _n('Criterion', 'Criteria', 1) . "" . __('Condition') . "" . __('Reason') . "
" . $item->getCriteriaName($criteria["criteria"]) . "" . RuleCriteria::getConditionByID( - $criteria["condition"], - get_class($item), - $criteria["criteria"] - ) . "" . $criteria["pattern"] . "
\n"; - echo "
" . __('Actions refused') . ""; - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo "\n"; - foreach ($refused['actions'] as $k_action) { - $action = $rules['rule'][$k_rule]['ruleaction'][$k_action]; - //fix empty empty array values - if (empty($action['value'])) { - $action['value'] = null; - } - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - } - echo "
" . _n('Field', 'Fields', Session::getPluralNumber()) . "" . __('Action type') . "" . __('Value') . "
" . $item->getActionName($action["field"]) . "" . RuleAction::getActionByID($action["action_type"]) . "" . $action["value"] . "
\n"; - echo "
\n"; - echo "
"; - echo ""; - echo "
"; - Html::closeForm(); + // if no conflict detected, we can directly process the import + if (!count($rules_refused)) { + Html::redirect("rule.backup.php?action=process_import"); + } + + TemplateRenderer::getInstance()->display('pages/admin/rules/import_preview.html.twig', [ + 'refused_rules' => $rules_refused + ]); return true; } - /** * import rules in glpi after user validation * @@ -1579,7 +1437,6 @@ public static function processImportRules() return true; } - /** * Process all the rules collection * @@ -1646,7 +1503,6 @@ public function processAllRules($input = [], $output = [], $params = [], $option return $output; } - /** * Show form displaying results for rule collection preview * @@ -1657,36 +1513,10 @@ public function processAllRules($input = [], $output = [], $params = [], $option public function showRulesEnginePreviewCriteriasForm($target, array $values, $condition = 0) { $input = $this->prepareInputDataForTestProcess($condition); + $rule = $this->getRuleClass(); + $criterias = $rule->getAllCriteria(); if (count($input)) { - $rule = $this->getRuleClass(); - $criterias = $rule->getAllCriteria(); - echo ""; - echo "\n
"; - echo ""; - echo "\n"; - - //Brower all criterias - foreach ($input as $criteria) { - echo ""; - - if (isset($criterias[$criteria])) { - $criteria_constants = $criterias[$criteria]; - echo ""; - } else { - echo ""; - } - - echo "\n"; - } - // Add all used criteria on rule as `Rule::showSpecificCriteriasForPreview()` // adapt its output depending on used criteria $rule->criterias = []; @@ -1695,24 +1525,22 @@ public function showRulesEnginePreviewCriteriasForm($target, array $values, $con 'fields' => ['criteria' => $criteria], ]; } - $rule->showSpecificCriteriasForPreview($_POST); - - echo "\n"; - echo "
" . _n('Criterion', 'Criteria', Session::getPluralNumber()) . "
" . $criteria_constants["name"] . "" . $criteria . ""; - $rule->displayCriteriaSelectPattern( - $criteria, - $criteria, - Rule::PATTERN_IS, - isset($values[$criteria]) ? $values[$criteria] : '' - ); - echo "
"; - echo ""; - echo ""; - echo ""; - echo "
"; - Html::closeForm(); - } else { - echo '
' . __('No element to be tested') . '
'; } + TemplateRenderer::getInstance()->display('pages/admin/rules/engine_preview_criteria.html.twig', [ + 'rule' => $rule, + 'input' => $input, + 'values' => $values, + 'criteria' => $criterias, + 'rule_classname' => $this->getRuleClassName(), + 'condition' => $condition, + 'params' => [ + 'target' => $target, + ] + ]); return $input; } - /** * Test all the rules collection * @@ -1764,7 +1592,6 @@ public function testAllRules($input = [], $output = [], $params = [], $condition return $output; } - /** * Prepare input data for the rules collection * @@ -1778,7 +1605,6 @@ public function prepareInputDataForProcess($input, $params) return $input; } - /** * Prepare input data for the rules collection, also using plugins values * @@ -1820,7 +1646,6 @@ public function prepareInputDataForProcessWithPlugins($input, $params) return $input; } - /** * Prepare input datas for the rules collection * @@ -1862,7 +1687,6 @@ public function prepareInputDataForTestProcess($condition = 0) return $input; } - /** * Show form displaying results for rule engine preview * @@ -1872,55 +1696,60 @@ public function prepareInputDataForTestProcess($condition = 0) **/ public function showRulesEnginePreviewResultsForm($target, array $input, $condition = 0) { - + global $DB; $output = []; if ($this->use_output_rule_process_as_next_input) { $output = $input; } - $output = $this->testAllRules($input, $output, $input, $condition); - $rule = $this->getRuleClass(); + $results = []; - echo "
"; - - if (isset($output["result"])) { - echo ""; - echo "\n"; - - foreach ($output["result"] as $ID => $rule_result) { - echo ""; - $rule->getFromDB($ID); - echo ""; - echo "\n"; - } - - echo "
" . __('Result details') . "
" . $rule->fields["name"] . ""; - - switch ($rule_result["result"]) { - case 0: - case 1: - echo Dropdown::getYesNo($rule_result["result"]); - break; - - case 2: - echo __('Inactive'); - break; - } - - echo "
"; + foreach ($output["result"] as $ID => $rule_result) { + $it = $DB->request([ + 'SELECT' => ['name'], + 'FROM' => $rule::getTable(), + 'WHERE' => ['id' => $ID], + 'LIMIT' => 1 + ]); + $name = $it->current()['name'] ?? ''; + $result = match ($rule_result['result']) { + 0, 1 => Dropdown::getYesNo($rule_result['result']), + 2 => __('Inactive'), + default => '' + }; + $results[] = [ + 'name' => $name, + 'result' => $result + ]; } $output = $this->cleanTestOutputCriterias($output); unset($output["result"]); $global_result = (count($output) ? 1 : 0); + $actions = $rule->getAllActions(); + $output = $this->preProcessPreviewResults($output); + $result_actions = []; - echo "
"; - $this->showTestResults($rule, $output, $global_result); - echo "
"; - } + foreach ($output as $criteria => $value) { + if (!isset($actions[$criteria])) { + continue; + } + $action_type = $actions[$criteria]['action_type'] ?? ''; + $result_actions[] = [ + 'name' => $actions[$criteria]['name'] ?? '', + 'value' => $rule->getActionValue($criteria, $action_type, $value), + ]; + } + TemplateRenderer::getInstance()->display('pages/admin/rules/engine_preview_results.html.twig', [ + 'results' => $results, + 'global_result_raw' => $global_result, + 'global_result' => Dropdown::getYesNo($global_result), + 'result_actions' => $result_actions, + ]); + } /** * Unset criterias from the rule's ouput results (begins by _) @@ -1944,41 +1773,6 @@ public function cleanTestOutputCriterias(array $output) return $output; } - - /** - * Show test results for a rule - * - * @param $rule rule object - * @param $output array output data array - * @param $global_result boolean global result - * - * @return void - **/ - public function showTestResults($rule, array $output, $global_result) - { - - $actions = $rule->getAllActions(); - echo ""; - echo "\n"; - echo ""; - echo ""; - echo ""; - - $output = $this->preProcessPreviewResults($output); - - foreach ($output as $criteria => $value) { - if (isset($actions[$criteria])) { - echo ""; - echo ""; - $action_type = (isset($actions[$criteria]['action_type']) ? $actions[$criteria]['action_type'] : ''); - echo "\n"; - } - } - echo "
" . __('Rule results') . "
" . _n('Validation', 'Validations', 1) . "" . Dropdown::getYesNo($global_result) . "
" . $actions[$criteria]["name"] . "" . $rule->getActionValue($criteria, $action_type, $value); - echo "
\n"; - } - - /** * @param $output **/ @@ -2011,7 +1805,6 @@ public function preProcessPreviewResults($output) return $this->cleanTestOutputCriterias($output); } - /** * Print a title if needed which will be displayed above list of rules * @@ -2021,7 +1814,6 @@ public function title() { } - /** * Get rulecollection classname by giving his itemtype * @@ -2056,19 +1848,16 @@ public static function getClassByType($itemtype, $check_dictionnary_type = false return null; } - public function showInheritedTab() { return false; } - public function showChildrensTab() { return false; } - /** * Get all the fields needed to perform the rule **/ @@ -2102,7 +1891,6 @@ public function getFieldsToLookFor() return $params; } - /** * For tabs management : force isNewItem * @@ -2113,7 +1901,6 @@ public function isNewItem() return false; } - /** * @see CommonGLPI::defineTabs() **/ @@ -2136,9 +1923,6 @@ public function getMainTabLabel() return _n('Rule', 'Rules', Session::getPluralNumber()); } - /** - * @see CommonGLPI::getTabNameForItem() - **/ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { @@ -2174,7 +1958,6 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) return ''; } - public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { @@ -2205,7 +1988,6 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ return false; } - /** * Get list of Rules * @@ -2260,7 +2042,6 @@ public static function getRules(): array return $rules; } - /** * Get list of dictionnaries * diff --git a/src/RuleCriteria.php b/src/RuleCriteria.php index 570c72901d4..21ffe728ef6 100644 --- a/src/RuleCriteria.php +++ b/src/RuleCriteria.php @@ -596,9 +596,9 @@ public static function match(RuleCriteria &$criterion, $field, &$criterias_resul /** * Return the condition label by giving his ID * - * @param $ID condition's ID - * @param $itemtype itemtype - * @param $criterion (default '') + * @param int $ID condition's ID + * @param string $itemtype itemtype + * @param string $criterion (default '') * * @return condition's label **/ diff --git a/templates/components/form/basic_inputs_macros.html.twig b/templates/components/form/basic_inputs_macros.html.twig index 8669fd61ffa..d7a5339ca6e 100644 --- a/templates/components/form/basic_inputs_macros.html.twig +++ b/templates/components/form/basic_inputs_macros.html.twig @@ -33,7 +33,7 @@ {% macro input(name, value, options = {}) %} {% set options = { - 'id': '%id%', + 'id': null, 'type': 'text', 'input_addclass': '', 'additional_attributes': {}, @@ -55,7 +55,7 @@ {% endif %} {% set input %} - . + # + # --------------------------------------------------------------------- + #} + +{% macro btn(url, icon, label) %} + + + {{ label }} + +{% endmacro %} + +
+ {{ _self.btn(config('root_doc') ~ '/front/rule.backup.php?action=import', 'ti ti-upload', _x('button', 'Import')) }} + {{ _self.btn(config('root_doc') ~ '/front/rule.backup.php?action=export', 'ti ti-download', _x('button', 'Export')) }} +
diff --git a/templates/pages/admin/rules_list.html.twig b/templates/pages/admin/rules/collections_list.html.twig similarity index 83% rename from templates/pages/admin/rules_list.html.twig rename to templates/pages/admin/rules/collections_list.html.twig index 61ec575e3ec..a6b563543c9 100644 --- a/templates/pages/admin/rules_list.html.twig +++ b/templates/pages/admin/rules/collections_list.html.twig @@ -31,16 +31,7 @@ # --------------------------------------------------------------------- #} - +{{ include('pages/admin/rules/backup_header.html.twig') }}
diff --git a/templates/pages/admin/rules/engine_preview_criteria.html.twig b/templates/pages/admin/rules/engine_preview_criteria.html.twig new file mode 100644 index 00000000000..27130a42ccb --- /dev/null +++ b/templates/pages/admin/rules/engine_preview_criteria.html.twig @@ -0,0 +1,74 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2023 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +{% import 'components/form/fields_macros.html.twig' as fields %} +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %} + +{% if input|length %} +
+
+

{{ _n('Criterion', 'Criteria', get_plural_number()) }}

+
+
+ +
+
+
+
+ {% for criterion in input %} + {% set field_content %} + {% do call([rule, 'displayCriteriaSelectPattern'], [criterion, criterion, constant('Rule::PATTERN_IS'), values[criterion]|default('')]) %} + {% endset %} + {{ fields.htmlField( + criterion, + field_content, + criteria[criterion] is defined ? criteria[criterion]['name'] : criterion, + ) }} + {% endfor %} + {% do call([rule, 'showSpecificCriteriasForPreview'], [_request]) %} +
+
+
+
+ {{ inputs.submit('test_all_rules', _x('button', 'Test'), 1) }} + {{ inputs.hidden('sub_type', rule_classname) }} + {{ inputs.hidden('condition', condition) }} + {{ inputs.hidden('_glpi_csrf_token', csrf_token()) }} + +
+
+{% else %} +
+ {{ __('No element to be tested') }} +
+{% endif %} diff --git a/templates/pages/admin/rules/engine_preview_results.html.twig b/templates/pages/admin/rules/engine_preview_results.html.twig new file mode 100644 index 00000000000..041f712a384 --- /dev/null +++ b/templates/pages/admin/rules/engine_preview_results.html.twig @@ -0,0 +1,73 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2023 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +
+
+

{{ __('Result details') }}

+
+
+ + + {% for result in results %} + + + + + {% endfor %} + +
{{ result['name'] }}{{ result['result'] }}
+ + + + + + + + {% for result_action in result_actions %} + + + + + {% endfor %} + +
+

+ {{ __('Rule results') }} +
+ + {{ _n('Validation', 'Validations', 1) }}: {{ global_result }} + +

+
{{ result_action['name'] }}{{ result_action['value'] }}
+
+
diff --git a/templates/pages/admin/rules/engine_summary.html.twig b/templates/pages/admin/rules/engine_summary.html.twig new file mode 100644 index 00000000000..2e603768949 --- /dev/null +++ b/templates/pages/admin/rules/engine_summary.html.twig @@ -0,0 +1,48 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2023 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +
+ {% if collection.stop_on_first_match %} + {{ __('The engine will stop after the first matched rule.') }} + {% else %} + {{ __('The engine will run all matching rules.') }} + {% endif %} +
+ {% if collection.use_output_rule_process_as_next_input %} + {{ __('The engine passes the result of each rule to the next matching rule.') }} +
+ {% endif %} + {% if collection.isRuleUseConditions %} + {{ __('The rules are conditional based on a type of action.') }} + {% endif %} +
diff --git a/templates/pages/admin/rules/import.html.twig b/templates/pages/admin/rules/import.html.twig new file mode 100644 index 00000000000..6bd8ab27acb --- /dev/null +++ b/templates/pages/admin/rules/import.html.twig @@ -0,0 +1,48 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2023 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %} + +
+ {{ inputs.hidden('_glpi_csrf_token', csrf_token()) }} +
+

{{ __('Import rules from an XML file') }}

+ + {{ inputs.hidden('action', 'preview_import') }} + {% set import_label %} + + {{ _x('button', 'Import') }} + {% endset %} + {{ inputs.submit('import', import_label, 1) }} +
+
diff --git a/templates/pages/admin/rules/import_preview.html.twig b/templates/pages/admin/rules/import_preview.html.twig new file mode 100644 index 00000000000..1e44fe9eed6 --- /dev/null +++ b/templates/pages/admin/rules/import_preview.html.twig @@ -0,0 +1,135 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2023 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +{% import 'components/form/fields_macros.html.twig' as fields %} +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %} + +
+ {{ inputs.hidden('action', 'process_import') }} + {{ inputs.hidden('_glpi_csrf_token', csrf_token()) }} +
+ + + + + + + + + + + + + {% for refused in refused_rules %} + + + + + + {% endfor %} + + + + + + +
{{ __('Rules refused') }}
{{ _n('Type', 'Types', 1) }}{{ __('Name') }}{{ __('Reason of rejection') }}
{{ refused['type_title'] }}{{ refused['rule_name'] }} + + + {% if refused['reasons']['criteria'] is not defined and refused['reasons']['actions'] is not defined %} + {% if refused['reasons']['entity'] is defined %} + + + + + {% endif %} + {% endif %} + {% if refused['reasons']['criteria'] is defined %} + + + + + {% endif %} + {% if refused['reasons']['actions'] is defined %} + + + + + {% endif %} + +
{{ __('%1$s (%2$s)')|format(__('Entity not found'), refused['reasons']['entity']) }} + {{ fields.dropdownField('Entity', 'new_entities[' ~ refused['uuid'] ~ ']', null, __('Select the desired entity')) }} +
{{ __('Criteria refused') }} + + + + + + + + + + {% for criterion in refused['reasons']['criteria'] %} + + + + + + {% endfor %} + +
{{ _n('Criterion', 'Criteria', 1) }}{{ __('Condition') }}{{ __('Reason') }}
{{ criterion['name'] }}{{ criterion['label'] }}{{ criterion['pattern'] }}
+
{{ __('Actions refused') }} + + + + + + + + + + {% for action in refused['reasons']['actions'] %} + + + + + + {% endfor %} + +
{{ _n('Field', 'Fields', 1) }}{{ __('Action type') }}{{ __('Value') }}
{{ action['name'] }}{{ action['label'] }}{{ action['value']|default('') }}
+
+
+ {{ inputs.submit('submit', _x('button', 'Post'), 1) }} +
+
+