1
0

home.php 8.1 KB

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