1
0

home.twig 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. {% extends "layout.twig" %}
  2. {% block content %}
  3. <section class="space-y-6">
  4. {% if authError|default(false) %}
  5. <div class="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">
  6. Sign-in failed. Check the server logs or the audit log for details.
  7. </div>
  8. {% endif %}
  9. {% if currentUser is null %}
  10. <div class="rounded-lg border bg-white p-6 dark:bg-slate-800 dark:border-slate-700">
  11. <h1 class="text-2xl font-semibold tracking-tight">Sprint Planner</h1>
  12. <p class="text-slate-600 mt-2 max-w-prose dark:text-slate-400">
  13. Sign in with your Microsoft account to get started. The first person
  14. to sign in becomes the admin automatically.
  15. </p>
  16. <div class="mt-4 flex flex-wrap items-center gap-3">
  17. {% if oidcConfigured %}
  18. <a href="/auth/login"
  19. class="inline-flex items-center gap-2 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">
  20. Sign in with Microsoft
  21. </a>
  22. {% endif %}
  23. {% if localAdminEnabled %}
  24. <a href="/auth/local"
  25. class="inline-flex items-center gap-2 rounded-md border border-slate-300 bg-white text-slate-700 px-4 py-2 text-sm font-medium hover:bg-slate-100 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-700">
  26. Sign in as local admin
  27. </a>
  28. {% endif %}
  29. {% if not oidcConfigured and not localAdminEnabled %}
  30. <span class="inline-block rounded-md bg-slate-100 text-slate-600 px-3 py-2 text-sm dark:bg-slate-700 dark:text-slate-300">
  31. No sign-in method configured. Set <code>ENTRA_*</code> or
  32. <code>LOCAL_ADMIN_*</code> in <code>.env</code>.
  33. </span>
  34. {% endif %}
  35. </div>
  36. </div>
  37. {% else %}
  38. <div class="flex items-end justify-between gap-4">
  39. <div>
  40. <h1 class="text-2xl font-semibold tracking-tight">Sprints</h1>
  41. <p class="text-slate-600 mt-1 text-sm dark:text-slate-400">
  42. {{ sprintRows|length }} sprint{{ sprintRows|length == 1 ? '' : 's' }}.
  43. </p>
  44. </div>
  45. {% if currentUser.isAdmin %}
  46. <a href="/sprints/new"
  47. class="inline-flex items-center gap-2 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">
  48. New sprint
  49. </a>
  50. {% endif %}
  51. </div>
  52. <div class="rounded-lg border bg-white overflow-hidden dark:bg-slate-800 dark:border-slate-700">
  53. {% if sprintRows is empty %}
  54. <div class="p-8 text-center text-slate-500 text-sm dark:text-slate-400">
  55. No sprints yet.
  56. {% if currentUser.isAdmin %}
  57. <a href="/sprints/new" class="text-blue-700 hover:underline dark:text-blue-400 dark:hover:text-blue-300">Create the first one</a>.
  58. {% endif %}
  59. </div>
  60. {% else %}
  61. <table class="min-w-full text-sm">
  62. <thead class="bg-slate-50 text-slate-600 text-xs uppercase tracking-wider dark:bg-slate-700 dark:text-slate-300">
  63. <tr>
  64. <th class="text-left px-4 py-2 font-semibold">Name</th>
  65. <th class="text-left px-4 py-2 font-semibold">Dates</th>
  66. <th class="text-right px-4 py-2 font-semibold">Workers</th>
  67. <th class="text-right px-4 py-2 font-semibold">Tasks</th>
  68. <th class="text-right px-4 py-2 font-semibold">Reserve</th>
  69. <th class="text-left px-4 py-2 font-semibold">Status</th>
  70. </tr>
  71. </thead>
  72. <tbody class="divide-y divide-slate-100 dark:divide-slate-700">
  73. {% for row in sprintRows %}
  74. {% set s = row.sprint %}
  75. <tr class="hover:bg-slate-50 cursor-pointer dark:hover:bg-slate-700"
  76. data-href="/sprints/{{ s.id }}">
  77. <td class="px-4 py-2 font-medium">
  78. <a href="/sprints/{{ s.id }}" class="hover:underline">{{ s.name }}</a>
  79. </td>
  80. <td class="px-4 py-2 text-slate-600 dark:text-slate-400">
  81. {{ s.startDate }} – {{ s.endDate }}
  82. </td>
  83. <td class="px-4 py-2 text-right font-mono">{{ row.nWorkers }}</td>
  84. <td class="px-4 py-2 text-right font-mono">{{ row.nTasks }}</td>
  85. <td class="px-4 py-2 text-right font-mono">
  86. {{ (s.reserveFraction * 100)|number_format(0) }}%
  87. </td>
  88. <td class="px-4 py-2">
  89. {% if s.isArchived %}
  90. <span class="inline-block px-2 py-0.5 text-xs bg-slate-100 text-slate-600 rounded dark:bg-slate-700 dark:text-slate-300">archived</span>
  91. {% else %}
  92. <span class="inline-block px-2 py-0.5 text-xs bg-green-100 text-green-800 rounded dark:bg-green-900 dark:text-green-200">active</span>
  93. {% endif %}
  94. </td>
  95. </tr>
  96. {% endfor %}
  97. </tbody>
  98. </table>
  99. {% endif %}
  100. </div>
  101. {% endif %}
  102. {% if currentUser is null or currentUser.isAdmin %}
  103. <details class="rounded-lg border bg-white p-4 dark:bg-slate-800 dark:border-slate-700">
  104. <summary class="text-sm font-semibold text-slate-700 uppercase tracking-wider cursor-pointer dark:text-slate-200">Runtime</summary>
  105. <dl class="mt-3 grid grid-cols-[max-content_1fr] gap-x-6 gap-y-1 text-sm">
  106. <dt class="text-slate-500 dark:text-slate-400">PHP</dt>
  107. <dd class="font-mono">{{ constant('PHP_VERSION') }}</dd>
  108. <dt class="text-slate-500 dark:text-slate-400">APP_ENV</dt>
  109. <dd class="font-mono">{{ appEnv }}</dd>
  110. <dt class="text-slate-500 dark:text-slate-400">SQLite file</dt>
  111. <dd class="font-mono break-all">{{ dbPath }}</dd>
  112. <dt class="text-slate-500 dark:text-slate-400">Schema version</dt>
  113. <dd class="font-mono">{{ schemaVersion }}</dd>
  114. <dt class="text-slate-500 dark:text-slate-400">OIDC</dt>
  115. <dd class="font-mono">{{ oidcConfigured ? 'configured' : 'not configured' }}</dd>
  116. <dt class="text-slate-500 dark:text-slate-400">Local admin</dt>
  117. <dd class="font-mono">{{ localAdminEnabled ? 'enabled' : 'disabled' }}</dd>
  118. </dl>
  119. <p class="mt-4 text-xs text-slate-500 dark:text-slate-400">
  120. Liveness probe: <a class="text-blue-700 hover:underline dark:text-blue-400 dark:hover:text-blue-300" href="/healthz"><code>/healthz</code></a>
  121. </p>
  122. </details>
  123. {% endif %}
  124. </section>
  125. {% endblock %}