Partage d'export enregistré et génération asynchrone des exports

This commit is contained in:
2025-07-08 13:53:25 +00:00
parent c4cc0baa8e
commit 8bc16dadb0
447 changed files with 14134 additions and 3854 deletions

View File

@@ -446,11 +446,31 @@ Toutes les classes btn-* de bootstrap sont fonctionnelles
</div>
<div class="row">
<h1>Badges</h1>
<h1>Entity badges</h1>
<span class="badge-accompanying-work-type-simple">Action d'accompagnement</span>
<span class="badge-activity-type-simple">Type d'échange</span>
<span class="badge-calendar-simple">Rendez-vous</span>
</div>
<h1>Badges</h1>
<p>
<span class="badge bg-primary">Primary</span>
<span class="badge bg-secondary">Secondary</span>
<span class="badge bg-success">Success</span>
<span class="badge bg-danger">Danger</span>
<span class="badge bg-warning">Warning</span>
<span class="badge bg-info">Info</span>
<span class="badge bg-light">Light</span>
<span class="badge bg-dark">Dark</span>
<span class="badge bg-chill-blue">chill-blue</span>
<span class="badge bg-chill-green">chill-green</span>
<span class="badge bg-chill-yellow">chill-yellow</span>
<span class="badge bg-chill-orange">chill-orange</span>
<span class="badge bg-chill-red">chill-red</span>
<span class="badge bg-chill-beige">chill-beige</span>
</p>
{% endblock %}

View File

@@ -1,12 +1,14 @@
<ul class="nav nav-pills justify-content-center">
<li class="nav-item">
<a href="{{ chill_path_forward_return_path('chill_main_export_index') }}" class="nav-link {% if current == 'common' %}active{% endif %}">
{{ 'Exports list'|trans }}
</a>
</li>
{% if is_granted('CHILL_MAIN_COMPOSE_EXPORT') %}
<li class="nav-item">
<a href="{{ chill_path_forward_return_path('chill_main_export_index') }}" class="nav-link {% if current == 'common' %}active{% endif %}">
{{ 'Exports list'|trans }}
</a>
</li>
{% endif %}
<li class="nav-item">
<a href="{{ chill_path_forward_return_path('chill_main_export_saved_list_my') }}" class="nav-link {% if current == 'my' %}active{% endif %}">
{{ 'saved_export.My saved exports'|trans }}
{{ 'saved_export.Saved exports'|trans }}
</a>
</li>
</ul>
</ul>

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>
*
* This program is free software: you can redistribute it and/or modify
@@ -20,6 +20,49 @@
{% 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 %}
@@ -28,45 +71,23 @@
<div class="col-md-10 exports-list">
<div class="container mt-4">
{% for group, exports in grouped_exports %}{% if group != '_' %}
<h2 class="display-6">{{ group|trans }}</h2>
<div class="row flex-bloc">
<h1 class="display-6 export-title">{{ group|trans }}</h1>
<div class="row row-cols-1 row-cols-md-3 g-2">
{% for export_alias, export in exports %}
<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>
{{ _self.render_export_card(export, export_alias, last_executions[export_alias]) }}
{% endfor %}
</div>
{% endif %}{% endfor %}
{% 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 %}
<div class="row flex-bloc">
<div class="row row-cols-1 row-cols-md-3 g-2">
{% for export_alias,export in grouped_exports['_'] %}
<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>
{{ _self.render_export_card(export, export_alias, last_executions[export_alias]) }}
{% endfor %}
</div>
</div>

View File

@@ -40,15 +40,15 @@
<h3 class="m-3">{{ 'Center'|trans }}</h3>
{{ form_widget(form.centers.center) }}
{{ form_widget(form.centers.centers) }}
<div class="mb-3 mt-3">
<input id="toggle-check-all" class="btn btn-misc" type= "button" onclick='uncheckAll(this)' value="{{ 'uncheck all centers'|trans|e('html_attr') }}"/>
</div>
{% if form.centers.regroupment is defined %}
{% if form.centers.regroupments is defined %}
<h3 class="m-3">{{ 'Pick aggregated centers'|trans }}</h3>
{{ form_widget(form.centers.regroupment) }}
{{ form_widget(form.centers.regroupments) }}
{% endif %}
</section>

View File

