import_upload.twig 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. {% extends "layout.twig" %}
  2. {% set errorMessages = {
  3. 'no_file': 'No file was uploaded.',
  4. 'too_big': 'The file is larger than 5 MB.',
  5. 'partial': 'The upload was interrupted. Try again.',
  6. 'upload_invalid': 'Upload validation failed.',
  7. 'not_xlsx': 'That doesn’t look like an .xlsx file.',
  8. 'parse_failed': 'Could not parse the workbook. Open it in Excel to confirm it’s not corrupted.',
  9. 'expired': 'Your previous import session expired. Please upload again.',
  10. 'nothing_selected':'No sheets were selected to import.',
  11. 'server': 'Server upload error.',
  12. 'size': 'File size is invalid.',
  13. 'unknown': 'Upload failed.',
  14. } %}
  15. {% block content %}
  16. <section class="max-w-2xl">
  17. <h1 class="text-2xl font-semibold tracking-tight">Import sprints from XLSX</h1>
  18. <p class="text-slate-600 mt-1 text-sm dark:text-slate-400">
  19. Upload the team’s <em>Tool_Sprint Planning</em> workbook. Each tab is parsed
  20. as one sprint; the next step lets you confirm targets, names, dates,
  21. and review the diff before committing.
  22. </p>
  23. {% if error != '' and errorMessages[error] is defined %}
  24. <div class="mt-4 rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:bg-red-900 dark:border-red-800 dark:text-red-200">
  25. {{ errorMessages[error] }}
  26. </div>
  27. {% endif %}
  28. <form method="post" action="/sprints/import" enctype="multipart/form-data"
  29. class="mt-6 space-y-4 rounded-lg border bg-white p-5 dark:bg-slate-800 dark:border-slate-700">
  30. <input type="hidden" name="_csrf" value="{{ csrfToken }}">
  31. <label class="block">
  32. <span class="text-sm text-slate-700 dark:text-slate-300">Workbook (.xlsx, max 5 MB)</span>
  33. <input type="file" name="xlsx" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" required
  34. class="mt-1 block w-full text-sm text-slate-700 file:mr-3 file:rounded-md file:border-0 file:bg-slate-900 file:text-white file:px-3 file:py-2 dark:text-slate-200 dark:file:bg-slate-700">
  35. </label>
  36. <details class="text-sm text-slate-600 dark:text-slate-400">
  37. <summary class="cursor-pointer select-none">How are cell colours mapped to status?</summary>
  38. <ul class="mt-2 ml-5 list-disc space-y-1">
  39. <li>Greens (e.g. Excel “Green”, light pastel green) → <strong>abgeschlossen</strong>.</li>
  40. <li>Yellows and oranges → <strong>gestartet</strong>.</li>
  41. <li>Reds → <strong>abgebrochen</strong>.</li>
  42. <li>White, blue, or no fill → <strong>zugewiesen</strong> (default).</li>
  43. </ul>
  44. <p class="mt-2">Workers and tasks are matched to existing rows by name (case-insensitive).
  45. Anything not yet in the database is created.</p>
  46. </details>
  47. <div class="flex gap-3 pt-2">
  48. <button type="submit"
  49. class="rounded-md bg-slate-900 text-white px-4 py-2 text-sm font-medium hover:bg-slate-800 dark:bg-slate-700 dark:hover:bg-slate-600">
  50. Upload &amp; preview
  51. </button>
  52. <a href="/" class="inline-flex items-center rounded-md border border-slate-300 bg-white text-slate-700 px-4 py-2 text-sm hover:bg-slate-100 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-700">
  53. Cancel
  54. </a>
  55. </div>
  56. </form>
  57. </section>
  58. {% endblock %}