From b680f48feb1a6c947a1cefecb082d3b5e110d376 Mon Sep 17 00:00:00 2001 From: Mojmir Fendek Date: Tue, 9 Jun 2020 13:38:22 +1200 Subject: [PATCH] NEW: Advanced jobs admin UI. --- README.md | 11 ++ composer.json | 3 + src/Controllers/QueuedJobsAdmin.php | 178 ++++++++++++++++++++++++ src/DataObjects/QueuedJobDescriptor.php | 31 ++++- 4 files changed, 218 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4f706312..621c854f 100644 --- a/README.md +++ b/README.md @@ -819,6 +819,17 @@ As a consequence, the work might end up being very fragmented and each chunk may Some projects do not mind this however, so this solution may still be quite suitable. +## Enabling extended admin UI + +In case your project has many jobs to search through and the basic UI is not enough, you can use the advanced jobs admin UI option. +This option requires the `silverstripe-terraformers/gridfield-rich-filter-header` module, though. +To enable the advanced UI simply add this config to your project. + +```yaml +Symbiote\QueuedJobs\Controllers\QueuedJobsAdmin: + advanced_admin_ui: true +``` + ## Contributing ### Translations diff --git a/composer.json b/composer.json index 9956d148..fe0a3a39 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,9 @@ "replace": { "silverstripe/queuedjobs": "self.version" }, + "suggest": { + "silverstripe-terraformers/gridfield-rich-filter-header": "Required for advanced admin UI" + }, "autoload": { "psr-4": { "Symbiote\\QueuedJobs\\": "src/", diff --git a/src/Controllers/QueuedJobsAdmin.php b/src/Controllers/QueuedJobsAdmin.php index 13eeece7..33235070 100644 --- a/src/Controllers/QueuedJobsAdmin.php +++ b/src/Controllers/QueuedJobsAdmin.php @@ -15,9 +15,12 @@ use SilverStripe\Forms\GridField\GridFieldAddNewButton; use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; use SilverStripe\Forms\GridField\GridFieldDataColumns; +use SilverStripe\Forms\GridField\GridFieldFilterHeader; use SilverStripe\Forms\GridField\GridFieldPageCount; use SilverStripe\Forms\GridField\GridFieldToolbarHeader; use SilverStripe\Forms\TextareaField; +use SilverStripe\ORM\DataList; +use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\Security\Permission; use SilverStripe\Security\Security; use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor; @@ -25,6 +28,7 @@ use Symbiote\QueuedJobs\Services\AbstractQueuedJob; use Symbiote\QueuedJobs\Services\QueuedJob; use Symbiote\QueuedJobs\Services\QueuedJobService; +use Terraformers\RichFilterHeader\Form\GridField\RichFilterHeader; /** * @author Marcus Nyeholt @@ -32,6 +36,9 @@ */ class QueuedJobsAdmin extends ModelAdmin { + const SCHEDULED_FILTER_FUTURE = 'future'; + const SCHEDULED_FILTER_PAST = 'past'; + /** * @var string */ @@ -74,6 +81,16 @@ class QueuedJobsAdmin extends ModelAdmin */ private static $date_format_european = 'dd/MM/yyyy'; + /** + * Enables advanced admin UI + * This requires the optional module + * silverstripe-terraformers/gridfield-rich-filter-header + * + * @config + * @var bool + */ + private static $advanced_admin_ui = false; + /** * @var QueuedJobService */ @@ -167,6 +184,10 @@ public function getEditForm($id = null, $fields = null) ); } + if ($this->config()->get('advanced_admin_ui')) { + $this->enableAdvancedAdminUi($grid); + } + $this->extend('updateEditForm', $form); return $form; @@ -213,4 +234,161 @@ public function createjob($data, Form $form) } return $this->redirectBack(); } + + /** + * @param GridField $gridField + */ + private function enableAdvancedAdminUi(GridField $gridField) + { + if (!class_exists(RichFilterHeader::class)) { + return; + } + + $config = $gridField->getConfig(); + + /** @var GridFieldDataColumns $gridFieldColumns */ + $gridFieldColumns = $config->getComponentByType(GridFieldDataColumns::class); + + $gridFieldColumns->setDisplayFields([ + 'getTrimmedImplementation' => _t(__CLASS__ . '.SUMMARY_TYPE', 'Type'), + 'JobTypeString' => _t(__CLASS__ . '.SUMMARY_QUEUE', 'Queue'), + 'JobStatus' => _t(__CLASS__ . '.SUMMARY_STATUS', 'Status'), + 'JobTitle' => _t(__CLASS__ . '.SUMMARY_DESCRIPTION', 'Description'), + 'Created' => _t(__CLASS__ . '.SUMMARY_ADDED', 'Added'), + 'StartAfter' => _t(__CLASS__ . '.SUMMARY_SCHEDULED', 'Scheduled'), + 'JobFinished' => _t(__CLASS__ . '.SUMMARY_FINISHED', 'Finished'), + ]); + + $config->removeComponentsByType(GridFieldFilterHeader::class); + + $filter = new RichFilterHeader(); + $filter + ->setFilterConfig([ + 'getTrimmedImplementation' => 'Implementation', + 'Description' => 'JobTitle', + 'Status' => [ + 'title' => 'JobStatus', + 'filter' => 'ExactMatchFilter', + ], + 'JobTypeString' => [ + 'title' => 'JobType', + 'filter' => 'ExactMatchFilter', + ], + 'Created' => 'Added', + 'StartAfter' => 'Scheduled', + ]) + ->setFilterFields([ + 'JobType' => $queueType = DropdownField::create( + '', + '', + $this->getQueueTypes() + ), + 'JobStatus' => $jobStatus = DropdownField::create( + '', + '', + $this->getJobStatuses() + ), + 'Added' => $added = DropdownField::create( + '', + '', + $this->getAddedDates() + ), + 'Scheduled' => $scheduled = DropdownField::create( + '', + '', + [ + self::SCHEDULED_FILTER_FUTURE => self::SCHEDULED_FILTER_FUTURE, + self::SCHEDULED_FILTER_PAST => self::SCHEDULED_FILTER_PAST, + ] + ), + ]) + ->setFilterMethods([ + 'Added' => static function (DataList $list, $name, $value) { + if ($value) { + $added = DBDatetime::now()->modify($value); + + return $list->filter(['Created:LessThanOrEqual' => $added->Rfc2822()]); + } + + return $list; + }, + 'Scheduled' => static function (DataList $list, $name, $value) { + if ($value === static::SCHEDULED_FILTER_FUTURE) { + return $list->filter([ + 'StartAfter:GreaterThan' => DBDatetime::now()->Rfc2822(), + ]); + } + + if ($value === static::SCHEDULED_FILTER_PAST) { + return $list->filter([ + 'StartAfter:LessThanOrEqual' => DBDatetime::now()->Rfc2822(), + ]); + } + + return $list; + }, + ]); + + foreach ([$jobStatus, $queueType, $added, $scheduled] as $dropDownField) { + /** @var DropdownField $dropDownField */ + $dropDownField->setEmptyString('-- select --'); + } + + $config->addComponent($filter, GridFieldPaginator::class); + } + + /** + * Queue types options for drop down field + * + * @return array + */ + private function getQueueTypes() + { + /** @var QueuedJobDescriptor $job */ + $job = QueuedJobDescriptor::singleton(); + $map = $job->getJobTypeValues(); + $values = array_values($map); + $keys = []; + + foreach (array_keys($map) as $key) { + $keys[] = (int) $key; + } + + return array_combine($keys, $values); + } + + /** + * All possible job statuses (this list is not exposed by the module) + * intended to be used in a drop down field + * + * @return array + */ + private function getJobStatuses() + { + /** @var QueuedJobDescriptor $job */ + $job = QueuedJobDescriptor::singleton(); + $statuses = $job->getJobStatusValues(); + + sort($statuses, SORT_STRING); + + $statuses = array_combine($statuses, $statuses); + + return $statuses; + } + + /** + * Date options for added dates drop down field + * + * @return array + */ + private function getAddedDates() + { + return [ + '-1 day' => '1 day or older', + '-3 day' => '3 days or older', + '-7 day' => '7 days or older', + '-14 day' => '14 days or older', + '-1 month' => '1 month or older', + ]; + } } diff --git a/src/DataObjects/QueuedJobDescriptor.php b/src/DataObjects/QueuedJobDescriptor.php index b5728c1f..dc9d06f7 100644 --- a/src/DataObjects/QueuedJobDescriptor.php +++ b/src/DataObjects/QueuedJobDescriptor.php @@ -318,6 +318,19 @@ public function getJobTypeString() return isset($map[$this->JobType]) ? $map[$this->JobType] : '(Unknown)'; } + /** + * @return string + */ + public function getTrimmedImplementation() + { + $segments = explode('\\', $this->Implementation); + + while (count($segments) > 2) { + array_shift($segments); + } + + return implode('\\', $segments); + } /** * Return a map of numeric JobType values to localisable string representations. @@ -333,13 +346,11 @@ public function getJobTypeValues() } /** - * @return FieldList + * @return array */ - public function getCMSFields() + public function getJobStatusValues() { - $fields = parent::getCMSFields(); - - $statuses = [ + return [ QueuedJob::STATUS_NEW, QueuedJob::STATUS_INIT, QueuedJob::STATUS_RUN, @@ -349,6 +360,16 @@ public function getCMSFields() QueuedJob::STATUS_CANCELLED, QueuedJob::STATUS_BROKEN, ]; + } + + /** + * @return FieldList + */ + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $statuses = $this->getJobStatusValues(); $runAs = $fields->fieldByName('Root.Main.RunAsID');