From be5ed68513eba219f32e06c8a96570fd7fcf7068 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 30 Oct 2023 11:19:36 +0000 Subject: [PATCH] Schedule grid filter improvements and Folder css adjustments (#2181) * Folders : Improve css * Schedule : Add two new filters to the grid for direct and shared schedules. * Schedule : Improve SQL for shared and direct grid filtering. Add comments to each statement. * Schedule Grid : Improve the SQL filter further. add date filters to the sub queries --- lib/Controller/Schedule.php | 2 + lib/Factory/ScheduleFactory.php | 145 +++++++++++++++++++++++++++++++- views/campaign-page.twig | 24 +++--- views/dataset-page.twig | 24 +++--- views/display-page.twig | 24 +++--- views/displaygroup-page.twig | 24 +++--- views/layout-page.twig | 24 +++--- views/library-page.twig | 24 +++--- views/menuboard-page.twig | 24 +++--- views/playlist-page.twig | 24 +++--- views/schedule-page.twig | 33 +++++++- views/syncgroup-page.twig | 24 +++--- views/template-page.twig | 24 +++--- web/theme/default/css/xibo.css | 5 ++ 14 files changed, 312 insertions(+), 113 deletions(-) diff --git a/lib/Controller/Schedule.php b/lib/Controller/Schedule.php index 21090dafcd..dade00ef06 100644 --- a/lib/Controller/Schedule.php +++ b/lib/Controller/Schedule.php @@ -2235,6 +2235,8 @@ public function grid(Request $request, Response $response) 'name' => $params->getString('name'), 'useRegexForName' => $params->getCheckbox('useRegexForName'), 'logicalOperatorName' => $params->getString('logicalOperatorName'), + 'directSchedule' => $params->getCheckbox('directSchedule'), + 'sharedSchedule' => $params->getCheckbox('sharedSchedule'), 'gridFilter' => 1, ], $params) ); diff --git a/lib/Factory/ScheduleFactory.php b/lib/Factory/ScheduleFactory.php index 74cbfc2cda..7fcd7e7b8d 100644 --- a/lib/Factory/ScheduleFactory.php +++ b/lib/Factory/ScheduleFactory.php @@ -486,8 +486,149 @@ public function query($sortOrder = null, $filterBy = []) // End both dates if ($parsedFilter->getIntArray('displayGroupIds') != null) { - $body .= ' AND `schedule`.eventId IN (SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` - WHERE displayGroupId IN (' . implode(',', $parsedFilter->getIntArray('displayGroupIds')) . ')) '; + // parameterize the selected display/groups and number of selected display/groups + $selectedDisplayGroupIds = implode(',', $parsedFilter->getIntArray('displayGroupIds')); + $numberOfSelectedDisplayGroups = count($parsedFilter->getIntArray('displayGroupIds')); + + // build date filter for sub-queries for shared schedules + $sharedScheduleDateFilter = ''; + if ($parsedFilter->getInt('futureSchedulesFrom') !== null + && $parsedFilter->getInt('futureSchedulesTo') === null + ) { + // Get schedules that end after this date, or that recur after this date + $sharedScheduleDateFilter .= ' AND (IFNULL(`schedule`.toDt, `schedule`.fromDt) >= :futureSchedulesFrom + OR `schedule`.recurrence_range >= :futureSchedulesFrom OR (IFNULL(`schedule`.recurrence_range, 0) = 0) + AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\') '; + $params['futureSchedulesFrom'] = $parsedFilter->getInt('futureSchedulesFrom'); + } + + if ($parsedFilter->getInt('futureSchedulesFrom') !== null + && $parsedFilter->getInt('futureSchedulesTo') !== null + ) { + // Get schedules that end after this date, or that recur after this date + $sharedScheduleDateFilter .= ' AND ((schedule.fromDt < :futureSchedulesTo + AND IFNULL(`schedule`.toDt, `schedule`.fromDt) >= :futureSchedulesFrom) + OR `schedule`.recurrence_range >= :futureSchedulesFrom OR (IFNULL(`schedule`.recurrence_range, 0) = 0 + AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\') ) '; + $params['futureSchedulesFrom'] = $parsedFilter->getInt('futureSchedulesFrom'); + $params['futureSchedulesTo'] = $parsedFilter->getInt('futureSchedulesTo'); + } + + // non Schedule grid filter, keep it the way it was. + if ($parsedFilter->getInt('sharedSchedule') === null && + $parsedFilter->getInt('directSchedule') === null + ) { + $body .= ' AND `schedule`.eventId IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + WHERE displayGroupId IN (' . $selectedDisplayGroupIds . ') + ) '; + } else { + // Schedule grid query + // check what options we were provided with and adjust query accordingly. + $sharedSchedule = ($parsedFilter->getInt('sharedSchedule') === 1); + $directSchedule = ($parsedFilter->getInt('directSchedule') === 1); + + // shared and direct + // events scheduled directly on the selected displays/groups + // and scheduled on all selected displays/groups + // Example : Two Displays selected, return only events scheduled directly to both of them + if ($sharedSchedule && $directSchedule) { + $body .= ' AND `schedule`.eventId IN ( + SELECT `lkscheduledisplaygroup`.eventId + FROM `lkscheduledisplaygroup` + INNER JOIN `schedule` ON `schedule`.eventId = `lkscheduledisplaygroup`.eventId + WHERE displayGroupId IN (' . $selectedDisplayGroupIds . ')' . + $sharedScheduleDateFilter . ' + GROUP BY eventId + HAVING COUNT(DISTINCT displayGroupId) >= ' . + $numberOfSelectedDisplayGroups . + ') '; + } + + // shared and not direct + // 1 - events scheduled on the selected display/groups + // 2 - events scheduled on a display group selected display is a member of + // 3 - events scheduled on a parent display group of selected display group + // and scheduled on all selected displays/groups + // Example : Two Displays selected, return only events scheduled directly to both of them + if ($sharedSchedule && !$directSchedule) { + $body .= ' AND ( + ( `schedule`.eventId IN ( + SELECT `lkscheduledisplaygroup`.eventId + FROM `lkscheduledisplaygroup` + INNER JOIN `schedule` ON `schedule`.eventId = `lkscheduledisplaygroup`.eventId + WHERE displayGroupId IN (' . $selectedDisplayGroupIds . ')' . + $sharedScheduleDateFilter . ' + GROUP BY eventId + HAVING COUNT(DISTINCT displayGroupId) >= ' . $numberOfSelectedDisplayGroups . ' + )) + OR `schedule`.eventID IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + INNER JOIN `schedule` ON `schedule`.eventId = `lkscheduledisplaygroup`.eventId + INNER JOIN `lkdgdg` ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId + INNER JOIN `lkdisplaydg` ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId + WHERE `lkdisplaydg`.DisplayID IN ( + SELECT lkdisplaydg.displayId FROM lkdisplaydg + INNER JOIN displaygroup ON lkdisplaydg.displayGroupId = displaygroup.displayGroupId + WHERE lkdisplaydg.displayGroupId IN (' . $selectedDisplayGroupIds . ') + AND displaygroup.isDisplaySpecific = 1 ) ' . + $sharedScheduleDateFilter . ' + GROUP BY eventId + HAVING COUNT(DISTINCT `lkdisplaydg`.displayId) >= ' . + $numberOfSelectedDisplayGroups . ' + ) + OR `schedule`.eventID IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + INNER JOIN `schedule` ON `schedule`.eventId = `lkscheduledisplaygroup`.eventId + INNER JOIN `lkdgdg` ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId + WHERE `lkscheduledisplaygroup`.displayGroupId IN ( + SELECT lkdgdg.childId FROM lkdgdg + WHERE lkdgdg.parentId IN (' . $selectedDisplayGroupIds .') AND lkdgdg.depth > 0)' . + $sharedScheduleDateFilter . ' + GROUP BY eventId + HAVING COUNT(DISTINCT `lkscheduledisplaygroup`.displayGroupId) >= ' . + $numberOfSelectedDisplayGroups . ' + ) + ) '; + } + + // not shared and direct (old default) + // events scheduled directly on selected displays/groups + if (!$sharedSchedule && $directSchedule) { + $body .= ' AND `schedule`.eventId IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + WHERE displayGroupId IN (' . $selectedDisplayGroupIds . ') + ) '; + } + + // not shared and not direct (new default) + // 1 - events scheduled on the selected display/groups + // 2 - events scheduled on a display group selected display is a member of + // 3 - events scheduled on a parent display group of selected display group + if (!$sharedSchedule && !$directSchedule) { + $body .= ' AND ( + ( `schedule`.eventId IN (SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + WHERE displayGroupId IN (' . $selectedDisplayGroupIds . ')) ) + OR `schedule`.eventID IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + INNER JOIN `lkdgdg` ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId + INNER JOIN `lkdisplaydg` ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId + WHERE `lkdisplaydg`.DisplayID IN ( + SELECT lkdisplaydg.displayId FROM lkdisplaydg + INNER JOIN displaygroup ON lkdisplaydg.displayGroupId = displaygroup.displayGroupId + WHERE lkdisplaydg.displayGroupId IN (' . $selectedDisplayGroupIds . ') + AND displaygroup.isDisplaySpecific = 1 ) + ) + OR `schedule`.eventID IN ( + SELECT `lkscheduledisplaygroup`.eventId FROM `lkscheduledisplaygroup` + INNER JOIN `lkdgdg` ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId + WHERE `lkscheduledisplaygroup`.displayGroupId IN ( + SELECT lkdgdg.childId FROM lkdgdg + WHERE lkdgdg.parentId IN (' . $selectedDisplayGroupIds .') AND lkdgdg.depth > 0) + ) + ) '; + } + } } // Future schedules? diff --git a/views/campaign-page.twig b/views/campaign-page.twig index a9f9603cae..060df20a63 100644 --- a/views/campaign-page.twig +++ b/views/campaign-page.twig @@ -86,23 +86,25 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/views/dataset-page.twig b/views/dataset-page.twig index f2a9356a19..3df53553f4 100644 --- a/views/dataset-page.twig +++ b/views/dataset-page.twig @@ -59,23 +59,25 @@
-
- -
- - -
-
-

{% trans 'No Folders matching the search term' %}

+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-
-
+
+
diff --git a/views/display-page.twig b/views/display-page.twig index 92ea558241..d82cefff39 100644 --- a/views/display-page.twig +++ b/views/display-page.twig @@ -178,16 +178,18 @@
-
- -
- - -
-
-

{% trans 'No Folders matching the search term' %}

+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
@@ -200,8 +202,8 @@
-
-
+
+
diff --git a/views/displaygroup-page.twig b/views/displaygroup-page.twig index 1b6ca516bd..dec53545ec 100644 --- a/views/displaygroup-page.twig +++ b/views/displaygroup-page.twig @@ -83,23 +83,25 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/views/layout-page.twig b/views/layout-page.twig index 6a04f542fd..38f1aea02d 100644 --- a/views/layout-page.twig +++ b/views/layout-page.twig @@ -112,16 +112,18 @@
-
- -
- - -
-
-

{% trans 'No Folders matching the search term' %}

+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
@@ -129,8 +131,8 @@
-
-
+
+
diff --git a/views/library-page.twig b/views/library-page.twig index 12c312d39c..653ab01241 100644 --- a/views/library-page.twig +++ b/views/library-page.twig @@ -98,23 +98,25 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/views/menuboard-page.twig b/views/menuboard-page.twig index 40d37ff62b..81c5870f6b 100644 --- a/views/menuboard-page.twig +++ b/views/menuboard-page.twig @@ -74,19 +74,21 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/views/playlist-page.twig b/views/playlist-page.twig index 620328a2fc..33f1aaa9c5 100644 --- a/views/playlist-page.twig +++ b/views/playlist-page.twig @@ -92,23 +92,25 @@
-
- -
- - -
-
-

{% trans 'No Folders matching the search term' %}

+
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-
-
+
+
diff --git a/views/schedule-page.twig b/views/schedule-page.twig index cdc2aa93f4..29b8a788ff 100644 --- a/views/schedule-page.twig +++ b/views/schedule-page.twig @@ -128,7 +128,7 @@ {% set title %}{% trans "Display Groups" %}{% endset %} -
+
+
+
+ + + + + {% set title %}{% trans "Only show schedules which appear on all filtered displays/groups?" %}{% endset %} + {% set label %}{% trans "Shared Schedule?" %}{% endset %} +
+ +
+
+
+
+ +
+
+
+
+
+ {% set title %}{% trans 'Geo Aware?' %}{% endset %} {% set options = [ { id: null, name: "Both"|trans }, diff --git a/views/syncgroup-page.twig b/views/syncgroup-page.twig index f02182dd61..fda92800c2 100644 --- a/views/syncgroup-page.twig +++ b/views/syncgroup-page.twig @@ -56,23 +56,25 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/views/template-page.twig b/views/template-page.twig index e48c37659c..67940d49df 100644 --- a/views/template-page.twig +++ b/views/template-page.twig @@ -57,23 +57,25 @@
-
- -
- - +
+
+ +
+ + +
+
+

{% trans 'No Folders matching the search term' %}

+
+
-
-

{% trans 'No Folders matching the search term' %}

-
-
-
-
+
+
diff --git a/web/theme/default/css/xibo.css b/web/theme/default/css/xibo.css index fc13e6e15d..a111ca321c 100644 --- a/web/theme/default/css/xibo.css +++ b/web/theme/default/css/xibo.css @@ -1517,4 +1517,9 @@ div.dataTables_wrapper div.dataTables_info { .text-xibo-primary { color: #0E70F6; +} + +.grid-folder-tree-container { + border: 1px solid #00000020; + border-radius: 0.25rem; } \ No newline at end of file