A project management app derived from Mind-Vision-Code
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

221 líneas
11KB

  1. <?php
  2. $taskColumns = [
  3. 'backlog' => 'Backlog',
  4. 'in-progress' => 'In progress',
  5. 'review' => 'In review',
  6. 'blocked' => 'Blocked',
  7. 'done' => 'Done',
  8. ];
  9. ?>
  10. <section class="stack">
  11. <div class="project-header">
  12. <div class="project-hero">
  13. <div class="project-top">
  14. <div>
  15. <span class="eyebrow"><?= e($project['code']) ?></span>
  16. <h1><?= e($project['name']) ?></h1>
  17. <p><?= e($project['description']) ?></p>
  18. </div>
  19. <div class="board-actions">
  20. <a class="button button-secondary" href="/projects">Back to projects</a>
  21. <a class="button button-ghost" href="/activity">Activity feed</a>
  22. </div>
  23. </div>
  24. <div class="badge-row">
  25. <span class="status-pill <?= e($project['health_class']) ?>"><?= e($project['status_label']) ?></span>
  26. <span class="status-pill is-blue"><?= e($project['throughput']) ?></span>
  27. <span class="status-pill is-amber">Owner: <?= e($project['owner_name']) ?></span>
  28. <span class="status-pill is-neutral">Last update: <?= e(format_date($project['latest_activity'], 'M j, Y · H:i')) ?></span>
  29. </div>
  30. <div class="progress"><span style="width: <?= e((string) $project['progress_percent']) ?>%"></span></div>
  31. <div class="project-meta-grid">
  32. <div class="meta-card"><span>Client</span><strong><?= e($project['client_name']) ?></strong></div>
  33. <div class="meta-card"><span>Budget</span><strong><?= e($project['budget_label']) ?></strong></div>
  34. <div class="meta-card"><span>Due date</span><strong><?= e($project['due_label']) ?></strong></div>
  35. <div class="meta-card"><span>Tasks</span><strong><?= e((string) $project['task_count']) ?> total / <?= e((string) $project['done_task_count']) ?> done</strong></div>
  36. </div>
  37. <div class="project-actions">
  38. <form method="post" action="/projects/<?= e((string) $project['id']) ?>/status" class="board-actions">
  39. <?= csrf_field() ?>
  40. <label class="field">
  41. <span>Project status</span>
  42. <select class="select" name="status">
  43. <?php foreach (['planned','active','at-risk','paused','done'] as $status): ?>
  44. <option value="<?= e($status) ?>" <?= $project['status'] === $status ? 'selected' : '' ?>><?= e(project_status_label($status)) ?></option>
  45. <?php endforeach; ?>
  46. </select>
  47. </label>
  48. <button class="button button-primary" type="submit">Update status</button>
  49. </form>
  50. </div>
  51. </div>
  52. </div>
  53. <div class="shell">
  54. <div class="board-shell">
  55. <div class="board-header">
  56. <div>
  57. <span class="eyebrow">Kanban board</span>
  58. <h2>Task flow</h2>
  59. </div>
  60. <div class="board-actions">
  61. <span class="tag is-neutral"><?= e((string) count($project['members'])) ?> team members</span>
  62. <span class="tag is-amber"><?= e((string) $project['blocked_task_count']) ?> blocked</span>
  63. <span class="tag is-red"><?= e((string) $project['overdue_task_count']) ?> overdue</span>
  64. </div>
  65. </div>
  66. <div class="board">
  67. <?php foreach ($taskColumns as $status => $label): ?>
  68. <section class="column">
  69. <header>
  70. <h3><?= e($label) ?></h3>
  71. <span class="count"><?= e((string) count($project['task_buckets'][$status])) ?></span>
  72. </header>
  73. <?php foreach ($project['task_buckets'][$status] as $task): ?>
  74. <article class="task-card" id="task-<?= e((string) $task['id']) ?>">
  75. <header>
  76. <div>
  77. <span class="mini-pill <?= e($task['status_class']) ?>"><?= e($task['priority']) ?></span>
  78. <h4><?= e($task['title']) ?></h4>
  79. </div>
  80. <span class="kicker"><?= e(format_date($task['due_date'])) ?></span>
  81. </header>
  82. <div class="task-body">
  83. <p><?= e($task['description']) ?></p>
  84. <div class="task-meta">
  85. <span class="mini-pill is-neutral">Assigned to <?= e($task['assignee']) ?></span>
  86. <span class="mini-pill is-blue"><?= e($task['estimate_hours'] !== null ? (string) $task['estimate_hours'] . 'h' : 'No estimate') ?></span>
  87. </div>
  88. </div>
  89. <footer>
  90. <form method="post" action="/tasks/<?= e((string) $task['id']) ?>/status" class="task-actions">
  91. <?= csrf_field() ?>
  92. <select class="select" name="status">
  93. <?php foreach ($taskStatusOptions as $option): ?>
  94. <option value="<?= e($option) ?>" <?= $task['status'] === $option ? 'selected' : '' ?>><?= e(task_status_label($option)) ?></option>
  95. <?php endforeach; ?>
  96. </select>
  97. <button class="button button-ghost" type="submit">Move</button>
  98. </form>
  99. </footer>
  100. </article>
  101. <?php endforeach; ?>
  102. </section>
  103. <?php endforeach; ?>
  104. </div>
  105. </div>
  106. <aside class="side-stack">
  107. <section class="panel">
  108. <div class="block-title">
  109. <div>
  110. <span class="eyebrow">Team</span>
  111. <h2>Project members</h2>
  112. </div>
  113. </div>
  114. <div class="members-list">
  115. <?php foreach ($project['members'] as $member): ?>
  116. <div class="member-chip">
  117. <div>
  118. <strong><?= e($member['full_name']) ?></strong>
  119. <small><?= e($member['role']) ?></small>
  120. </div>
  121. <span class="tag is-neutral"><?= e((string) $member['allocation_percent']) ?>%</span>
  122. </div>
  123. <?php endforeach; ?>
  124. </div>
  125. </section>
  126. <section class="panel">
  127. <div class="block-title">
  128. <div>
  129. <span class="eyebrow">Add task</span>
  130. <h2>New work item</h2>
  131. </div>
  132. </div>
  133. <?php if (!empty($taskErrors['_token'])): ?>
  134. <div class="alert alert-error"><?= e($taskErrors['_token'][0]) ?></div>
  135. <?php endif; ?>
  136. <form class="task-form" method="post" action="/projects/<?= e((string) $project['id']) ?>/tasks">
  137. <?= csrf_field() ?>
  138. <label class="field">
  139. <span>Task title</span>
  140. <input class="input" type="text" name="title" maxlength="140" value="<?= e($taskOld['title']) ?>" required>
  141. <?php if (!empty($taskErrors['title'])): ?><small class="field-error"><?= e($taskErrors['title'][0]) ?></small><?php endif; ?>
  142. </label>
  143. <label class="field">
  144. <span>Description</span>
  145. <textarea class="textarea" name="description" maxlength="800" required><?= e($taskOld['description']) ?></textarea>
  146. </label>
  147. <div class="form-grid">
  148. <label class="field">
  149. <span>Priority</span>
  150. <select class="select" name="priority">
  151. <?php foreach ($priorityOptions as $option): ?>
  152. <option value="<?= e($option) ?>" <?= $taskOld['priority'] === $option ? 'selected' : '' ?>><?= e(ucfirst($option)) ?></option>
  153. <?php endforeach; ?>
  154. </select>
  155. </label>
  156. <label class="field">
  157. <span>Status</span>
  158. <select class="select" name="status">
  159. <?php foreach ($taskStatusOptions as $option): ?>
  160. <option value="<?= e($option) ?>" <?= $taskOld['status'] === $option ? 'selected' : '' ?>><?= e(task_status_label($option)) ?></option>
  161. <?php endforeach; ?>
  162. </select>
  163. </label>
  164. <label class="field">
  165. <span>Assignee</span>
  166. <input class="input" type="text" name="assignee" maxlength="100" value="<?= e($taskOld['assignee']) ?>" required>
  167. </label>
  168. <label class="field">
  169. <span>Estimate hours</span>
  170. <input class="input" type="number" step="0.5" min="0" name="estimate_hours" value="<?= e($taskOld['estimate_hours']) ?>">
  171. </label>
  172. </div>
  173. <label class="field">
  174. <span>Due date</span>
  175. <input class="input" type="date" name="due_date" value="<?= e($taskOld['due_date']) ?>">
  176. </label>
  177. <button class="button button-primary" type="submit">Add task</button>
  178. </form>
  179. </section>
  180. <section class="panel">
  181. <div class="block-title">
  182. <div>
  183. <span class="eyebrow">Timeline</span>
  184. <h2>Recent activity</h2>
  185. </div>
  186. </div>
  187. <div class="list">
  188. <?php foreach ($activity as $item): ?>
  189. <div class="feed-item">
  190. <header>
  191. <strong><?= e($item['headline']) ?></strong>
  192. <span class="kicker"><?= e(format_date($item['created_at'], 'M j · H:i')) ?></span>
  193. </header>
  194. <p><?= e($item['detail']) ?></p>
  195. </div>
  196. <?php endforeach; ?>
  197. </div>
  198. </section>
  199. </aside>
  200. </div>
  201. </section>

Powered by TurnKey Linux.