feat: implement export functionality for projects and scenarios with CSV and Excel support

This commit is contained in:
2025-11-10 18:32:24 +01:00
parent 4b33a5dba3
commit 43b1e53837
15 changed files with 906 additions and 133 deletions

View File

@@ -0,0 +1,10 @@
{% macro toast(id, hidden=True, level="info", message="") %}
<div id="{{ id }}" class="toast toast--{{ level }}{% if hidden %} hidden{% endif %}" role="alert">
<span class="toast__icon" aria-hidden="true"></span>
<p class="toast__message">{{ message }}</p>
<button type="button" class="toast__close" data-toast-close>
<span aria-hidden="true">×</span>
<span class="sr-only">Dismiss</span>
</button>
</div>
{% endmacro %}

View File

@@ -0,0 +1,17 @@
{% from "partials/components.html" import table_container %}
{% call table_container("import-preview-container", hidden=True, aria_label="Import preview table", heading=table_heading or "Preview Rows") %}
<thead>
<tr>
<th scope="col">Row</th>
<th scope="col">Status</th>
<th scope="col">Issues</th>
{% for column in columns %}
<th scope="col">{{ column }}</th>
{% endfor %}
</tr>
</thead>
<tbody data-import-preview-body>
<!-- Rows injected via JavaScript -->
</tbody>
{% endcall %}

View File

@@ -0,0 +1,25 @@
{% from "partials/components.html" import feedback %}
<section class="import-upload" data-import-upload>
<header class="import-upload__header">
<h3>{{ title or "Bulk Import" }}</h3>
{% if description %}<p class="import-upload__description">{{ description }}</p>{% endif %}
</header>
<div class="import-upload__dropzone" data-import-dropzone>
<span class="icon-upload" aria-hidden="true"></span>
<p>Drag & drop CSV/XLSX files here or</p>
<label class="btn secondary">
Browse
<input type="file" name="import-file" accept=".csv,.xlsx" hidden />
</label>
<p class="import-upload__hint">Maximum size {{ max_size_hint or "10 MB" }}. UTF-8 encoding required.</p>
</div>
<div class="import-upload__actions">
<button type="button" class="btn primary" data-import-upload-trigger disabled>Upload & Preview</button>
<button type="button" class="btn" data-import-reset hidden>Reset</button>
</div>
{{ feedback("import-upload-feedback", hidden=True, role="alert") }}
</section>