@@ -0,0 +1,61 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('page_download_exports') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('page_download_exports') }}
{% endblock %}
{% block title exportGeneration.linkedToSavedExport ? exportGeneration.savedExport.title : ('Download export'|trans) %}
{% block content %}
<h1>{{ block('title') }}</h1>
<div id="app"
data-export-generation-id="{{ exportGeneration.id | escape('html_attr') }}"
data-export-generation-date="{{ exportGeneration.createdAt.format('Ymd-His') }}"
data-export-title="{{ export.title|trans }}"
></div>
<ul class="sticky-form-buttons record_actions">
<li class="cancel">
<a href="{{ chill_return_path_or('chill_main_export_saved_list_my') }}" class="btn btn-cancel">
{{ 'export.generation.Come back later'|trans|chill_return_path_label }}
</a>
</li>
{% if not exportGeneration.linkedToSavedExport %}
<li>
<a href="{{ chill_path_add_return_path('chill_main_export_saved_create_from_export_generation', {'id': exportGeneration.id}) }}" class="btn btn-save">
{{ 'Save'|trans }}
</a>
</li>
{% else %}
{% if exportGeneration.configurationDifferentFromSavedExport %}
<li>
<div class="dropdown">
<button class="btn btn-save dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">{{ 'Save'|trans }}</button>
<ul class="dropdown-menu dropdown-menu-end">
<li class="dropdown-item">
<a href="{{ chill_path_add_return_path('chill_main_export_saved_create_from_export_generation', {'id': exportGeneration.id, 'title': exportGeneration.savedExport.title ~ ' (' ~ 'saved_export.Duplicated'|trans ~ ' ' ~ null|format_datetime('short', 'medium') ~ ')'}) }}" class="btn">
<i class="bi bi-copy"></i> {{ 'saved_export.Save to new saved export'|trans }}
</a>
</li>
{% if is_granted('CHILL_MAIN_EXPORT_SAVED_EDIT', exportGeneration.savedExport) %}
<li class="dropdown-item">
<form method="POST" action="{{ path('chill_main_export_saved_options_edit', {'savedExport': exportGeneration.savedExport.id, 'exportGeneration': exportGeneration.id }) }}">
<button type="submit" class="btn">
<i class="bi bi-floppy"></i> {{ 'saved_export.Update current saved export'|trans }}
</button>
</form>
</li>
{% endif %}
</ul>
</div>
</li>
{% endif %}
{% endif %}
</ul>
{% endblock content %}

View File

@@ -2,6 +2,16 @@
{% block title %}{{ 'saved_export.Edit'|trans }}{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block content %}
<div class="col-10">
<h1>{{ block('title') }}</h1>
@@ -10,9 +20,13 @@
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{% if form.share is defined %}
{{ form_row(form.share) }}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ chill_return_path_or('chill_main_homepage') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
<a href="{{ chill_return_path_or('chill_main_export_saved_list_my') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
</li>
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
@@ -20,4 +34,4 @@
</ul>
{{ form_end(form) }}
</div>
{% endblock %}
{% endblock %}

View File

