tasks.html 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <pstm-uri>/tasks</pstm-uri>
  5. <pstm-template>main</pstm-template>
  6. <script>
  7. // The task queue. Plan 12: the filters (status / project / goal)
  8. // run CLIENT-SIDE — the Statum entrypoint fetch never carries the
  9. // page's own query string to the server, so selects filter the
  10. // rendered rows directly (window.taskFilters + taskRowVisible)
  11. // and survive re-renders; the create form gains the mode select
  12. // (with descriptions) and the auto-enqueue-after dropdown (the
  13. // global human-task list; goal tasks are the goal agent's to
  14. // sequence).
  15. if (window.statum) {
  16. (function () {
  17. 'use strict';
  18. window.taskFilters = window.taskFilters || {};
  19. window.taskRowVisible = function (row) {
  20. var filters = window.taskFilters || {};
  21. if (filters.status && filters.status !== 'all'
  22. && row.status !== filters.status) {
  23. return false;
  24. }
  25. if (filters.project && filters.project > 0
  26. && String(row.project_id) !== String(filters.project)) {
  27. return false;
  28. }
  29. if (filters.goal) {
  30. if (filters.goal === 'standalone' && row.goal_id > 0) {
  31. return false;
  32. }
  33. if (filters.goal !== 'standalone'
  34. && String(row.goal_id) !== String(filters.goal)) {
  35. return false;
  36. }
  37. }
  38. return true;
  39. };
  40. window.setTaskFilter = function (name, value) {
  41. window.taskFilters[name] = value;
  42. var tasks = statum.read('tasks');
  43. if (tasks && tasks.refresh) {
  44. statum.act(tasks.refresh).catch(function () { });
  45. } else {
  46. // No sealed refresh on this build: force a render
  47. // cycle through the pulse listener if present.
  48. document.body.setAttribute('data-filter-bump', String(Date.now()));
  49. }
  50. };
  51. })();
  52. }
  53. </script>
  54. </head>
  55. <body>
  56. <div class="page">
  57. <h1>Tasks</h1>
  58. <form class="inline" onsubmit="return false">
  59. <label for="filter-status">Status</label>
  60. <select id="filter-status" onchange="window.setTaskFilter('status', this.value)">
  61. <option value="all">all</option>
  62. <option value="draft">draft</option>
  63. <option value="queued">queued</option>
  64. <option value="assigned">assigned</option>
  65. <option value="working">working</option>
  66. <option value="blocked">blocked</option>
  67. <option value="suspended">suspended</option>
  68. <option value="done">done</option>
  69. <option value="failed">failed</option>
  70. </select>
  71. <label for="filter-project">Project</label>
  72. <select id="filter-project" onchange="window.setTaskFilter('project', this.value)">
  73. <option value="0">all</option>
  74. <option stm-for-project-in="tasks.projects" stm-attribute.value="project.id"
  75. stm-text="project.name">project</option>
  76. </select>
  77. <label for="filter-goal">Goal</label>
  78. <select id="filter-goal" onchange="window.setTaskFilter('goal', this.value)">
  79. <option value="all">all</option>
  80. <option value="standalone">standalone only</option>
  81. <option stm-for-goal-in="tasks.goal_options" stm-attribute.value="goal.id"
  82. stm-text="goal.title">goal</option>
  83. </select>
  84. <span class="muted">— filters apply instantly</span>
  85. </form>
  86. <details class="history-expander">
  87. <summary><strong>New task</strong></summary>
  88. <form stm-action="tasks.create">
  89. <div class="form-row"><label for="task-project">Project</label>
  90. <select id="task-project" name="project_id" required>
  91. <option stm-for-project-in="tasks.projects" stm-attribute.value="project.id"
  92. stm-text="project.name">project</option>
  93. </select></div>
  94. <div class="form-row"><label for="task-title">Title</label>
  95. <input type="text" id="task-title" name="title" required></div>
  96. <div class="form-row"><label for="task-mode">Mode</label>
  97. <select id="task-mode" name="mode">
  98. <option value="implement" selected>implement — build the change on a task branch</option>
  99. <option value="investigate">investigate — explore and report, no code changes</option>
  100. <option value="review">review — read and critique existing work</option>
  101. <option value="test">test — write and run tests</option>
  102. </select></div>
  103. <div class="form-row"><label for="task-description">Mandate</label>
  104. <textarea id="task-description" name="description" rows="4"
  105. placeholder="What the agent must accomplish (the mandate)"></textarea></div>
  106. <div class="form-row"><label for="task-priority">Priority</label>
  107. <select id="task-priority" name="priority">
  108. <option value="1">1 — highest</option>
  109. <option value="2">2</option>
  110. <option value="3">3</option>
  111. <option value="4">4</option>
  112. <option value="5" selected>5 — default</option>
  113. <option value="6">6</option>
  114. <option value="7">7</option>
  115. <option value="8">8</option>
  116. <option value="9">9 — lowest</option>
  117. </select></div>
  118. <div class="form-row"><label for="task-enqueue-after">Auto-enqueue after
  119. <span class="muted">(optional — enqueues itself when the predecessor is done)</span></label>
  120. <select id="task-enqueue-after" name="enqueue_after_task_id">
  121. <option value="">none</option>
  122. <option stm-for-option-in="tasks.enqueue_after_options"
  123. stm-attribute.value="option.id" stm-text="option.name">task</option>
  124. </select></div>
  125. <div class="form-row" stm-if="tasks.capability_options.length > 0">
  126. <label for="task-capabilities">Capabilities
  127. <span class="muted">(the saddle fleet must carry them until assigned)</span></label>
  128. <select id="task-capabilities" name="required_capabilities" multiple
  129. size="3">
  130. <option stm-for-capability-in="tasks.capability_options"
  131. stm-attribute.value="capability.id"
  132. stm-text="capability.name">cap</option>
  133. </select></div>
  134. <button type="submit" class="primary">Create task</button>
  135. </form>
  136. </details>
  137. <table>
  138. <thead>
  139. <tr><th>#</th><th>Title</th><th>Status</th><th>Mode</th><th>Goal</th>
  140. <th>Priority</th><th>Project</th><th>Capabilities</th></tr>
  141. </thead>
  142. <tbody>
  143. <tr stm-for-task-in="tasks.tasks" stm-if="window.taskRowVisible(task)">
  144. <td stm-text="task.id">id</td>
  145. <td>
  146. <a stm-attribute.href="'/tasks/' + task.id" stm-text="task.title">title</a>
  147. </td>
  148. <td><span stm-attribute.class="'badge badge-' + task.status" stm-text="task.display">status</span></td>
  149. <td><span stm-attribute.class="'badge badge-mode-' + task.mode" stm-text="task.mode">mode</span></td>
  150. <td stm-if="task.goal_id > 0">
  151. <a stm-attribute.href="'/goals/' + task.goal_id" stm-text="task.goal_title">goal</a>
  152. <span class="muted" stm-if="task.creator == 'goal'">(agent)</span>
  153. </td>
  154. <td stm-if="task.goal_id == 0" class="muted">—</td>
  155. <td stm-text="task.priority">5</td>
  156. <td stm-text="task.project_name">project</td>
  157. <td><span stm-if="task.capabilities.length > 0"
  158. stm-text="task.capabilities.join(', ')">caps</span>
  159. <span class="muted" stm-if="task.capabilities.length == 0">—</span></td>
  160. </tr>
  161. <tr stm-if="tasks.tasks.length == 0"><td colspan="8" class="muted">No tasks.</td></tr>
  162. </tbody>
  163. </table>
  164. </div>
  165. </body>
  166. </html>