From afa9734df0981cb36ec8c58a9b65f1f6063385c2 Mon Sep 17 00:00:00 2001 From: Paul Mitchum Date: Wed, 29 Nov 2023 17:13:29 -0600 Subject: [PATCH] Harvest status page should reflect all registered harvests (#4048) --- modules/harvest/css/style.css | 9 +++ modules/harvest/src/DashboardController.php | 68 +++++++++++++------ modules/harvest/src/HarvestService.php | 13 ++-- .../src/Kernel/DashboardControllerTest.php | 66 ++++++++++++++++++ .../src/Unit/DashboardControllerTest.php | 12 +--- 5 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 modules/harvest/tests/src/Kernel/DashboardControllerTest.php diff --git a/modules/harvest/css/style.css b/modules/harvest/css/style.css index b95428886a..7363f041de 100644 --- a/modules/harvest/css/style.css +++ b/modules/harvest/css/style.css @@ -9,6 +9,15 @@ table.dashboard-datasets td.done background-color: #f3faef; } +/** + * Waiting. + */ +table.dashboard-harvests td.registered +{ + color: #5c5e1c; + background-color: #faf8ef; +} + /* * Warning. */ diff --git a/modules/harvest/src/DashboardController.php b/modules/harvest/src/DashboardController.php index c54643d32f..5e31ea4289 100644 --- a/modules/harvest/src/DashboardController.php +++ b/modules/harvest/src/DashboardController.php @@ -2,14 +2,16 @@ namespace Drupal\harvest; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Link; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Url; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Controller. */ -class DashboardController { +class DashboardController implements ContainerInjectionInterface { use StringTranslationTrait; @@ -25,13 +27,22 @@ class DashboardController { * * @var \Drupal\harvest\HarvestService */ - protected $harvest; + protected $harvestService; + + /** + * {@inheritDoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('dkan.harvest.service') + ); + } /** * Controller constructor. */ - public function __construct() { - $this->harvest = \Drupal::service('dkan.harvest.service'); + public function __construct(HarvestService $harvestService) { + $this->harvestService = $harvestService; } /** @@ -42,15 +53,17 @@ public function harvests(): array { date_default_timezone_set(date_default_timezone_get()); $rows = []; - foreach ($this->harvest->getAllHarvestIds() as $harvestId) { - // @todo Make Harvest Service's private getLastHarvestRunId() public, - // And replace 7-8 cases where we recreate it. - $runIds = $this->harvest->getAllHarvestRunInfo($harvestId); - - if ($runId = end($runIds)) { - $info = json_decode($this->harvest->getHarvestRunInfo($harvestId, $runId)); + foreach ($this->harvestService->getAllHarvestIds() as $harvestPlanId) { + if ($runId = $this->harvestService->getLastHarvestRunId($harvestPlanId)) { + // There is a run identifier, so we should get that info. + $info = json_decode($this->harvestService->getHarvestRunInfo($harvestPlanId, $runId)); - $rows[] = $this->buildHarvestRow($harvestId, $runId, $info); + $rows[] = $this->buildHarvestRow($harvestPlanId, $runId, $info); + } + else { + // There is no recent run identifier, so we should display some default + // info to the user. + $rows[] = $this->buildHarvestRow($harvestPlanId, '', NULL); } } @@ -60,25 +73,40 @@ public function harvests(): array { '#rows' => $rows, '#attributes' => ['class' => 'dashboard-harvests'], '#attached' => ['library' => ['harvest/style']], - '#empty' => "No harvests found", + '#empty' => 'No harvests found', ]; } /** * Private. */ - private function buildHarvestRow(string $harvestId, string $runId, $info) { - $url = Url::fromRoute('datastore.datasets_import_status_dashboard', ['harvest_id' => $harvestId]); + private function buildHarvestRow(string $harvestId, string $runId, $info): array { + $url = Url::fromRoute( + 'datastore.datasets_import_status_dashboard', + ['harvest_id' => $harvestId] + ); - return [ + // Default values if there is no run information. This will show the harvest + // in the list, even if there is no run status to report. + $row = [ 'harvest_link' => Link::fromTextAndUrl($harvestId, $url), 'extract_status' => [ - 'data' => $info->status->extract, - 'class' => strtolower($info->status->extract), + 'data' => 'REGISTERED', + 'class' => 'registered', ], - 'last_run' => date('m/d/y H:m:s T', $runId), - 'dataset_count' => count(array_keys((array) $info->status->load)), + 'last_run' => 'never', + 'dataset_count' => 'unknown', ]; + // Add run information if available. + if ($info) { + $row['extract_status'] = [ + 'data' => $info->status->extract, + 'class' => strtolower($info->status->extract), + ]; + $row['last_run'] = date('m/d/y H:m:s T', $runId); + $row['dataset_count'] = count(array_keys((array) $info->status->load)); + } + return $row; } } diff --git a/modules/harvest/src/HarvestService.php b/modules/harvest/src/HarvestService.php index b7cb445fc0..7a3e170b6e 100644 --- a/modules/harvest/src/HarvestService.php +++ b/modules/harvest/src/HarvestService.php @@ -214,13 +214,18 @@ public function getAllHarvestRunInfo($id) { } /** - * Get a harvest's most recent run identifier, i.e. timestamp. + * Get a harvest's most recent run identifier. * - * @param string $id + * Since the run record id is a timestamp, we can sort on the id. + * + * @param string $planId * The harvest identifier. + * + * @return string + * The most recent harvest run record identifier. */ - private function getLastHarvestRunId(string $id) { - $runs = $this->getAllHarvestRunInfo($id); + public function getLastHarvestRunId(string $planId) { + $runs = $this->getAllHarvestRunInfo($planId); rsort($runs); return reset($runs); } diff --git a/modules/harvest/tests/src/Kernel/DashboardControllerTest.php b/modules/harvest/tests/src/Kernel/DashboardControllerTest.php new file mode 100644 index 0000000000..1212734ad5 --- /dev/null +++ b/modules/harvest/tests/src/Kernel/DashboardControllerTest.php @@ -0,0 +1,66 @@ +container->get('dkan.harvest.service'); + + $dashboard_controller = DashboardController::create($this->container); + + // There are no registered harvests, so there should be zero rows. We also + // verify the empty table value. + $render_array = $dashboard_controller->harvests(); + $this->assertCount(0, $render_array['#rows'] ?? NULL); + $this->assertEquals('No harvests found', $render_array['#empty'] ?? NULL); + + // Register a harvest plan but don't run it... + $plan_identifier = 'test_plan'; + $plan = (object) [ + 'identifier' => $plan_identifier, + 'extract' => (object) [ + 'type' => DataJson::class, + 'uri' => 'file://' . __DIR__ . '/../../files/data.json', + ], + 'transforms' => [], + 'load' => (object) [ + 'type' => Simple::class, + ], + ]; + $this->assertNotNull($harvest_service->registerHarvest($plan)); + + // Revisit the dashboard. It should show the registered harvest. + $render_array = $dashboard_controller->harvests(); + $this->assertCount(1, $render_array['#rows'] ?? NULL); + $this->assertNotNull($row = $render_array['#rows'][0] ?? NULL); + /** @var \Drupal\Core\Link $link */ + $this->assertNotNull($link = $row['harvest_link'] ?? NULL); + $this->assertEquals($plan_identifier, $link->getText()); + // Harvest was registered, but never run. + $this->assertEquals('REGISTERED', $row['extract_status']['data'] ?? NULL); + $this->assertEquals('never', $row['last_run'] ?? NULL); + $this->assertEquals('unknown', $row['dataset_count'] ?? NULL); + } + +} diff --git a/modules/harvest/tests/src/Unit/DashboardControllerTest.php b/modules/harvest/tests/src/Unit/DashboardControllerTest.php index 3b92198d55..d614a258ca 100644 --- a/modules/harvest/tests/src/Unit/DashboardControllerTest.php +++ b/modules/harvest/tests/src/Unit/DashboardControllerTest.php @@ -18,9 +18,7 @@ public function testNoHarvests() { ->add(HarvestService::class, 'getAllHarvestIds', []) ->getMock(); - \Drupal::setContainer($container); - - $controller = new DashboardController(); + $controller = DashboardController::create($container); $response = $controller->harvests(); $json = json_encode($response); @@ -36,9 +34,7 @@ public function testRegisteredHarvest() { ->add(HarvestService::class, 'getAllHarvestRunInfo', []) ->getMock(); - \Drupal::setContainer($container); - - $controller = new DashboardController(); + $controller = DashboardController::create($container); $response = $controller->harvests(); $json = json_encode($response); @@ -56,9 +52,7 @@ public function testGoodHarvestRun() { ->add(HarvestService::class, 'getAllHarvestRunInfo', [$time]) ->getMock(); - \Drupal::setContainer($container); - - $controller = new DashboardController(); + $controller = DashboardController::create($container); $response = $controller->harvests(); $json = json_encode((array)$response);