feat: add shared task assignments and quick win sorting
This commit is contained in:
@@ -16,7 +16,11 @@
|
||||
<link rel="apple-touch-icon" href="{{ url_for('static', filename='images/apple-touch-icon.png') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css', v=asset_version('css/style.css')) }}">
|
||||
</head>
|
||||
<body data-push-key="{{ config['VAPID_PUBLIC_KEY'] if current_user.is_authenticated else '' }}">
|
||||
<body
|
||||
data-push-key="{{ config['VAPID_PUBLIC_KEY'] if current_user.is_authenticated else '' }}"
|
||||
data-current-user-id="{{ current_user.id if current_user.is_authenticated else '' }}"
|
||||
data-current-user-name="{{ current_user.name if current_user.is_authenticated else '' }}"
|
||||
>
|
||||
{% from "partials/macros.html" import nav_icon %}
|
||||
<div class="app-shell {% if not current_user.is_authenticated %}app-shell--auth{% endif %}">
|
||||
{% if current_user.is_authenticated %}
|
||||
@@ -119,10 +123,7 @@
|
||||
<p class="eyebrow">Punkte fair verbuchen</p>
|
||||
<h2>Wer hat diese Aufgabe erledigt?</h2>
|
||||
<p id="completeDialogText">Bitte wähle aus, wem die Punkte gutgeschrieben werden sollen.</p>
|
||||
<div class="choice-grid">
|
||||
<button type="button" class="button button--secondary" data-complete-choice="assigned">Zugewiesene Person</button>
|
||||
<button type="button" class="button" data-complete-choice="me">Ich</button>
|
||||
</div>
|
||||
<div class="choice-grid" id="completeDialogChoices"></div>
|
||||
<button type="button" class="button button--ghost" id="completeDialogClose">Abbrechen</button>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<div>
|
||||
<div class="chip-row">
|
||||
{{ status_badge(task) }}
|
||||
<span class="point-pill">{{ task.points_awarded }} Punkte</span>
|
||||
<span class="point-pill">{{ task.points_awarded }} Punkte{% if task.is_shared_assignment %} / Person{% endif %}</span>
|
||||
</div>
|
||||
<h3>{{ task.title }}</h3>
|
||||
</div>
|
||||
@@ -68,7 +68,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<dt>Zuständig</dt>
|
||||
<dd>{{ task.assigned_user.name if task.assigned_user else 'Unverteilt' }}</dd>
|
||||
<dd>{{ task.assignee_label }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Rhythmus</dt>
|
||||
@@ -84,18 +84,26 @@
|
||||
|
||||
<div class="task-card__footer">
|
||||
<div class="task-assignee">
|
||||
{{ avatar(task.assigned_user) }}
|
||||
<span>{{ task.assigned_user.name if task.assigned_user else 'Ohne Person' }}</span>
|
||||
<span class="task-assignee__avatars">
|
||||
{% for assigned_user in task.assigned_users %}
|
||||
{{ avatar(assigned_user) }}
|
||||
{% endfor %}
|
||||
</span>
|
||||
<span>{{ task.assignee_label }}</span>
|
||||
</div>
|
||||
|
||||
{% if not task.completed_at %}
|
||||
{% if task.assigned_user_id and task.assigned_user_id != current_user.id %}
|
||||
{% if task.assigned_users and current_user.id not in task.assigned_user_ids %}
|
||||
<button
|
||||
type="button"
|
||||
class="button"
|
||||
data-complete-action="{{ url_for('tasks.complete', task_id=task.id) }}"
|
||||
data-complete-title="{{ task.title }}"
|
||||
data-complete-assigned="{{ task.assigned_user.name if task.assigned_user else 'Zugewiesene Person' }}"
|
||||
data-complete-assigned="{{ task.assignee_label }}"
|
||||
data-assigned-primary-id="{{ task.assigned_user.id if task.assigned_user else '' }}"
|
||||
data-assigned-primary-name="{{ task.assigned_user.name if task.assigned_user else '' }}"
|
||||
data-assigned-secondary-id="{{ task.assigned_user_secondary.id if task.assigned_user_secondary else '' }}"
|
||||
data-assigned-secondary-name="{{ task.assigned_user_secondary.name if task.assigned_user_secondary else '' }}"
|
||||
>
|
||||
{{ nav_icon('check') }}
|
||||
<span>Erledigen</span>
|
||||
|
||||
@@ -36,11 +36,17 @@
|
||||
<article class="panel">
|
||||
<p class="eyebrow">Direkt sichtbar</p>
|
||||
<h2>Aktive Quick-Wins bearbeiten</h2>
|
||||
<div class="quick-win-list">
|
||||
<p class="muted">Per Drag & Drop kannst du die Reihenfolge festlegen, die später auch bei den Quick-Win-Chips erscheint.</p>
|
||||
<input type="hidden" id="quickWinSortToken" value="{{ csrf_token() }}">
|
||||
<div class="quick-win-list" data-quick-win-sort-list>
|
||||
{% for quick_win in quick_wins %}
|
||||
<article class="quick-win-manage-card">
|
||||
<article class="quick-win-manage-card" draggable="true" data-quick-win-sort-item="{{ quick_win.id }}">
|
||||
<form method="post" action="{{ url_for('settings.update_quick_win', quick_win_id=quick_win.id) }}" class="quick-win-manage-form">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="quick-win-manage-card__drag">
|
||||
{{ nav_icon('list') }}
|
||||
<span>Ziehen zum Sortieren</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="quick-win-title-{{ quick_win.id }}">Titel</label>
|
||||
<input id="quick-win-title-{{ quick_win.id }}" type="text" name="title" value="{{ quick_win.title }}" minlength="2" maxlength="160" required>
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
<option value="all" {% if filters.status == 'all' %}selected{% endif %}>Alle</option>
|
||||
<option value="open" {% if filters.status == 'open' %}selected{% endif %}>Offen</option>
|
||||
<option value="soon" {% if filters.status == 'soon' %}selected{% endif %}>Bald fällig</option>
|
||||
<option value="today" {% if filters.status == 'today' %}selected{% endif %}>Heute fällig</option>
|
||||
<option value="tomorrow" {% if filters.status == 'tomorrow' %}selected{% endif %}>Morgen fällig</option>
|
||||
<option value="day_after_tomorrow" {% if filters.status == 'day_after_tomorrow' %}selected{% endif %}>Übermorgen fällig</option>
|
||||
<option value="overdue" {% if filters.status == 'overdue' %}selected{% endif %}>Überfällig</option>
|
||||
<option value="completed" {% if filters.status == 'completed' %}selected{% endif %}>Erledigt</option>
|
||||
</select>
|
||||
@@ -48,4 +51,3 @@
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
<small class="calendar-task__person" lang="de">
|
||||
{% if task.completed_by_user %}
|
||||
{{ task.completed_by_user.name|hyphenate_de }}
|
||||
{% elif task.assigned_user %}
|
||||
{{ task.assigned_user.name|hyphenate_de }}
|
||||
{% elif task.assigned_users %}
|
||||
{{ task.assignee_label|hyphenate_de }}
|
||||
{% else %}
|
||||
{{ 'Ohne Zuweisung'|hyphenate_de }}
|
||||
{% endif %}
|
||||
@@ -108,8 +108,8 @@
|
||||
<small class="calendar-task__person" lang="de">
|
||||
{% if task.completed_by_user %}
|
||||
{{ task.completed_by_user.name|hyphenate_de }}
|
||||
{% elif task.assigned_user %}
|
||||
{{ task.assigned_user.name|hyphenate_de }}
|
||||
{% elif task.assigned_users %}
|
||||
{{ task.assignee_label|hyphenate_de }}
|
||||
{% else %}
|
||||
{{ 'Ohne Zuweisung'|hyphenate_de }}
|
||||
{% endif %}
|
||||
|
||||
@@ -46,13 +46,41 @@
|
||||
<section class="stack">
|
||||
<div class="section-heading">
|
||||
<h2>Bald fällig</h2>
|
||||
<span class="section-heading__count">{{ sections.soon|length }}</span>
|
||||
<span class="section-heading__count">{{ sections.due_today|length }}</span>
|
||||
</div>
|
||||
<div class="task-grid">
|
||||
{% for task in sections.soon %}
|
||||
{% for task in sections.due_today %}
|
||||
{{ task_card(task, current_user) }}
|
||||
{% else %}
|
||||
<div class="empty-state">Gerade nichts, was in den nächsten Tagen drängt.</div>
|
||||
<div class="empty-state">Heute ist gerade nichts mehr auf Kante.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stack">
|
||||
<div class="section-heading">
|
||||
<h2>Morgen fällig</h2>
|
||||
<span class="section-heading__count">{{ sections.due_tomorrow|length }}</span>
|
||||
</div>
|
||||
<div class="task-grid">
|
||||
{% for task in sections.due_tomorrow %}
|
||||
{{ task_card(task, current_user) }}
|
||||
{% else %}
|
||||
<div class="empty-state">Für morgen sieht es gerade entspannt aus.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stack">
|
||||
<div class="section-heading">
|
||||
<h2>Übermorgen fällig</h2>
|
||||
<span class="section-heading__count">{{ sections.due_day_after_tomorrow|length }}</span>
|
||||
</div>
|
||||
<div class="task-grid">
|
||||
{% for task in sections.due_day_after_tomorrow %}
|
||||
{{ task_card(task, current_user) }}
|
||||
{% else %}
|
||||
<div class="empty-state">Auch übermorgen ist noch nichts Drängendes drin.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
@@ -85,4 +113,3 @@
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
{% for error in form.assigned_user_id.errors %}<small class="error">{{ error }}</small>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
{{ form.assigned_user_secondary_id.label }}
|
||||
{{ form.assigned_user_secondary_id() }}
|
||||
<small class="muted">Wenn du hier noch jemanden auswählst, zählen die Punkte pro Person halbiert.</small>
|
||||
{% for error in form.assigned_user_secondary_id.errors %}<small class="error">{{ error }}</small>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
{{ form.due_date.label }}
|
||||
{{ form.due_date() }}
|
||||
|
||||
Reference in New Issue
Block a user