Layout for export list

This commit is contained in:
Julien Fastré 2025-04-14 10:58:52 +02:00
parent 35f5501489
commit 2842548c17
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
4 changed files with 111 additions and 33 deletions

View File

@ -11,14 +11,23 @@ declare(strict_types=1);
namespace Chill\MainBundle\Controller; namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Repository\ExportGenerationRepository;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Twig\Environment; use Twig\Environment;
final readonly class ExportIndexController final readonly class ExportIndexController
{ {
public function __construct(private ExportManager $exportManager, private Environment $twig) {} public function __construct(
private ExportManager $exportManager,
private Environment $twig,
private ExportGenerationRepository $exportGenerationRepository,
private Security $security,
) {}
/** /**
* Render the list of available exports. * Render the list of available exports.
@ -26,11 +35,22 @@ final readonly class ExportIndexController
#[Route(path: '/{_locale}/exports/', name: 'chill_main_export_index')] #[Route(path: '/{_locale}/exports/', name: 'chill_main_export_index')]
public function indexAction(ExportController $exportController): Response public function indexAction(ExportController $exportController): Response
{ {
$user = $this->security->getUser();
if (!$user instanceof User) {
throw new AccessDeniedHttpException('Only regular user can see this page');
}
$exports = $this->exportManager->getExportsGrouped(true); $exports = $this->exportManager->getExportsGrouped(true);
$lastExecutions = [];
foreach ($this->exportManager->getExports() as $alias => $export) {
$lastExecutions[$alias] = $this->exportGenerationRepository->findExportGenerationByAliasAndUser($alias, $user, 5);
}
return new Response( return new Response(
$this->twig->render('@ChillMain/Export/layout.html.twig', [ $this->twig->render('@ChillMain/Export/layout.html.twig', [
'grouped_exports' => $exports, 'grouped_exports' => $exports,
'last_executions' => $lastExecutions,
]), ]),
); );
} }

View File

@ -14,6 +14,8 @@ namespace Chill\MainBundle\Repository;
use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\MainBundle\Entity\ExportGeneration; use Chill\MainBundle\Entity\ExportGeneration;
use Chill\MainBundle\Entity\SavedExport;
use Chill\MainBundle\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@ -37,4 +39,38 @@ class ExportGenerationRepository extends ServiceEntityRepository implements Asso
->getQuery() ->getQuery()
->getOneOrNullResult(); ->getOneOrNullResult();
} }
/**
* @return list<ExportGeneration>
*/
public function findExportGenerationByAliasAndUser(string $alias, User $user, int $limit = 100, int $offset = 0): array
{
return $this->createQueryBuilder('e')
->where('e.createdBy = :user')
->andWhere('e.exportAlias LIKE :alias')
->orderBy('e.createdAt', 'DESC')
->setParameter('user', $user)
->setParameter('alias', $alias)
->setFirstResult($offset)
->setMaxResults($limit)
->getQuery()
->getResult();
}
/**
* @return list<ExportGeneration>
*/
public function findExportGenerationBySavedExportAndUser(SavedExport $savedExport, User $user, int $limit = 100, int $offset = 0): array
{
return $this->createQueryBuilder('e')
->where('e.createdBy = :user')
->andWhere('e.savedExport = :savedExport')
->orderBy('e.createdAt', 'DESC')
->setParameter('user', $user)
->setParameter('savedExport', $savedExport)
->setFirstResult($offset)
->setMaxResults($limit)
->getQuery()
->getResult();
}
} }

View File

