From 4aa4447c018d2fce724810f0911557897abb784c Mon Sep 17 00:00:00 2001 From: Florian Heinz Date: Wed, 15 Apr 2026 11:49:46 +0200 Subject: [PATCH] feat: add shared quick wins workflow --- CloudronManifest.json | 2 +- README.md | 22 +++- app/__init__.py | 3 + app/forms.py | 14 ++- app/models.py | 9 ++ app/routes/settings.py | 89 +++++++++++---- app/routes/tasks.py | 40 ++++--- app/services/app_settings.py | 3 + app/services/bootstrap.py | 43 ++++++-- app/services/tasks.py | 6 +- app/static/css/style.css | 65 +++++++++++ app/templates/base.html | 67 ++++++++---- app/templates/settings/index.html | 68 ------------ app/templates/settings/quick_wins.html | 143 +++++++++++++++++++++++++ 14 files changed, 437 insertions(+), 137 deletions(-) create mode 100644 app/templates/settings/quick_wins.html diff --git a/CloudronManifest.json b/CloudronManifest.json index 88f590c..6f80ace 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -4,7 +4,7 @@ "author": "hnzio ", "description": "Spielerische Haushalts-App mit Aufgaben, Punkten, Monats-Highscore, Kalender und PWA-Push.", "tagline": "Haushalt mit Liga-Gefühl", - "version": "0.6.0", + "version": "0.6.5", "manifestVersion": 2, "healthCheckPath": "/healthz", "httpPort": 8000, diff --git a/README.md b/README.md index 31e3fba..f534ce0 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Putzliga ist eine moderne, leichte Haushaltsaufgaben-Web-App mit spielerischem C - Mehrere Nutzer mit Login, Admin-Nutzermanagement und Profil-/Avatar-Einstellungen - Trennung zwischen `TaskTemplate` und `TaskInstance` - Aufgaben anlegen, bearbeiten, zuweisen und erledigen -- globale Schnellaufgabe per Plus-Button mit Titel + Aufwand und automatisch passender Punktezahl +- globale Quick-Wins per Plus-Button mit gemeinsamen Vorlagen und freiem „Sonstiges“-Fallback - Wiederholungen für einmalig, alle X Tage, alle X Wochen und alle X Monate - Saubere Erledigungslogik für fremd zugewiesene Aufgaben mit Auswahl, wer wirklich erledigt hat - Statuslogik für offen, bald fällig, überfällig und erledigt @@ -129,11 +129,13 @@ Admins können Nutzer zusätzlich direkt in der App unter `Optionen -> Profil & Badges werden dauerhaft pro Nutzer gespeichert und automatisch freigeschaltet. Die Badge-Regeln werden für Admins auf einer eigenen Seite unter `Optionen -> Badges` gepflegt. -## Schnellaufgabe +## Quick-Wins -Über den global sichtbaren Plus-Button rechts unten kannst du auf jeder eingeloggten Seite eine Schnellaufgabe anlegen. +Über den global sichtbaren Plus-Button rechts unten kannst du auf jeder eingeloggten Seite Quick-Wins nutzen. -- nur `Titel` und `Aufwand` +- gemeinsame Quick-Wins sind für alle Nutzer sichtbar und direkt klickbar +- alle Nutzer können im separaten Optionen-Tab neue Quick-Wins anlegen +- für `Sonstiges (bitte auch nutzen)` lassen sich Titel und Aufwand frei wählen - die Aufgabe wird automatisch dem gerade eingeloggten Nutzer zugewiesen - Fälligkeit ist direkt `heute` - die Punkte hängen vom Aufwand ab @@ -144,8 +146,9 @@ Die Aufwand-Stufen sind: - Normal - Dauert etwas - Aufwendig +- Super aufwendig -Admins können die Punkte je Aufwand unter `Optionen -> Profil & Team` anpassen. +Admins können die Punkte je Aufwand unter `Optionen -> Quick-Wins` anpassen. ### 5. Entwicklungsserver starten @@ -343,6 +346,15 @@ Der ausgegebene `VAPID_PRIVATE_KEY` ist bereits `.env`-freundlich mit escaped Ne ## Release Notes +### 0.6.5 + +- Quick-Wins als gemeinsames Team-Feature ausgebaut +- neuer Optionen-Tab zum Anlegen und Verwalten gemeinsamer Quick-Wins +- Plus-Dialog auf klickbare Quick-Win-Karten umgestellt +- „Sonstiges (bitte auch nutzen)“ mit freiem Titel und Aufwand ergänzt +- neue Aufwand-Stufe `super aufwendig` +- Cloudron-Version auf `0.6.5` angehoben + ### 0.6.0 - Persönlicher read-only ICS-Feed pro Nutzer für externe Kalender ergänzt diff --git a/app/__init__.py b/app/__init__.py index 73e4c08..e16274f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -10,6 +10,7 @@ from config import Config from .cli import register_cli, seed_badges from .extensions import csrf, db, login_manager from .forms import QuickTaskForm +from .models import QuickWin from .routes import auth, main, scoreboard, settings, tasks from .routes.main import load_icon_svg from .services.app_settings import get_quick_task_config @@ -64,6 +65,7 @@ def create_app(config_class: type[Config] = Config) -> Flask: (key, values["label"]) for key, values in quick_task_config.items() ] + quick_wins = QuickWin.query.filter_by(active=True).order_by(QuickWin.id.asc()).all() def asset_version(filename: str) -> int: path = Path(app.static_folder) / filename try: @@ -94,6 +96,7 @@ def create_app(config_class: type[Config] = Config) -> Flask: "now_local": local_now(), "quick_task_form": quick_task_form, "quick_task_config": quick_task_config, + "quick_wins": quick_wins, } @app.template_filter("date_de") diff --git a/app/forms.py b/app/forms.py index 2abfae0..faaa6a3 100644 --- a/app/forms.py +++ b/app/forms.py @@ -121,7 +121,7 @@ class QuickTaskForm(FlaskForm): choices=[(key, key) for key, _, _ in QUICK_TASK_EFFORTS], validators=[DataRequired()], ) - submit = SubmitField("Schnellaufgabe speichern") + submit = SubmitField("Quick-Win speichern") class QuickTaskConfigForm(FlaskForm): @@ -133,4 +133,16 @@ class QuickTaskConfigForm(FlaskForm): medium_points = IntegerField("Dauert etwas", validators=[DataRequired(), NumberRange(min=1, max=500)]) heavy_label = StringField("Bezeichnung", validators=[DataRequired(), Length(min=2, max=60)]) heavy_points = IntegerField("Aufwendig", validators=[DataRequired(), NumberRange(min=1, max=500)]) + super_heavy_label = StringField("Bezeichnung", validators=[DataRequired(), Length(min=2, max=60)]) + super_heavy_points = IntegerField("Super aufwendig", validators=[DataRequired(), NumberRange(min=1, max=500)]) submit = SubmitField("Aufwand speichern") + + +class QuickWinForm(FlaskForm): + title = StringField("Quick-Win", validators=[DataRequired(), Length(min=2, max=160)]) + effort = SelectField( + "Aufwand", + choices=[(key, key) for key, _, _ in QUICK_TASK_EFFORTS], + validators=[DataRequired()], + ) + submit = SubmitField("Quick-Win speichern") diff --git a/app/models.py b/app/models.py index ddafcbb..dca33f2 100644 --- a/app/models.py +++ b/app/models.py @@ -48,6 +48,7 @@ class User(UserMixin, TimestampMixin, db.Model): lazy=True, ) subscriptions = db.relationship("PushSubscription", backref="user", lazy=True, cascade="all, delete-orphan") + created_quick_wins = db.relationship("QuickWin", backref="created_by_user", lazy=True) awarded_badges = db.relationship( "UserBadge", backref="user", @@ -106,6 +107,14 @@ class TaskTemplate(TimestampMixin, db.Model): return f"Alle {self.recurrence_interval_value} {unit_label}" +class QuickWin(TimestampMixin, db.Model): + id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.String(160), nullable=False, index=True) + effort = db.Column(db.String(40), nullable=False, index=True) + active = db.Column(db.Boolean, nullable=False, default=True) + created_by_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False, index=True) + + class TaskInstance(TimestampMixin, db.Model): id = db.Column(db.Integer, primary_key=True) task_template_id = db.Column(db.Integer, db.ForeignKey("task_template.id"), nullable=False, index=True) diff --git a/app/routes/settings.py b/app/routes/settings.py index 7beac44..2844cd1 100644 --- a/app/routes/settings.py +++ b/app/routes/settings.py @@ -8,8 +8,8 @@ from flask_login import current_user, login_required from werkzeug.utils import secure_filename from ..extensions import csrf, db -from ..forms import AdminUserForm, QuickTaskConfigForm, SettingsProfileForm -from ..models import BadgeDefinition, MonthlyScoreSnapshot, NotificationLog, PushSubscription, TaskInstance, TaskTemplate, User +from ..forms import AdminUserForm, QuickTaskConfigForm, QuickWinForm, SettingsProfileForm +from ..models import BadgeDefinition, MonthlyScoreSnapshot, NotificationLog, PushSubscription, QuickWin, TaskInstance, TaskTemplate, User from ..services.app_settings import get_quick_task_config, set_setting_int, set_setting_str from ..services.badges import earned_badges_for_user from ..services.notifications import push_enabled @@ -26,7 +26,10 @@ def _require_admin(): def _settings_tabs(): - tabs = [("settings.index", "Profil & Team", "gear")] + tabs = [ + ("settings.index", "Profil & Team", "gear"), + ("settings.quick_wins", "Quick-Wins", "plus"), + ] if current_user.is_admin: tabs.append(("settings.badges", "Badges", "award")) return tabs @@ -48,17 +51,6 @@ def index(): current_user.ensure_calendar_feed_token() form = SettingsProfileForm(original_email=current_user.email, obj=current_user) admin_form = AdminUserForm(prefix="admin") - quick_task_config_form = QuickTaskConfigForm(prefix="quickconfig") - quick_task_config = get_quick_task_config() - if request.method == "GET": - quick_task_config_form.fast_label.data = quick_task_config["fast"]["label"] - quick_task_config_form.fast_points.data = quick_task_config["fast"]["points"] - quick_task_config_form.normal_label.data = quick_task_config["normal"]["label"] - quick_task_config_form.normal_points.data = quick_task_config["normal"]["points"] - quick_task_config_form.medium_label.data = quick_task_config["medium"]["label"] - quick_task_config_form.medium_points.data = quick_task_config["medium"]["points"] - quick_task_config_form.heavy_label.data = quick_task_config["heavy"]["label"] - quick_task_config_form.heavy_points.data = quick_task_config["heavy"]["points"] if form.validate_on_submit(): current_user.name = form.name.data.strip() current_user.email = form.email.data.lower().strip() @@ -77,8 +69,6 @@ def index(): "settings/index.html", form=form, admin_form=admin_form, - quick_task_config_form=quick_task_config_form, - quick_task_config=quick_task_config, users=User.query.order_by(User.is_admin.desc(), User.name.asc()).all(), earned_badges=earned_badges_for_user(current_user.id), calendar_feed_url=url_for("main.calendar_feed", token=current_user.calendar_feed_token, _external=True), @@ -89,6 +79,53 @@ def index(): ) +@bp.route("/quick-wins", methods=["GET", "POST"]) +@login_required +def quick_wins(): + quick_win_form = QuickWinForm(prefix="quickwin") + quick_task_config_form = QuickTaskConfigForm(prefix="quickconfig") + quick_task_config = get_quick_task_config() + quick_win_form.effort.choices = [(key, values["label"]) for key, values in quick_task_config.items()] + + quick_task_config_form.fast_label.data = quick_task_config["fast"]["label"] + quick_task_config_form.fast_points.data = quick_task_config["fast"]["points"] + quick_task_config_form.normal_label.data = quick_task_config["normal"]["label"] + quick_task_config_form.normal_points.data = quick_task_config["normal"]["points"] + quick_task_config_form.medium_label.data = quick_task_config["medium"]["label"] + quick_task_config_form.medium_points.data = quick_task_config["medium"]["points"] + quick_task_config_form.heavy_label.data = quick_task_config["heavy"]["label"] + quick_task_config_form.heavy_points.data = quick_task_config["heavy"]["points"] + quick_task_config_form.super_heavy_label.data = quick_task_config["super_heavy"]["label"] + quick_task_config_form.super_heavy_points.data = quick_task_config["super_heavy"]["points"] + + if quick_win_form.validate_on_submit(): + existing_quick_win = QuickWin.query.filter_by(title=quick_win_form.title.data.strip(), active=True).first() + if existing_quick_win: + flash("Diesen Quick-Win gibt es bereits.", "error") + return redirect(url_for("settings.quick_wins")) + + quick_win = QuickWin( + title=quick_win_form.title.data.strip(), + effort=quick_win_form.effort.data, + active=True, + created_by_user_id=current_user.id, + ) + db.session.add(quick_win) + db.session.commit() + flash(f"Quick-Win „{quick_win.title}“ wurde gespeichert.", "success") + return redirect(url_for("settings.quick_wins")) + + return render_template( + "settings/quick_wins.html", + quick_win_form=quick_win_form, + quick_task_config_form=quick_task_config_form, + quick_task_config=quick_task_config, + quick_wins=QuickWin.query.filter_by(active=True).order_by(QuickWin.id.asc()).all(), + settings_tabs=_settings_tabs(), + active_settings_tab="settings.quick_wins", + ) + + @bp.route("/calendar-feed/regenerate", methods=["POST"]) @login_required def regenerate_calendar_feed(): @@ -174,9 +211,25 @@ def update_quick_task_config(): set_setting_int("quick_task_points_medium", form.medium_points.data) set_setting_str("quick_task_label_heavy", form.heavy_label.data) set_setting_int("quick_task_points_heavy", form.heavy_points.data) + set_setting_str("quick_task_label_super_heavy", form.super_heavy_label.data) + set_setting_int("quick_task_points_super_heavy", form.super_heavy_points.data) db.session.commit() - flash("Schnellaufgaben-Aufwand und Punkte wurden aktualisiert.", "success") - return redirect(url_for("settings.index")) + flash("Quick-Win-Aufwand und Punkte wurden aktualisiert.", "success") + return redirect(url_for("settings.quick_wins")) + + +@bp.route("/quick-wins//delete", methods=["POST"]) +@login_required +def delete_quick_win(quick_win_id: int): + quick_win = QuickWin.query.get_or_404(quick_win_id) + if quick_win.created_by_user_id != current_user.id and not current_user.is_admin: + flash("Diesen Quick-Win kannst du nicht entfernen.", "error") + return redirect(url_for("settings.quick_wins")) + + quick_win.active = False + db.session.commit() + flash("Quick-Win wurde ausgeblendet.", "success") + return redirect(url_for("settings.quick_wins")) @bp.route("/users//toggle-admin", methods=["POST"]) diff --git a/app/routes/tasks.py b/app/routes/tasks.py index 2eb747b..bcbdb49 100644 --- a/app/routes/tasks.py +++ b/app/routes/tasks.py @@ -8,7 +8,7 @@ from flask import Blueprint, flash, redirect, render_template, request, url_for from flask_login import current_user, login_required from ..forms import QuickTaskForm, TaskForm -from ..models import TaskInstance, User +from ..models import QuickWin, TaskInstance, User from ..services.app_settings import get_quick_task_config from ..services.dates import month_label, today_local from ..services.tasks import ( @@ -109,26 +109,34 @@ def create(): @bp.route("/tasks/quick", methods=["POST"]) @login_required def quick_create(): - form = QuickTaskForm(prefix="quick") config = get_quick_task_config() - form.effort.choices = [ - (key, values["label"]) - for key, values in config.items() - ] - - if not form.validate_on_submit(): - for field_errors in form.errors.values(): - for error in field_errors: - flash(error, "error") - return redirect(request.referrer or url_for("tasks.my_tasks")) - quick_action = request.form.get("quick_action", "save") - task = create_quick_task(form.title.data, form.effort.data, current_user) + quick_mode = request.form.get("quick_mode", "preset") + + if quick_mode == "preset": + quick_win = QuickWin.query.filter_by(id=request.form.get("quick_win_id", type=int), active=True).first() + if not quick_win: + flash("Dieser Quick-Win ist nicht mehr verfügbar.", "error") + return redirect(request.referrer or url_for("tasks.my_tasks")) + title = quick_win.title + effort = quick_win.effort + else: + form = QuickTaskForm(prefix="quick") + form.effort.choices = [(key, values["label"]) for key, values in config.items()] + if not form.validate_on_submit(): + for field_errors in form.errors.values(): + for error in field_errors: + flash(error, "error") + return redirect(request.referrer or url_for("tasks.my_tasks")) + title = form.title.data + effort = form.effort.data + + task = create_quick_task(title, effort, current_user, description="Quick-Win") if quick_action == "complete": complete_task(task, current_user.id) - flash(f"Schnellaufgabe „{task.title}“ wurde direkt als erledigt gespeichert.", "success") + flash(f"Quick-Win „{task.title}“ wurde direkt als erledigt gespeichert.", "success") else: - flash(f"Schnellaufgabe „{task.title}“ wurde für dich angelegt.", "success") + flash(f"Quick-Win „{task.title}“ wurde für dich angelegt.", "success") return redirect(request.referrer or url_for("tasks.my_tasks")) diff --git a/app/services/app_settings.py b/app/services/app_settings.py index f54813c..fb35aec 100644 --- a/app/services/app_settings.py +++ b/app/services/app_settings.py @@ -9,10 +9,12 @@ QUICK_TASK_DEFAULTS = { "quick_task_label_normal": "Normal", "quick_task_label_medium": "Dauert etwas", "quick_task_label_heavy": "Aufwendig", + "quick_task_label_super_heavy": "Super aufwendig", "quick_task_points_fast": 4, "quick_task_points_normal": 8, "quick_task_points_medium": 12, "quick_task_points_heavy": 18, + "quick_task_points_super_heavy": 28, } QUICK_TASK_EFFORTS = [ @@ -20,6 +22,7 @@ QUICK_TASK_EFFORTS = [ ("normal", "quick_task_label_normal", "quick_task_points_normal"), ("medium", "quick_task_label_medium", "quick_task_points_medium"), ("heavy", "quick_task_label_heavy", "quick_task_points_heavy"), + ("super_heavy", "quick_task_label_super_heavy", "quick_task_points_super_heavy"), ] diff --git a/app/services/bootstrap.py b/app/services/bootstrap.py index 532cd36..cb3c536 100644 --- a/app/services/bootstrap.py +++ b/app/services/bootstrap.py @@ -5,7 +5,7 @@ import os from sqlalchemy import inspect, text from ..extensions import db -from ..models import User +from ..models import QuickWin, User from .app_settings import ensure_app_settings @@ -30,17 +30,48 @@ def ensure_schema_and_admins() -> None: db.session.commit() admin_exists = User.query.filter_by(is_admin=True).first() - if admin_exists: - return + default_quick_win_user = admin_exists preferred_admin_email = os.getenv("DEFAULT_ADMIN_EMAIL", "mail@hnz.io").lower().strip() preferred_user = User.query.filter(User.email.ilike(preferred_admin_email)).first() - if preferred_user: + if preferred_user and not admin_exists: preferred_user.is_admin = True db.session.commit() - return + default_quick_win_user = preferred_user first_user = User.query.order_by(User.id.asc()).first() - if first_user: + if first_user and not User.query.filter_by(is_admin=True).first(): first_user.is_admin = True db.session.commit() + default_quick_win_user = first_user + + _ensure_default_quick_wins(default_quick_win_user or User.query.order_by(User.id.asc()).first()) + + +def _ensure_default_quick_wins(default_user: User | None) -> None: + if not default_user: + return + + defaults = [ + ("Schnell Aufräumen", "fast"), + ("Spülmaschine ausräumen", "normal"), + ("Bett machen", "normal"), + ("Lüften", "fast"), + ("Wäsche zusammenlegen", "medium"), + ] + + existing_titles = {quick_win.title for quick_win in QuickWin.query.all()} + created = False + for title, effort in defaults: + if title not in existing_titles: + db.session.add( + QuickWin( + title=title, + effort=effort, + active=True, + created_by_user_id=default_user.id, + ) + ) + created = True + if created: + db.session.commit() diff --git a/app/services/tasks.py b/app/services/tasks.py index 4f8248e..756ad7c 100644 --- a/app/services/tasks.py +++ b/app/services/tasks.py @@ -129,12 +129,12 @@ def complete_task(task: TaskInstance, completed_by_user_id: int) -> TaskInstance return task -def create_quick_task(title: str, effort: str, creator: User) -> TaskInstance: +def create_quick_task(title: str, effort: str, creator: User, description: str = "Quick-Win") -> TaskInstance: config = get_quick_task_config() effort_config = config[effort] template = TaskTemplate( title=title.strip(), - description="Schnellaufgabe", + description=description, default_points=effort_config["points"], default_assigned_user_id=creator.id, recurrence_interval_value=None, @@ -147,7 +147,7 @@ def create_quick_task(title: str, effort: str, creator: User) -> TaskInstance: task = TaskInstance( task_template_id=template.id, title=template.title, - description="Schnellaufgabe", + description=description, assigned_user_id=creator.id, due_date=today_local(), points_awarded=template.default_points, diff --git a/app/static/css/style.css b/app/static/css/style.css index 7ba4d77..071317d 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -1030,6 +1030,71 @@ p { margin: 0; } +.quick-win-list { + display: grid; + gap: 12px; +} + +.quick-win-manage-card, +.quick-win-card { + display: grid; + gap: 12px; + padding: 18px; + border-radius: var(--radius-md); + background: var(--surface-soft); + border: 1px solid rgba(132, 152, 190, 0.22); +} + +.quick-win-manage-card { + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; +} + +.quick-win-grid { + display: grid; + gap: 12px; +} + +.quick-win-card__actions, +.quick-win-custom__body { + display: grid; + gap: 10px; +} + +.quick-win-card__actions .button, +.quick-win-custom__body .button { + width: 100%; +} + +.quick-win-card p, +.quick-win-manage-card p { + color: var(--muted); +} + +.quick-win-card--custom { + cursor: pointer; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + list-style: none; +} + +.quick-win-card--custom::-webkit-details-marker { + display: none; +} + +.quick-win-custom { + display: grid; + gap: 10px; +} + +.quick-win-custom[open] .quick-win-card--custom { + border-color: rgba(37, 99, 235, 0.24); +} + +.quick-win-custom__body { + padding: 4px 2px 0; +} + .push-box__state { align-items: flex-start; padding: 16px; diff --git a/app/templates/base.html b/app/templates/base.html index 2edc190..b2037e8 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -105,7 +105,7 @@ {% endfor %} - @@ -123,25 +123,54 @@ -
- {{ quick_task_form.hidden_tag() }} -

Schnellaufgabe

-

Direkt etwas für dich anlegen

-

Titel und Aufwand reichen. Die Aufgabe wird automatisch dir zugewiesen und auf heute gesetzt.

-
- {{ quick_task_form.title.label }} - {{ quick_task_form.title(placeholder="Zum Beispiel: Küche kurz aufräumen") }} +
+

Quick-Wins

+

Schnell etwas abhaken

+

Alle Quick-Wins sind für das ganze Team sichtbar. Für „Sonstiges“ kannst du Titel und Aufwand frei wählen.

+
+ {% for quick_win in quick_wins %} +
+
+ {{ quick_win.title }} +

{{ quick_task_config[quick_win.effort].label }}

+
+ + + + + + + +
+ {% endfor %} +
+ +
+ Sonstiges (bitte auch nutzen) +

Eigener Titel und freier Aufwand

+
+ {{ nav_icon('plus') }} +
+
+ {{ quick_task_form.hidden_tag() }} + +
+ {{ quick_task_form.title.label }} + {{ quick_task_form.title(placeholder="Zum Beispiel: Flur kurz aufräumen") }} +
+
+ {{ quick_task_form.effort.label }} + {{ quick_task_form.effort() }} +
+
+ + +
+
+
-
- {{ quick_task_form.effort.label }} - {{ quick_task_form.effort() }} -
-
- - - -
- + +
diff --git a/app/templates/settings/index.html b/app/templates/settings/index.html index 5db99a7..dfe7ccf 100644 --- a/app/templates/settings/index.html +++ b/app/templates/settings/index.html @@ -182,73 +182,5 @@ {% endfor %} - -
-

Admin

-

Schnellaufgabe-Aufwand

-

Hier definierst du die sichtbaren Aufwand-Stufen und die dazugehörigen Punkte. Im Schnellaufgaben-Dialog wird nur die Bezeichnung angezeigt.

- - {{ quick_task_config_form.hidden_tag() }} -
-
- Slot 1 -

Kleine Sache für zwischendurch.

-
-
- {{ quick_task_config_form.fast_label.label }} - {{ quick_task_config_form.fast_label() }} -
-
- - {{ quick_task_config_form.fast_points() }} -
-
-
-
- Slot 2 -

Typische Alltagssache.

-
-
- {{ quick_task_config_form.normal_label.label }} - {{ quick_task_config_form.normal_label() }} -
-
- - {{ quick_task_config_form.normal_points() }} -
-
-
-
- Slot 3 -

Braucht etwas mehr Zeit oder Konzentration.

-
-
- {{ quick_task_config_form.medium_label.label }} - {{ quick_task_config_form.medium_label() }} -
-
- - {{ quick_task_config_form.medium_points() }} -
-
-
-
- Slot 4 -

Spürbarer Aufwand mit mehr Punkten.

-
-
- {{ quick_task_config_form.heavy_label.label }} - {{ quick_task_config_form.heavy_label() }} -
-
- - {{ quick_task_config_form.heavy_points() }} -
-
-
- {{ quick_task_config_form.submit(class_='button button--secondary') }} -
- -
{% endif %} {% endblock %} diff --git a/app/templates/settings/quick_wins.html b/app/templates/settings/quick_wins.html new file mode 100644 index 0000000..eb60af2 --- /dev/null +++ b/app/templates/settings/quick_wins.html @@ -0,0 +1,143 @@ +{% extends "base.html" %} +{% from "partials/macros.html" import nav_icon %} +{% block title %}Quick-Wins · Putzliga{% endblock %} +{% block page_title %}Quick-Wins{% endblock %} +{% block content %} +
+ {% for endpoint, label, icon in settings_tabs %} + + {{ nav_icon(icon) }} + {{ label }} + + {% endfor %} +
+ +
+
+

Gemeinsame Vorlagen

+

Quick-Win anlegen

+

Alle hier angelegten Quick-Wins sind direkt für das ganze Team im Plus-Menü verfügbar.

+
+ {{ quick_win_form.hidden_tag() }} +
+ {{ quick_win_form.title.label }} + {{ quick_win_form.title(placeholder="Zum Beispiel: Müllbeutel wechseln") }} + {% for error in quick_win_form.title.errors %}{{ error }}{% endfor %} +
+
+ {{ quick_win_form.effort.label }} + {{ quick_win_form.effort() }} + {% for error in quick_win_form.effort.errors %}{{ error }}{% endfor %} +
+ {{ quick_win_form.submit(class_='button') }} +
+
+ +
+

Direkt sichtbar

+

Aktive Quick-Wins

+
+ {% for quick_win in quick_wins %} +
+
+ {{ quick_win.title }} +

{{ quick_task_config[quick_win.effort].label }} · von {{ quick_win.created_by_user.name }}

+
+ {% if quick_win.created_by_user_id == current_user.id or current_user.is_admin %} +
+ + +
+ {% endif %} +
+ {% else %} +
Noch keine Quick-Wins angelegt. Der erste steht gleich oben bereit.
+ {% endfor %} +
+
+
+ + {% if current_user.is_admin %} +
+

Admin

+

Quick-Win-Aufwand

+

Hier definierst du die sichtbaren Aufwand-Stufen und die dazugehörigen Punkte. Im Quick-Wins-Dialog wird nur die Bezeichnung angezeigt.

+
+ {{ quick_task_config_form.hidden_tag() }} +
+
+ Slot 1 +

Kleine Sache für zwischendurch.

+
+
+ {{ quick_task_config_form.fast_label.label }} + {{ quick_task_config_form.fast_label() }} +
+
+ + {{ quick_task_config_form.fast_points() }} +
+
+
+
+ Slot 2 +

Typische Alltagssache.

+
+
+ {{ quick_task_config_form.normal_label.label }} + {{ quick_task_config_form.normal_label() }} +
+
+ + {{ quick_task_config_form.normal_points() }} +
+
+
+
+ Slot 3 +

Braucht etwas mehr Zeit oder Konzentration.

+
+
+ {{ quick_task_config_form.medium_label.label }} + {{ quick_task_config_form.medium_label() }} +
+
+ + {{ quick_task_config_form.medium_points() }} +
+
+
+
+ Slot 4 +

Spürbarer Aufwand mit mehr Punkten.

+
+
+ {{ quick_task_config_form.heavy_label.label }} + {{ quick_task_config_form.heavy_label() }} +
+
+ + {{ quick_task_config_form.heavy_points() }} +
+
+
+
+ Slot 5 +

Extra große Aufgabe für echte Kraftakte.

+
+
+ {{ quick_task_config_form.super_heavy_label.label }} + {{ quick_task_config_form.super_heavy_label() }} +
+
+ + {{ quick_task_config_form.super_heavy_points() }} +
+
+
+ {{ quick_task_config_form.submit(class_='button button--secondary') }} +
+
+
+ {% endif %} +{% endblock %}