diff --git a/lib/Connector/CapConnector.php b/lib/Connector/CapConnector.php index ecea475d5c..7dd8027a53 100644 --- a/lib/Connector/CapConnector.php +++ b/lib/Connector/CapConnector.php @@ -532,12 +532,18 @@ public function onScheduleCriteriaRequest(ScheduleCriteriaRequestInterface $even // Initialize Emergency Alerts schedule criteria parameters $event->addType('emergency_alerts', __('Emergency Alerts')) ->addMetric('emergency_alert_status', __('Status')) + ->addCondition([ + 'eq' => __('Equal to') + ]) ->addValues('dropdown', [ self::ACTUAL_ALERT => __('Actual Alerts'), self::TEST_ALERT => __('Test Alerts'), self::NO_ALERT => __('No Alerts') ]) ->addMetric('emergency_alert_category', __('Category')) + ->addCondition([ + 'eq' => __('Equal to') + ]) ->addValues('dropdown', [ 'Geo' => __('Geo'), 'Met' => __('Met'), diff --git a/lib/Controller/Schedule.php b/lib/Controller/Schedule.php index f59b3fe64e..e7c3eea304 100644 --- a/lib/Controller/Schedule.php +++ b/lib/Controller/Schedule.php @@ -781,6 +781,7 @@ public function addForm(Request $request, Response $response, ?string $from, ?in // Retrieve the criteria data from the event $criteria = $event->getCriteria(); + $criteriaDefaultCondition = $event->getCriteriaDefaultCondition(); $addFormData = [ 'dayParts' => $this->dayPartFactory->allWithSystem(), @@ -791,7 +792,8 @@ public function addForm(Request $request, Response $response, ?string $from, ?in 'isScheduleNow' => false, 'relativeTime' => 0, 'setDisplaysFromFilter' => true, - 'scheduleCriteria' => $criteria + 'scheduleCriteria' => $criteria, + 'criteriaDefaultCondition' => $criteriaDefaultCondition ]; $formNowData = []; @@ -1339,6 +1341,7 @@ function editForm(Request $request, Response $response, $id) // Retrieve the data from the event $criteria = $event->getCriteria(); + $criteriaDefaultCondition = $event->getCriteriaDefaultCondition(); if (!$this->isEventEditable($schedule)) { throw new AccessDeniedException(); @@ -1403,7 +1406,8 @@ function editForm(Request $request, Response $response, $id) 'eventStart' => $eventStart, 'eventEnd' => $eventEnd, 'eventTypes' => \Xibo\Entity\Schedule::getEventTypesForm(), - 'scheduleCriteria' => $criteria + 'scheduleCriteria' => $criteria, + 'criteriaDefaultCondition' => $criteriaDefaultCondition ]); return $this->render($request, $response); diff --git a/lib/Event/ScheduleCriteriaRequestEvent.php b/lib/Event/ScheduleCriteriaRequestEvent.php index f36694a101..ea287be3ec 100644 --- a/lib/Event/ScheduleCriteriaRequestEvent.php +++ b/lib/Event/ScheduleCriteriaRequestEvent.php @@ -27,7 +27,7 @@ /** * This class represents a schedule criteria request event. It is responsible for initializing, * managing, and retrieving schedule criteria. The class provides methods for adding types, - * metrics, and their associated values. + * metrics, and their associated conditions and values. */ class ScheduleCriteriaRequestEvent extends Event implements ScheduleCriteriaRequestInterface { @@ -35,6 +35,23 @@ class ScheduleCriteriaRequestEvent extends Event implements ScheduleCriteriaRequ private $criteria = []; private $currentTypeIndex = null; private $currentMetric = null; + private array $defaultConditions = []; + + public function __construct() + { + // Initialize default conditions in key-value format + $this->defaultConditions = [ + 'set' => __('Is set'), + 'lt' => __('Less than'), + 'lte' => __('Less than or equal to'), + 'eq' => __('Equal to'), + 'neq' => __('Not equal to'), + 'gte' => __('Greater than or equal to'), + 'gt' => __('Greater than'), + 'contains' => __('Contains'), + 'ncontains' => __('Not contains'), + ]; + } /** * @inheritDoc @@ -61,6 +78,7 @@ public function addMetric(string $id, string $name): self $metric = [ 'id' => $id, 'name' => $name, + 'conditions' => $this->formatConditions($this->defaultConditions), 'values' => null ]; @@ -75,6 +93,54 @@ public function addMetric(string $id, string $name): self return $this; } + + /** + * @inheritDoc + */ + public function addCondition(array $conditions): self + { + // Ensure current type is set + if (!isset($this->criteria['types'][$this->currentTypeIndex])) { + throw new ConfigurationException(__('Current type is not set.')); + } + + // Validate conditions + foreach ($conditions as $id => $name) { + if (!array_key_exists($id, $this->defaultConditions)) { + throw new ConfigurationException(__('Invalid condition ID: %s', $id)); + } + } + + // Assign conditions to the current metric + foreach ($this->criteria['types'][$this->currentTypeIndex]['metrics'] as &$metric) { + if ($metric['name'] === $this->currentMetric['name']) { + $metric['conditions'] = $this->formatConditions($conditions); + break; + } + } + + return $this; + } + + /** + * Format conditions from key-value to the required array structure. + * + * @param array $conditions + * @return array + */ + private function formatConditions(array $conditions): array + { + $formattedConditions = []; + foreach ($conditions as $id => $name) { + $formattedConditions[] = [ + 'id' => $id, + 'name' => $name, + ]; + } + + return $formattedConditions; + } + /** * @inheritDoc */ @@ -122,4 +188,14 @@ public function getCriteria(): array { return $this->criteria; } + + /** + * Get the default conditions array. + * + * @return array + */ + public function getCriteriaDefaultCondition(): array + { + return $this->formatConditions($this->defaultConditions); + } } diff --git a/lib/Event/ScheduleCriteriaRequestInterface.php b/lib/Event/ScheduleCriteriaRequestInterface.php index dbc8f13fef..942fbfb48b 100644 --- a/lib/Event/ScheduleCriteriaRequestInterface.php +++ b/lib/Event/ScheduleCriteriaRequestInterface.php @@ -25,17 +25,19 @@ use Xibo\Support\Exception\ConfigurationException; /** - * Interface for managing schedule criteria types, metrics, and values. + * Interface for managing schedule criteria types, metrics, conditions, and values. * - * Allows the addition of types, metrics, and values in a chained manner: - * - Start with addType() to add a new type. Call addType() multiple times to add multiple types. - * - Follow with addMetric() to add metrics under the specified type. Call addMetric() multiple times to add multiple + * Allows the addition of types, metrics, conditions, and values in a chained manner: + * - Start with `addType()` to add a new type. Call `addType()` multiple times to add multiple types. + * - Follow with `addMetric()` to add metrics under the specified type. Call `addMetric()` multiple times to add multiple * metrics to the current type. - * - Conclude with addValues() immediately after addMetric() to specify a set of values for the metric. Each metric can + * - Optionally, call `addCondition()` after `addMetric()` to specify a set of conditions for the metric. If not called, + * the system will automatically apply default conditions, which include all supported conditions. + * - Conclude with `addValues()` immediately after `addMetric()` or `addCondition()` to specify a set of values for the metric. Each metric can * have one set of values. * * The added criteria are then parsed and displayed in the Schedule Criteria Form, enabling users to configure - * scheduling conditions based on the specified types, metrics, and values. + * scheduling conditions based on the specified parameters. */ interface ScheduleCriteriaRequestInterface { @@ -58,6 +60,42 @@ public function addType(string $id, string $type): self; */ public function addMetric(string $id, string $name): self; + /** + * Add conditions to the current metric. + * + * This method allows you to specify conditions for the currently added metric. + * The list of accepted conditions includes: + * - 'set' => 'Is set' + * - 'lt' => 'Less than' + * - 'lte' => 'Less than or equal to' + * - 'eq' => 'Equal to' + * - 'neq' => 'Not equal to' + * - 'gte' => 'Greater than or equal to' + * - 'gt' => 'Greater than' + * - 'contains' => 'Contains' + * - 'ncontains' => 'Not contains' + * + * **Important Notes:** + * - The `addMetric` method **must** be called before using `addCondition`. + * If no metric is currently set, this method will throw a `ConfigurationException`. + * - If this method is **not called** for a metric, the system will automatically + * provide the default conditions, which include **all the accepted conditions** listed above. + * + * Example usage: + * ``` + * $event->addMetric('temp', 'Temperature') + * ->addCondition([ + * 'eq' => 'Equal to', + * 'gt' => 'Greater than', + * ]); + * ``` + * + * @param array $conditions An associative array of conditions, where the key is the condition ID and the value is its name. + * @return $this + * @throws ConfigurationException If the current metric is not set. + */ + public function addCondition(array $conditions): self; + /** * Add values to the current metric. The input type must be either "dropdown", "string", "date", or "number". * diff --git a/ui/src/core/xibo-calendar.js b/ui/src/core/xibo-calendar.js index d6e86665fa..9dca2c98b5 100644 --- a/ui/src/core/xibo-calendar.js +++ b/ui/src/core/xibo-calendar.js @@ -56,6 +56,7 @@ $(function() { const selectedType = $target.val(); const $fields = $('#scheduleCriteriaFields'); const scheduleCriteria = $fields.data('scheduleCriteria'); + const criteriaDefaultCondition = $fields.data('criteriaDefaultCondition'); if (scheduleCriteria) { if (selectedType === 'custom') { @@ -63,6 +64,8 @@ $(function() { updateMetricsFieldAsText($row); // Use a text input for values updateValueFieldAsText($row); + // Revert condition field to default + updateConditionFieldToDefault($row, criteriaDefaultCondition); } else if (scheduleCriteria) { // Update metrics based on the selected type // and change text field to dropdown @@ -76,6 +79,8 @@ $(function() { const $metricLabel = $row.find('label[for="criteria_metric[]"]'); const $metricSelect = $(''); + const $fields = $('#scheduleCriteriaFields'); + const criteriaDefaultCondition = $fields.data('criteriaDefaultCondition'); // Check if scheduleCriteria has types if (scheduleCriteria.types) { @@ -97,6 +102,14 @@ $(function() { } else { updateValueFieldAsText($row); } + + // Update the condition field based on the selected metric + if (metricData && metricData.conditions) { + updateConditionField($row, metricData.conditions); + } else { + // If no conditions are defined, use the default conditions + updateConditionFieldToDefault($row, criteriaDefaultCondition); + } } } @@ -128,6 +141,7 @@ $(function() { const selectedMetric = $target.val(); const $fields = $('#scheduleCriteriaFields'); const scheduleCriteria = $fields.data('scheduleCriteria'); + const criteriaDefaultCondition = $fields.data('criteriaDefaultCondition'); const selectedType = $row.find('select[name="criteria_type[]"]').val(); if (scheduleCriteria && selectedType) { @@ -143,6 +157,14 @@ $(function() { } else { updateValueFieldAsText($row); } + + // Update the condition field based on the selected metric + if (metricData && metricData.conditions) { + updateConditionField($row, metricData.conditions); + } else { + // If no conditions are defined, use the default conditions + updateConditionFieldToDefault($row, criteriaDefaultCondition); + } } } }); @@ -909,6 +931,46 @@ $(function() { } }); +// Function to update the Condition dropdown according to the selected metric's available condition +function updateConditionField($row, conditions, selectedCondition) { + const $conditionField = $row.find('select[name="criteria_condition[]"]'); + + if ($conditionField.length > 0) { + // Clear existing options + $conditionField.empty(); + + // Populate with provided conditions + conditions.forEach((condition) => { + $conditionField.append( + $('