ai_upgrade_assistant-0.2.0-alpha2/src/Controller/UpdateHistoryController.php
src/Controller/UpdateHistoryController.php
<?php
namespace Drupal\ai_upgrade_assistant\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\ai_upgrade_assistant\Service\UpdateHistoryService;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
/**
* Controller for displaying update history.
*/
class UpdateHistoryController extends ControllerBase {
/**
* The update history service.
*
* @var \Drupal\ai_upgrade_assistant\Service\UpdateHistoryService
*/
protected $historyService;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* Constructs a new UpdateHistoryController.
*
* @param \Drupal\ai_upgrade_assistant\Service\UpdateHistoryService $history_service
* The update history service.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service.
*/
public function __construct(
UpdateHistoryService $history_service,
DateFormatterInterface $date_formatter
) {
$this->historyService = $history_service;
$this->dateFormatter = $date_formatter;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('ai_upgrade_assistant.update_history'),
$container->get('date.formatter')
);
}
/**
* Displays the update history overview page.
*
* @return array
* A render array for the overview page.
*/
public function overview() {
$build = [];
$build['#attached']['library'][] = 'ai_upgrade_assistant/update_history';
// Add filters
$build['filters'] = [
'#type' => 'container',
'#attributes' => ['class' => ['update-history-filters']],
];
$build['filters']['module'] = [
'#type' => 'textfield',
'#title' => $this->t('Module'),
'#attributes' => ['class' => ['update-history-filter-module']],
];
$build['filters']['status'] = [
'#type' => 'select',
'#title' => $this->t('Status'),
'#options' => [
'' => $this->t('- Any -'),
'success' => $this->t('Success'),
'failure' => $this->t('Failure'),
'in_progress' => $this->t('In Progress'),
],
'#attributes' => ['class' => ['update-history-filter-status']],
];
// Add metrics summary
$metrics = $this->historyService->getSuccessMetrics();
$build['metrics'] = [
'#type' => 'container',
'#attributes' => ['class' => ['update-history-metrics']],
'content' => [
'#theme' => 'item_list',
'#items' => [
$this->t('Total Updates: @total', ['@total' => $metrics['total']]),
$this->t('Successful Updates: @successful', ['@successful' => $metrics['successful']]),
$this->t('Success Rate: @rate%', ['@rate' => number_format($metrics['success_rate'], 1)]),
],
],
];
// Add history table
$header = [
'module' => $this->t('Module'),
'from_version' => $this->t('From Version'),
'to_version' => $this->t('To Version'),
'status' => $this->t('Status'),
'start_time' => $this->t('Started'),
'duration' => $this->t('Duration'),
'operations' => $this->t('Operations'),
];
$rows = [];
$updates = $this->historyService->getModuleHistory(NULL, 50); // Get last 50 updates
foreach ($updates as $update) {
$duration = '';
if ($update->end_time) {
$duration = $this->formatDuration($update->end_time - $update->start_time);
}
$row = [
'module' => $update->module_name,
'from_version' => $update->from_version,
'to_version' => $update->to_version,
'status' => [
'data' => [
'#type' => 'status_message',
'#status' => $update->status,
],
],
'start_time' => $this->dateFormatter->format($update->start_time, 'short'),
'duration' => $duration,
];
// Add operations
$operations = [];
$operations['view'] = [
'title' => $this->t('View Details'),
'url' => Url::fromRoute('ai_upgrade_assistant.update_history.details', ['update_id' => $update->id]),
];
$row['operations'] = [
'data' => [
'#type' => 'operations',
'#links' => $operations,
],
];
$rows[] = $row;
}
$build['table'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => $this->t('No updates found.'),
'#attributes' => ['class' => ['update-history-table']],
];
return $build;
}
/**
* Displays detailed information about a specific update.
*
* @param int $update_id
* The update ID.
*
* @return array
* A render array for the details page.
*/
public function details($update_id) {
$details = $this->historyService->getUpdateDetails($update_id);
if (!$details) {
return [
'#markup' => $this->t('Update not found.'),
];
}
$build = [];
$build['#attached']['library'][] = 'ai_upgrade_assistant/update_history';
// Update information
$build['info'] = [
'#type' => 'details',
'#title' => $this->t('Update Information'),
'#open' => TRUE,
'content' => [
'#theme' => 'table',
'#rows' => [
[
$this->t('Module'),
$details['update']['module_name'],
],
[
$this->t('From Version'),
$details['update']['from_version'],
],
[
$this->t('To Version'),
$details['update']['to_version'],
],
[
$this->t('Status'),
[
'data' => [
'#type' => 'status_message',
'#status' => $details['update']['status'],
],
],
],
[
$this->t('Started'),
$this->dateFormatter->format($details['update']['start_time'], 'long'),
],
[
$this->t('Completed'),
$details['update']['end_time'] ? $this->dateFormatter->format($details['update']['end_time'], 'long') : '-',
],
[
$this->t('Duration'),
$details['update']['end_time'] ? $this->formatDuration($details['update']['end_time'] - $details['update']['start_time']) : '-',
],
],
],
];
// Patches
if (!empty($details['patches'])) {
$build['patches'] = [
'#type' => 'details',
'#title' => $this->t('Generated Patches'),
'#open' => TRUE,
];
foreach ($details['patches'] as $patch) {
$build['patches'][$patch->id] = [
'#type' => 'details',
'#title' => $patch->file_path,
'content' => [
'#theme' => 'code',
'#code' => $patch->patch_content,
'#language' => 'diff',
],
'metadata' => [
'#theme' => 'item_list',
'#items' => [
$this->t('Status: @status', ['@status' => $patch->status]),
$this->t('AI Confidence: @confidence', ['@confidence' => number_format($patch->ai_confidence * 100, 1) . '%']),
$this->t('Created: @time', ['@time' => $this->dateFormatter->format($patch->created, 'short')]),
],
],
];
}
}
// Errors
if (!empty($details['errors'])) {
$build['errors'] = [
'#type' => 'details',
'#title' => $this->t('Errors'),
'#open' => TRUE,
];
foreach ($details['errors'] as $error) {
$build['errors'][$error->id] = [
'#type' => 'container',
'type' => [
'#markup' => '<strong>' . $error->error_type . '</strong>',
],
'message' => [
'#markup' => '<pre>' . $error->message . '</pre>',
],
'time' => [
'#markup' => $this->dateFormatter->format($error->timestamp, 'short'),
],
'stack_trace' => [
'#type' => 'details',
'#title' => $this->t('Stack Trace'),
'content' => [
'#markup' => '<pre>' . $error->stack_trace . '</pre>',
],
],
];
}
}
return $build;
}
/**
* Formats a duration in seconds into a human-readable string.
*
* @param int $seconds
* Number of seconds.
*
* @return string
* Formatted duration string.
*/
protected function formatDuration($seconds) {
if ($seconds < 60) {
return $this->t('@seconds seconds', ['@seconds' => $seconds]);
}
$minutes = floor($seconds / 60);
$seconds = $seconds % 60;
if ($minutes < 60) {
return $this->t('@minutes min @seconds sec', [
'@minutes' => $minutes,
'@seconds' => $seconds,
]);
}
$hours = floor($minutes / 60);
$minutes = $minutes % 60;
return $this->t('@hours hr @minutes min', [
'@hours' => $hours,
'@minutes' => $minutes,
]);
}
}