@@ -1,6 +1,88 @@
{% extends "@ChillMain/layout.html.twig" %}
{% block title %}{{ 'saved_export.My saved exports'|trans }}{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_saved_export_button') }}
<style lang="css">
.export-title {
margin-top: 2rem;
margin-bottom: 1rem;
}
</style>
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_saved_export_button') }}
{% endblock %}
{% block title %}{{ 'saved_export.Saved exports'|trans }}{% endblock %}
{% macro render_export_card(saved, export, export_alias, generations) %}
<div class="col">
<div class="card h-100">
<div class="card-header">
{{ export.title|trans }}
</div>
<div class="card-body">
<h2 class="card-title">{{ saved.title }}</h2>
{% if app.user is same as saved.user %}
<p class="card-text tags">
{% if app.user is same as saved.user %}<span class="badge bg-primary">{{ 'saved_export.Owner'|trans }}</span>{% endif %}
{% if saved.isShared() %}<span class="badge bg-info">{{ 'saved_export.Shared with others'|trans }}</span>{% endif %}
</p>
{% else %}
<p class="card-text tags">
Partagé par <span class="badge-user">{{ saved.user|chill_entity_render_box }}</span>
</p>
{% endif %}
<p class="card-text my-3">{{ saved.description|chill_markdown_to_html }}</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>
<div class="" data-generate-export-button data-saved-export-uuid="{{ saved.id|escape('html_attr') }}"></div>
</li>
<li>
<div class="dropdown">
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ 'Actions'|trans }}
</button>
<ul class="dropdown-menu">
{% if is_granted('CHILL_MAIN_EXPORT_SAVED_EDIT', saved) %}
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': saved.id }) }}" class="dropdown-item"><i class="fa fa-pencil"></i> {{ 'saved_export.update_title_and_description'|trans }}</a></li>
{% endif %}
{# reminder: the controller already checked that the user can generate saved exports #}
<li><a href="{{ chill_path_add_return_path('chill_main_export_new', {'alias': saved.exportAlias,'from_saved': saved.id }) }}" class="dropdown-item"><i class="fa fa-pencil"></i> {{ 'saved_export.update_filters_aggregators_and_execute'|trans }}</a></li>
{% if is_granted('CHILL_MAIN_EXPORT_SAVED_DUPLICATE', saved) %}
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_duplicate', {'id': saved.id}) }}" class="dropdown-item"><i class="fa fa-copy"></i> {{ 'saved_export.Duplicate'|trans }}</a></li>
{% endif %}
{% if is_granted('CHILL_MAIN_EXPORT_SAVED_DELETE', saved) %}
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': saved.id }) }}" class="dropdown-item"><i class="fa fa-trash"></i> {{ 'Delete'|trans }}</a></li>
{% endif %}
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
{% endmacro %}
{% block content %}
<div class="col-md-10 exports-list">
@@ -8,6 +90,7 @@
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }}
<div class="container mt-4">
{{ filter|chill_render_filter_order_helper }}
{% if total == 0 %}
<p class="chill-no-data-statement" >{{ 'saved_export.Any saved export'|trans }}</p>
@@ -15,71 +98,23 @@
{% for group, saveds in grouped_exports %}
{% if group != '_' %}
<h2 class="display-6">{{ group }}</h2>
<div class="row flex-bloc">
<h1 class="display-6 export-title">{{ group }}</h1>
<div class="row row-cols-1 row-cols-md-3 g-2">
{% for s in saveds %}
<div class="item-bloc">
<div class="item-row card-body">
<p class="card-subtitle"><strong>{{ s.export.title|trans }}</strong></p>
<h2 class="card-title">{{ s.saved.title }}</h2>
<div class="createdBy">{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}</div>
<div class="card-text my-3">
{{ s.saved.description|chill_markdown_to_html }}
</div>
<div>
<ul class="record_actions">
<li>
<div class="dropdown">
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ 'Actions'|trans }}
</button>
<ul class="dropdown-menu">
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="dropdown-item"><i class="fa fa-pencil"></i> {{ 'saved_export.update_title_and_description'|trans }}</a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_new', {'alias': s.saved.exportAlias,'from_saved': s.saved.id }) }}" class="dropdown-item"><i class="fa fa-pencil"></i> {{ 'saved_export.update_filters_aggregators_and_execute'|trans }}</a></li>
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="dropdown-item"><i class="fa fa-cog"></i> {{ 'saved_export.execute'|trans }}</a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="dropdown-item"><i class="fa fa-trash"></i> {{ 'Delete'|trans }}</a></li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
{{ _self.render_export_card(s.saved, s.export, s.saved.exportAlias, last_executions[s.saved.id.toString()]) }}
{% endfor %}
</div>
{% endif %}
{% endfor %}
{% if grouped_exports|keys|length > 1 and grouped_exports['_']|default([])|length > 0 %}
<h2 class="display-6">{{ 'Ungrouped exports'|trans }}</h2>
<h2 class="display-6 export-title">{{ 'Ungrouped exports'|trans }}</h2>
{% endif %}
<div class="row flex-bloc">
{% for saveds in grouped_exports['_']|default([]) %}
{% for s in saveds %}
<div class="item-bloc">
<div class="item-row card-body">
<p class="card-subtitle"><strong>{{ s.export.title|trans }}</strong></p>
<h2 class="card-title">{{ s.saved.title }}</h2>
<div class="createdBy">{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}</div>
<div class="card-text my-3">
{{ s.saved.description|chill_markdown_to_html }}
</div>
<div>
<ul class="record_actions">
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="btn btn-delete"></a></li>
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="btn btn-edit"></a></li>
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="btn btn-action"><i class="fa fa-cog"></i></a></li>
</ul>
</div>
</div>
</div>
{{ _self.render_export_card(s.saved, s.export, s.saved.exportAlias, last_executions[s.saved.id.toString()]) }}
{% endfor %}
{% endfor %}
</div>

View File

@@ -2,14 +2,35 @@
{% block title %}{{ 'saved_export.New'|trans }}{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block content %}
<div class="col-10">
<h1>{{ block('title') }}</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
{% if showWarningAutoGeneratedDescription|default(false) %}
<div class="alert alert-info" role="alert">
{{ 'saved_export.Alert auto generated description'|trans }}
</div>
{% endif %}
{{ form_row(form.description) }}
{% if form.share is defined %}
{{ form_row(form.share) }}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ chill_return_path_or('chill_main_homepage') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
@@ -20,4 +41,4 @@
</ul>
{{ form_end(form) }}
</div>
{% endblock %}
{% endblock %}

View File

@@ -10,19 +10,19 @@
{% for flashMessage in app.session.flashbag.get('success') %}
<div class="col-8 alert alert-success flash_message">
<span>{{ flashMessage|raw }}</span>
<span>{{ flashMessage|trans }}</span>
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('error') %}
<div class="col-8 alert alert-danger flash_message">
<span>{{ flashMessage|raw }}</span>
<span>{{ flashMessage|trans }}</span>
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="col-8 alert alert-warning flash_message">
<span>{{ flashMessage|raw }}</span>
<span>{{ flashMessage|trans }}</span>
</div>
{% endfor %}