@ -1,5 +1,5 @@
{# {#
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
<info@champs-libres.coop> / <http://www.champs-libres.coop> <info@champs-libres.coop> / <http://www.champs-libres.coop>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -20,6 +20,49 @@
{% block title %}{{ 'Exports list'|trans }}{% endblock %} {% block title %}{{ 'Exports list'|trans }}{% endblock %}
{% block css %}
{{ parent() }}
<style lang="css">
.export-title {
margin-top: 2rem;
margin-bottom: 1rem;
}
</style>
{% endblock %}
{% macro render_export_card(export, export_alias, generations) %}
<div class="col">
<div class="card h-100">
<div class="card-body">
<h2 class="card-title">{{ export.title|trans }}</h2>
<p class="card-text my-3">{{ export.description|trans }}</p>
</div>
{% if generations|length > 0 %}
<ul class="list-group list-group-flush">
{% for generation in generations %}
<li class="list-group-item">
<a href="{{ chill_path_add_return_path('chill_main_export-generation_wait', {'id': generation.id}) }}">{{ generation.createdAt|format_datetime('short', 'short') }}</a>
{% if generation.status == 'pending' %}
&nbsp;<span class="badge bg-info">{{ 'export.generation.Export generation is pending_short'|trans }}</span>
{% elseif generation.status == 'failure' %}
&nbsp;<span class="badge bg-warning">{{ 'export.generation.Error_short'|trans }}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
<div class="card-footer">
<ul class="record_actions slim">
<li>
<a class="btn btn-submit" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
{{ 'Create an export'|trans }}
</a>
</li>
</ul>
</div>
</div>
</div>
{% endmacro %}
{% block content %} {% block content %}
@ -28,45 +71,23 @@
<div class="col-md-10 exports-list"> <div class="col-md-10 exports-list">
<div class="container mt-4"> <div class="container mt-4">
{% for group, exports in grouped_exports %}{% if group != '_' %} {% for group, exports in grouped_exports %}{% if group != '_' %}
<h2 class="display-6">{{ group|trans }}</h2> <h1 class="display-6 export-title">{{ group|trans }}</h1>
<div class="row flex-bloc"> <div class="row row-cols-1 row-cols-md-3 g-2">
{% for export_alias, export in exports %} {% for export_alias, export in exports %}
<div class="item-bloc"> {{ _self.render_export_card(export, export_alias, last_executions[export_alias]) }}
<div class="item-row card-body">
<h2 class="card-title">{{ export.title|trans }}</h2>
<p class="card-text my-3">{{ export.description|trans }}</p>
<p>
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
{{ 'Create an export'|trans }}
</a>
</p>
</div>
</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %}{% endfor %} {% endif %}{% endfor %}
{% if grouped_exports|keys|length > 1 and grouped_exports['_']|length > 0 %} {% if grouped_exports|keys|length > 1 and grouped_exports['_']|length > 0 %}
<h2 class="display-6">{{ 'Ungrouped exports'|trans }}</h2> <h2 class="display-6 export-title">{{ 'Ungrouped exports'|trans }}</h2>
{% endif %} {% endif %}
<div class="row flex-bloc"> <div class="row row-cols-1 row-cols-md-3 g-2">
{% for export_alias,export in grouped_exports['_'] %} {% for export_alias,export in grouped_exports['_'] %}
{{ _self.render_export_card(export, export_alias, last_executions[export_alias]) }}
<div class="item-bloc">
<div class="item-row card-body">
<h2 class="card-title">{{ export.title|trans }}</h2>
<p class="card-text my-3">{{ export.description|trans }}</p>
<p>
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
{{ 'Create an export'|trans }}
</a>
</p>
</div>
</div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -722,6 +722,7 @@ export:
Come back later: Retour à l'index Come back later: Retour à l'index
Too many retries: Le nombre de vérification de la disponibilité de l'export a échoué. Essayez de recharger la page. Too many retries: Le nombre de vérification de la disponibilité de l'export a échoué. Essayez de recharger la page.
Error while generating export: Erreur interne lors de la génération de l'export Error while generating export: Erreur interne lors de la génération de l'export
Error_short: En erreur
Export ready: L'export est prêt à être téléchargé Export ready: L'export est prêt à être téléchargé
address_helper: address_helper:
id: Identifiant de l'adresse id: Identifiant de l'adresse