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(
+ $('