changement des notes légers: rendu le pipeline plus fluide et ai effacé des pages redondantes ou encombrantes
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: test
|
||||||
|
description: Describe what this custom agent does and when to use it.
|
||||||
|
argument-hint: The inputs this agent expects, e.g., "a task to implement" or "a question to answer".
|
||||||
|
# tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'web', 'todo'] # specify the tools this agent can use. If not set, all enabled tools are allowed.
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Tip: Use /create-agent in chat to generate content with agent assistance -->
|
||||||
|
|
||||||
|
Define what this custom agent does, including its behavior, capabilities, and any specific instructions for its operation.
|
||||||
Binary file not shown.
Binary file not shown.
+64
-5
@@ -8,7 +8,7 @@ import os
|
|||||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, send_file
|
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, send_file
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
from extensions import db, hash_password
|
from extensions import db, hash_password
|
||||||
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility, UserGamertag, GAME_PLATFORMS, Contract, OrgTeam, CoachAvailability, TeamNote, PersonalNote, OneOnOneRequest, Match, Team, TeamMember, MatchParticipant, Tryout
|
from models import User, ROLES, ESPORT_GAMES, PlayerDisponibility, UserGamertag, GAME_PLATFORMS, Contract, OrgTeam, CoachAvailability, TeamNote, PersonalNote, OneOnOneRequest, Match, Team, TeamMember, MatchParticipant, Tryout, TryoutRegistration
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from datetime import datetime, timedelta, date as date_type
|
from datetime import datetime, timedelta, date as date_type
|
||||||
import requests
|
import requests
|
||||||
@@ -1132,6 +1132,60 @@ def manage_personal_notes():
|
|||||||
org_team=org_team)
|
org_team=org_team)
|
||||||
|
|
||||||
|
|
||||||
|
@users_bp.route('/notes', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def notes_dashboard():
|
||||||
|
"""Unified notes dashboard for coaches.
|
||||||
|
|
||||||
|
GET: Render the combined notes management page with both team and personal notes forms.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response: Rendered notes dashboard template.
|
||||||
|
"""
|
||||||
|
if current_user.role != 'coach':
|
||||||
|
flash('Only coaches can manage notes.', 'danger')
|
||||||
|
return redirect(url_for('main.dashboard'))
|
||||||
|
|
||||||
|
# Get the coach's team
|
||||||
|
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||||
|
players = []
|
||||||
|
if org_team:
|
||||||
|
players = User.query.filter_by(role='player', team_id=org_team.id).order_by(User.full_name).all()
|
||||||
|
|
||||||
|
# Get existing team notes
|
||||||
|
team_notes = []
|
||||||
|
latest_team_note = None
|
||||||
|
if org_team:
|
||||||
|
team_notes = TeamNote.query.filter_by(org_team_id=org_team.id).order_by(TeamNote.created_at.desc()).all()
|
||||||
|
latest_team_note = team_notes[0] if team_notes else None
|
||||||
|
|
||||||
|
# Get all personal notes for players on this team
|
||||||
|
personal_notes = []
|
||||||
|
if org_team:
|
||||||
|
personal_notes = PersonalNote.query.filter(
|
||||||
|
PersonalNote.player_id.in_([p.id for p in players])
|
||||||
|
).order_by(PersonalNote.created_at.desc()).all()
|
||||||
|
|
||||||
|
# Get available matches and tryouts for context
|
||||||
|
matches = []
|
||||||
|
tryouts = []
|
||||||
|
teams = []
|
||||||
|
if current_user.role == 'coach' and org_team:
|
||||||
|
tryouts = Tryout.query.filter_by(target_org_team_id=org_team.id).order_by(Tryout.date.desc()).all()
|
||||||
|
matches = Match.query.join(Tryout).filter(Tryout.target_org_team_id == org_team.id).order_by(Match.date.desc()).all()
|
||||||
|
teams = Team.query.order_by(Team.name).all()
|
||||||
|
|
||||||
|
return render_template('pages/notes.html',
|
||||||
|
org_team=org_team,
|
||||||
|
players=players,
|
||||||
|
team_notes=team_notes,
|
||||||
|
latest_team_note=latest_team_note,
|
||||||
|
personal_notes=personal_notes,
|
||||||
|
matches=matches,
|
||||||
|
tryouts=tryouts,
|
||||||
|
teams=teams)
|
||||||
|
|
||||||
|
|
||||||
# Note source types for filtering
|
# Note source types for filtering
|
||||||
NOTE_SOURCE_MATCH = 'match'
|
NOTE_SOURCE_MATCH = 'match'
|
||||||
NOTE_SOURCE_TRYOUT = 'tryout'
|
NOTE_SOURCE_TRYOUT = 'tryout'
|
||||||
@@ -1256,7 +1310,7 @@ def add_personal_note():
|
|||||||
db.session.add(note)
|
db.session.add(note)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash('Personal note added successfully!', 'success')
|
flash('Personal note added successfully!', 'success')
|
||||||
return redirect(url_for('users.my_notes'))
|
return redirect(url_for('users.notes_dashboard'))
|
||||||
|
|
||||||
return render_template('pages/add_personal_note.html',
|
return render_template('pages/add_personal_note.html',
|
||||||
players=players,
|
players=players,
|
||||||
@@ -1362,6 +1416,7 @@ def add_note_from_tryout(tryout_id):
|
|||||||
tryout = Tryout.query.get_or_404(tryout_id)
|
tryout = Tryout.query.get_or_404(tryout_id)
|
||||||
|
|
||||||
# Check permissions
|
# Check permissions
|
||||||
|
org_team = None
|
||||||
if current_user.role == 'coach':
|
if current_user.role == 'coach':
|
||||||
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
org_team = OrgTeam.query.filter_by(coach_id=current_user.id).first()
|
||||||
if not org_team or (tryout.target_org_team_id and tryout.target_org_team_id != org_team.id):
|
if not org_team or (tryout.target_org_team_id and tryout.target_org_team_id != org_team.id):
|
||||||
@@ -1372,8 +1427,8 @@ def add_note_from_tryout(tryout_id):
|
|||||||
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
|
registrations = TryoutRegistration.query.filter_by(tryout_id=tryout_id).all()
|
||||||
player_ids = [r.player_id for r in registrations]
|
player_ids = [r.player_id for r in registrations]
|
||||||
|
|
||||||
# If coach, filter to only their team players
|
# If coach, filter to only their team players; otherwise include all
|
||||||
if current_user.role == 'coach' and org_team:
|
if org_team:
|
||||||
players = User.query.filter(User.id.in_(player_ids), User.team_id == org_team.id).order_by(User.full_name).all()
|
players = User.query.filter(User.id.in_(player_ids), User.team_id == org_team.id).order_by(User.full_name).all()
|
||||||
else:
|
else:
|
||||||
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all()
|
players = User.query.filter(User.id.in_(player_ids)).order_by(User.full_name).all()
|
||||||
@@ -1403,7 +1458,11 @@ def add_note_from_tryout(tryout_id):
|
|||||||
flash('Personal note added successfully!', 'success')
|
flash('Personal note added successfully!', 'success')
|
||||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id))
|
||||||
|
|
||||||
|
# Allow pre-selecting a player via query parameter
|
||||||
|
preselected_player_id = request.args.get('player_id', type=int)
|
||||||
|
|
||||||
return render_template('pages/add_note_from_tryout.html',
|
return render_template('pages/add_note_from_tryout.html',
|
||||||
tryout=tryout,
|
tryout=tryout,
|
||||||
players=players,
|
players=players,
|
||||||
team_notes=team_notes)
|
team_notes=team_notes,
|
||||||
|
preselected_player_id=preselected_player_id)
|
||||||
|
|||||||
@@ -95,15 +95,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('users.manage_team_notes') }}" class="{% if request.endpoint == 'users.manage_team_notes' %}active{% endif %}">
|
<a href="{{ url_for('users.notes_dashboard') }}" class="{% if request.endpoint == 'users.notes_dashboard' or request.endpoint == 'users.manage_team_notes' or request.endpoint == 'users.manage_personal_notes' %}active{% endif %}">
|
||||||
<i class="fas fa-users"></i>
|
|
||||||
<span>Team Notes</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ url_for('users.manage_personal_notes') }}" class="{% if request.endpoint == 'users.manage_personal_notes' %}active{% endif %}">
|
|
||||||
<i class="fas fa-sticky-note"></i>
|
<i class="fas fa-sticky-note"></i>
|
||||||
<span>Personal Notes</span>
|
<span>Notes</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<select name="player_id" id="player_id" class="form-select" required>
|
<select name="player_id" id="player_id" class="form-select" required>
|
||||||
<option value="">-- Select a Player --</option>
|
<option value="">-- Select a Player --</option>
|
||||||
{% for player in players %}
|
{% for player in players %}
|
||||||
<option value="{{ player.id }}">{{ player.full_name }}</option>
|
<option value="{{ player.id }}" {% if preselected_player_id == player.id %}selected{% endif %}>{{ player.full_name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -127,6 +127,9 @@
|
|||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
<i class="fas fa-save"></i> {% if existing_eval %}Update Evaluation{% else %}Submit Evaluation{% endif %}
|
<i class="fas fa-save"></i> {% if existing_eval %}Update Evaluation{% else %}Submit Evaluation{% endif %}
|
||||||
</button>
|
</button>
|
||||||
|
<a href="{{ url_for('users.notes_dashboard') }}" class="btn btn-outline" title="Add note for this player">
|
||||||
|
<i class="fas fa-sticky-note"></i> Add Note
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
{% extends "layouts/base.html" %}
|
||||||
|
{% block title %}Notes - TryoutPro{% endblock %}
|
||||||
|
{% block page_title %}Notes{% endblock %}
|
||||||
|
{% block breadcrumb %}<span class="breadcrumb">Home / Notes</span>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="dashboard-grid">
|
||||||
|
<!-- Add Team Notes Section -->
|
||||||
|
{% if org_team %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-users"></i> Team Notes</h3>
|
||||||
|
<span class="badge badge-esport">{{ org_team.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ url_for('users.manage_team_notes') }}" class="form" id="teamNotesForm">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="team_notes_content">Team Notes Content</label>
|
||||||
|
<textarea name="content" id="team_notes_content" class="form-textarea" rows="4" placeholder="Enter improvement suggestions and notes for your team...">{{ latest_team_note.content if latest_team_note else '' }}</textarea>
|
||||||
|
<p class="form-text">These notes will be visible to all players on your team.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save"></i> {% if latest_team_note %}Update{% else %}Add{% endif %} Team Notes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Add Personal Note Section -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-user-friends"></i> Add Personal Note</h3>
|
||||||
|
{% if org_team %}
|
||||||
|
<span class="badge badge-esport">{{ org_team.name }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ url_for('users.add_personal_note') }}" class="form" id="personalNoteForm">
|
||||||
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="player_id">Select Player</label>
|
||||||
|
<select name="player_id" id="player_id" class="form-select" required>
|
||||||
|
<option value="">-- Select a Player --</option>
|
||||||
|
{% for player in players %}
|
||||||
|
<option value="{{ player.id }}">{{ player.full_name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note_content">Note Content</label>
|
||||||
|
<textarea name="content" id="note_content" class="form-textarea" rows="3" placeholder="Enter personal feedback or coaching tips for this player..." required></textarea>
|
||||||
|
<p class="form-text">These notes will only be visible to the selected player.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="context">Context (Optional)</label>
|
||||||
|
<p class="form-text text-muted">Link this note to a specific match, tryout, or team for better organization.</p>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note_match_id">Match</label>
|
||||||
|
<select name="match_id" id="note_match_id" class="form-select">
|
||||||
|
<option value="">-- Select Match --</option>
|
||||||
|
{% for match in matches %}
|
||||||
|
<option value="{{ match.id }}">{{ match.title }} - {{ match.date.strftime('%m/%d/%Y') }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note_tryout_id">Tryout</label>
|
||||||
|
<select name="tryout_id" id="note_tryout_id" class="form-select">
|
||||||
|
<option value="">-- Select Tryout --</option>
|
||||||
|
{% for tryout in tryouts %}
|
||||||
|
<option value="{{ tryout.id }}">{{ tryout.title }} - {{ tryout.date.strftime('%m/%d/%Y') }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="note_team_id">Team</label>
|
||||||
|
<select name="team_id" id="note_team_id" class="form-select">
|
||||||
|
<option value="">-- Select Team --</option>
|
||||||
|
{% for team in teams %}
|
||||||
|
<option value="{{ team.id }}">{{ team.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save"></i> Add Note
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dashboard-grid mt-4">
|
||||||
|
<!-- Team Notes History -->
|
||||||
|
{% if org_team and team_notes %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-history"></i> Team Notes History</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Last Updated</th>
|
||||||
|
<th>Content Preview</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for note in team_notes %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ note.updated_at.strftime('%B %d, %Y at %I:%M %p') if note.updated_at else 'Unknown date' }}</td>
|
||||||
|
<td>{{ note.content[:100] if note.content else '' }}{% if note.content and note.content|length > 100 %}...{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Personal Notes History -->
|
||||||
|
{% if personal_notes %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-sticky-note"></i> Recent Personal Notes</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="detail-grid">
|
||||||
|
{% for note in personal_notes %}
|
||||||
|
<div class="detail-item full-width mb-4">
|
||||||
|
<span class="detail-label">
|
||||||
|
<i class="fas fa-user"></i> {{ note.player.full_name if note.player else 'Unknown Player' }} -
|
||||||
|
<span class="text-muted">{{ note.created_at.strftime('%B %d, %Y') if note.created_at else 'Unknown date' }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="detail-value">{{ note.content | nl2br if note.content else '' }}</span>
|
||||||
|
<span class="detail-label text-muted small">From: {{ note.coach.full_name if note.coach else 'Unknown Coach' }}</span>
|
||||||
|
{% if note.match_id or note.team_id or note.tryout_id %}
|
||||||
|
<div class="mt-2">
|
||||||
|
{% if note.match_id and note.match %}
|
||||||
|
<span class="badge badge-info" title="From match"><i class="fas fa-futbol"></i> {{ note.match.title }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if note.team_id and note.team %}
|
||||||
|
<span class="badge badge-warning" title="From team"><i class="fas fa-users"></i> {{ note.team.name }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if note.tryout_id and note.tryout %}
|
||||||
|
<span class="badge badge-success" title="From tryout"><i class="fas fa-calendar-alt"></i> {{ note.tryout.title }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -66,6 +66,11 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if current_user.role == 'coach' and team.coach_id == current_user.id %}
|
||||||
|
<a href="{{ url_for('users.notes_dashboard') }}" class="btn btn-sm btn-primary" title="Add Notes">
|
||||||
|
<i class="fas fa-sticky-note"></i> Notes
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|||||||
@@ -155,10 +155,13 @@
|
|||||||
<span class="badge badge-warning">Pending</span>
|
<span class="badge badge-warning">Pending</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="eval-actions">
|
||||||
<a href="{{ url_for('evaluations.evaluate_player', tryout_id=tryout.id, player_id=p.id) }}" class="btn btn-sm btn-primary">
|
<a href="{{ url_for('evaluations.evaluate_player', tryout_id=tryout.id, player_id=p.id) }}" class="btn btn-sm btn-primary" title="Evaluate player">
|
||||||
<i class="fas fa-edit"></i> {% if player_eval_status.get(p.id) %}Edit{% else %}Evaluate{% endif %}
|
<i class="fas fa-edit"></i> {% if player_eval_status.get(p.id) %}Edit{% else %}Evaluate{% endif %}
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ url_for('users.add_note_from_tryout', tryout_id=tryout.id) }}?player_id={{ p.id }}" class="btn btn-sm btn-outline" title="Add note for {{ p.full_name }}">
|
||||||
|
<i class="fas fa-sticky-note"></i>
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user