|
|
@@ -51,6 +51,74 @@
|
|
|
</div>
|
|
|
{% else %}
|
|
|
|
|
|
+ {% macro capacity_table(sprintWorkers, capacity) %}
|
|
|
+ <section class="rounded-lg border bg-white overflow-x-auto dark:bg-slate-800 dark:border-slate-700">
|
|
|
+ <div class="px-4 py-2 border-b bg-slate-50 text-xs uppercase tracking-wider text-slate-600 font-semibold dark:bg-slate-700 dark:border-slate-700 dark:text-slate-300">
|
|
|
+ Capacity
|
|
|
+ </div>
|
|
|
+ <table class="min-w-full text-sm">
|
|
|
+ <thead>
|
|
|
+ <tr class="bg-slate-50 text-slate-600 text-xs dark:bg-slate-700 dark:text-slate-300">
|
|
|
+ <th class="text-left px-3 py-2 font-semibold sticky left-0 bg-slate-50 z-10 dark:bg-slate-700"> </th>
|
|
|
+ {% for sw in sprintWorkers %}
|
|
|
+ <th class="text-center px-2 py-2 font-semibold whitespace-nowrap">
|
|
|
+ {{ sw.workerName }}
|
|
|
+ </th>
|
|
|
+ {% endfor %}
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody class="divide-y divide-slate-100 dark:divide-slate-700">
|
|
|
+ <tr>
|
|
|
+ <th class="text-left px-3 py-2 text-slate-700 font-medium sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">Ressourcen</th>
|
|
|
+ {% for sw in sprintWorkers %}
|
|
|
+ {% set c = capacity[sw.id]|default(null) %}
|
|
|
+ <td class="px-2 py-2 text-center font-mono"
|
|
|
+ data-cap-ressourcen data-sw-id="{{ sw.id }}">
|
|
|
+ {{ fmt_days(c.ressourcen|default(0.0)) }}
|
|
|
+ </td>
|
|
|
+ {% endfor %}
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <th class="text-left px-3 py-2 text-slate-700 font-medium sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">− Reserven</th>
|
|
|
+ {% for sw in sprintWorkers %}
|
|
|
+ {% set c = capacity[sw.id]|default(null) %}
|
|
|
+ <td class="px-2 py-2 text-center font-mono text-slate-600 dark:text-slate-400"
|
|
|
+ data-cap-after-reserves data-sw-id="{{ sw.id }}">
|
|
|
+ {{ fmt_days(c.after_reserves|default(0.0)) }}
|
|
|
+ </td>
|
|
|
+ {% endfor %}
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <th class="text-left px-3 py-2 text-slate-700 font-semibold sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">Available</th>
|
|
|
+ {% for sw in sprintWorkers %}
|
|
|
+ {% set c = capacity[sw.id]|default(null) %}
|
|
|
+ {% set av = c.available|default(0.0) %}
|
|
|
+ <td class="px-2 py-2 text-center font-mono font-semibold {{ av < 0 ? 'text-red-700 dark:text-red-400' : 'text-slate-900 dark:text-slate-100' }}"
|
|
|
+ data-cap-available data-sw-id="{{ sw.id }}">
|
|
|
+ {{ fmt_days(av) }}
|
|
|
+ </td>
|
|
|
+ {% endfor %}
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </section>
|
|
|
+ {% endmacro %}
|
|
|
+
|
|
|
+ <nav class="flex border-b border-slate-200 dark:border-slate-700" role="tablist" data-tab-nav>
|
|
|
+ <button type="button" role="tab" data-tab-btn="arbeitstage"
|
|
|
+ class="px-4 py-2 text-sm font-medium border-b-2 -mb-px focus:outline-none focus:ring-2 focus:ring-slate-400 data-[active=true]:border-slate-900 data-[active=true]:text-slate-900 data-[active=false]:border-transparent data-[active=false]:text-slate-500 data-[active=false]:hover:text-slate-700 dark:data-[active=true]:border-slate-100 dark:data-[active=true]:text-slate-100 dark:data-[active=false]:text-slate-400 dark:data-[active=false]:hover:text-slate-200"
|
|
|
+ data-active="true">
|
|
|
+ Arbeitstage and capacity
|
|
|
+ </button>
|
|
|
+ <button type="button" role="tab" data-tab-btn="tasks"
|
|
|
+ class="px-4 py-2 text-sm font-medium border-b-2 -mb-px focus:outline-none focus:ring-2 focus:ring-slate-400 data-[active=true]:border-slate-900 data-[active=true]:text-slate-900 data-[active=false]:border-transparent data-[active=false]:text-slate-500 data-[active=false]:hover:text-slate-700 dark:data-[active=true]:border-slate-100 dark:data-[active=true]:text-slate-100 dark:data-[active=false]:text-slate-400 dark:data-[active=false]:hover:text-slate-200"
|
|
|
+ data-active="false">
|
|
|
+ Capacity and tasks
|
|
|
+ </button>
|
|
|
+ </nav>
|
|
|
+
|
|
|
+ <div data-tab-panel="arbeitstage" class="space-y-6">
|
|
|
+
|
|
|
<section class="rounded-lg border bg-white overflow-x-auto dark:bg-slate-800 dark:border-slate-700">
|
|
|
<table class="min-w-full text-sm" data-arbeitstage>
|
|
|
<thead class="bg-slate-50 text-slate-600 text-xs uppercase tracking-wider dark:bg-slate-700 dark:text-slate-300">
|
|
|
@@ -142,67 +210,26 @@
|
|
|
</table>
|
|
|
</section>
|
|
|
|
|
|
- <section class="rounded-lg border bg-white overflow-x-auto dark:bg-slate-800 dark:border-slate-700">
|
|
|
- <div class="px-4 py-2 border-b bg-slate-50 text-xs uppercase tracking-wider text-slate-600 font-semibold dark:bg-slate-700 dark:border-slate-700 dark:text-slate-300">
|
|
|
- Capacity
|
|
|
- </div>
|
|
|
- <table class="min-w-full text-sm">
|
|
|
- <thead>
|
|
|
- <tr class="bg-slate-50 text-slate-600 text-xs dark:bg-slate-700 dark:text-slate-300">
|
|
|
- <th class="text-left px-3 py-2 font-semibold sticky left-0 bg-slate-50 z-10 dark:bg-slate-700"> </th>
|
|
|
- {% for sw in sprintWorkers %}
|
|
|
- <th class="text-center px-2 py-2 font-semibold whitespace-nowrap">
|
|
|
- {{ sw.workerName }}
|
|
|
- </th>
|
|
|
- {% endfor %}
|
|
|
- </tr>
|
|
|
- </thead>
|
|
|
- <tbody class="divide-y divide-slate-100 dark:divide-slate-700">
|
|
|
- <tr>
|
|
|
- <th class="text-left px-3 py-2 text-slate-700 font-medium sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">Ressourcen</th>
|
|
|
- {% for sw in sprintWorkers %}
|
|
|
- {% set c = capacity[sw.id]|default(null) %}
|
|
|
- <td class="px-2 py-2 text-center font-mono"
|
|
|
- data-cap-ressourcen data-sw-id="{{ sw.id }}">
|
|
|
- {{ fmt_days(c.ressourcen|default(0.0)) }}
|
|
|
- </td>
|
|
|
- {% endfor %}
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <th class="text-left px-3 py-2 text-slate-700 font-medium sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">− Reserven</th>
|
|
|
- {% for sw in sprintWorkers %}
|
|
|
- {% set c = capacity[sw.id]|default(null) %}
|
|
|
- <td class="px-2 py-2 text-center font-mono text-slate-600 dark:text-slate-400"
|
|
|
- data-cap-after-reserves data-sw-id="{{ sw.id }}">
|
|
|
- {{ fmt_days(c.after_reserves|default(0.0)) }}
|
|
|
- </td>
|
|
|
- {% endfor %}
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <th class="text-left px-3 py-2 text-slate-700 font-semibold sticky left-0 bg-white dark:bg-slate-800 dark:text-slate-200">Available</th>
|
|
|
- {% for sw in sprintWorkers %}
|
|
|
- {% set c = capacity[sw.id]|default(null) %}
|
|
|
- {% set av = c.available|default(0.0) %}
|
|
|
- <td class="px-2 py-2 text-center font-mono font-semibold {{ av < 0 ? 'text-red-700 dark:text-red-400' : 'text-slate-900 dark:text-slate-100' }}"
|
|
|
- data-cap-available data-sw-id="{{ sw.id }}">
|
|
|
- {{ fmt_days(av) }}
|
|
|
- </td>
|
|
|
- {% endfor %}
|
|
|
- </tr>
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
- </section>
|
|
|
+ {{ _self.capacity_table(sprintWorkers, capacity) }}
|
|
|
|
|
|
<p class="text-xs text-slate-500 dark:text-slate-400">
|
|
|
Numeric inputs snap to 0.5 (days) or 0.05 (RTB) on blur. Edits save automatically
|
|
|
with a 400 ms debounce; Available turns red if a worker is overcommitted.
|
|
|
</p>
|
|
|
|
|
|
- {% include "sprints/_task_list.twig" %}
|
|
|
+ </div>{# /tab-panel arbeitstage #}
|
|
|
+
|
|
|
+ <div data-tab-panel="tasks" class="space-y-6 hidden">
|
|
|
+
|
|
|
+ {{ _self.capacity_table(sprintWorkers, capacity) }}
|
|
|
+
|
|
|
+ {% include "sprints/_task_list.twig" %}
|
|
|
+
|
|
|
+ {# Spacer so the task list never sits flush against the viewport
|
|
|
+ bottom — gives room for popovers anchored on the last row. #}
|
|
|
+ <div aria-hidden="true" class="min-h-[100px]"></div>
|
|
|
|
|
|
- {# Spacer so the task list never sits flush against the viewport
|
|
|
- bottom — gives room for popovers anchored on the last row. #}
|
|
|
- <div aria-hidden="true" class="min-h-[100px]"></div>
|
|
|
+ </div>{# /tab-panel tasks #}
|
|
|
|
|
|
{% endif %}
|
|
|
</section>
|