2 Commits

2 changed files with 85 additions and 17 deletions

View File

@@ -3,6 +3,7 @@
## Build/Lint/Test Commands ## Build/Lint/Test Commands
### Setup ### Setup
```bash ```bash
# Install dependencies with Poetry # Install dependencies with Poetry
poetry install poetry install
@@ -12,6 +13,7 @@ pre-commit install
``` ```
### Linting and Formatting ### Linting and Formatting
```bash ```bash
# Run all pre-commit checks (linting, formatting, type checking) # Run all pre-commit checks (linting, formatting, type checking)
pre-commit run --all-files pre-commit run --all-files
@@ -25,6 +27,7 @@ markdownlint . # Markdown linting
``` ```
### Running Tests ### Running Tests
```bash ```bash
# No formal test framework configured # No formal test framework configured
# Project uses manual testing with example PDF files in repository # Project uses manual testing with example PDF files in repository
@@ -35,6 +38,7 @@ markdownlint . # Markdown linting
``` ```
### Running the Web API ### Running the Web API
```bash ```bash
# Or with poetry # Or with poetry
poetry run fastapi run myice/webapi.py --host 127.0.0.1 poetry run fastapi run myice/webapi.py --host 127.0.0.1
@@ -43,34 +47,40 @@ poetry run fastapi run myice/webapi.py --host 127.0.0.1
## Code Style Guidelines ## Code Style Guidelines
### Imports ### Imports
- Standard library imports first, then third-party, then local imports - Standard library imports first, then third-party, then local imports
- Use explicit imports rather than wildcard imports - Use explicit imports rather than wildcard imports
- Group imports logically with blank lines between groups - Group imports logically with blank lines between groups
### Formatting ### Formatting
- Use ruff-format for automatic formatting - Use ruff-format for automatic formatting
- Follow PEP 8 style guide - Follow PEP 8 style guide
- Maximum line length: 88 characters (default ruff setting) - Maximum line length: 88 characters (default ruff setting)
- Use 4 spaces for indentation - Use 4 spaces for indentation
### Types ### Types
- Use type hints for function parameters and return values - Use type hints for function parameters and return values
- Prefer built-in types (str, int, list, dict) over typing aliases when possible - Prefer built-in types (str, int, list, dict) over typing aliases when possible
- Use typing.Annotated for Typer command options - Use typing.Annotated for Typer command options
### Naming Conventions ### Naming Conventions
- Variables and functions: snake_case - Variables and functions: snake_case
- Classes: PascalCase - Classes: PascalCase
- Constants: UPPER_SNAKE_CASE - Constants: UPPER_SNAKE_CASE
- Private members: prefixed with underscore (_private) - Private members: prefixed with underscore (_private)
### Error Handling ### Error Handling
- Use try/except blocks for expected exceptions - Use try/except blocks for expected exceptions
- Raise appropriate HTTPException for API errors - Raise appropriate HTTPException for API errors
- Include descriptive error messages - Include descriptive error messages
- Use sys.exit(1) for command-line tool errors - Use sys.exit(1) for command-line tool errors
### Frameworks and Libraries ### Frameworks and Libraries
- Typer for CLI interface - Typer for CLI interface
- FastAPI for web API - FastAPI for web API
- requests for HTTP requests - requests for HTTP requests
@@ -79,15 +89,17 @@ poetry run fastapi run myice/webapi.py --host 127.0.0.1
- Custom rl_ai_tools package for AI functionalities - Custom rl_ai_tools package for AI functionalities
### Git Commit Messages ### Git Commit Messages
- Use conventional commits format - Use conventional commits format
- Never mention Claude in commit messages - Never mention Claude in commit messages
- Be descriptive but concise - Be descriptive but concise
- Use present tense ("add feature" not "added feature") - Use present tense ("add feature" not "added feature")
### Additional Rules ### Additional Rules
- Always use ddg-mcp to perform Web Search functionality - Always use ddg-mcp to perform Web Search functionality
- Follow the existing code patterns in myice/myice.py and myice/webapi.py - Follow the existing code patterns in myice/myice.py and myice/webapi.py
- Maintain backward compatibility when modifying existing APIs - Maintain backward compatibility when modifying existing APIs
- Document new features in README.md - Document new features in README.md
- Always run ruff format and ruff check after editing a python file - Always run ruff format and ruff check after editing a python file
- use conventional commit messages - use conventional commit messages

View File

@@ -518,9 +518,11 @@
headers: { "Authorization": `Bearer ${storedApiKey}` } headers: { "Authorization": `Bearer ${storedApiKey}` }
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const sortedPlayers = data.convocation.available // Check if available players data exists
.sort((a, b) => (a.number || 0) - (b.number || 0)); const availablePlayers = data.convocation.available || [];
const sortedPlayers = availablePlayers
.sort((a, b) => (a.number || 0) - (b.number || 0));
// Calculate player statistics // Calculate player statistics
const totalPlayers = sortedPlayers.length; const totalPlayers = sortedPlayers.length;
@@ -551,19 +553,73 @@
return numA - numB; return numA - numB;
}); });
eventDetailsContent.innerHTML = ` // Process staff data
<h5>${data.title}</h5> const staffList = data.convocation.staff || [];
<p><strong>Type:</strong> ${data.type}</p> const totalStaff = staffList.length;
<p><strong>Lieu:</strong> ${data.place}</p>
<p><strong>Heure:</strong> ${data.time_start} - ${data.time_end}</p> // Check if there are no players
<p><strong>Joueurs convoqués:</strong> ${totalPlayers} joueur${totalPlayers > 1 ? 's' : ''} (${positionBreakdown})</p> if (totalPlayers === 0 && totalStaff === 0) {
<h6>Liste des joueurs:</h6> eventDetailsContent.innerHTML = `
<ul>${playersByPosition.map(player => { <div class="card border-warning">
let number = player.number ? player.number : "N/A"; <div class="card-body text-center">
let position = player.position ? player.position : "N/A"; <h5 class="card-title">${data.title}</h5>
return `<li>[${position}] ${number} - ${player.fname} ${player.lname} (${player.dob})</li>`; <p class="card-text"><strong>Type:</strong> ${data.type}</p>
}).join('')}</ul> <p class="card-text"><strong>Lieu:</strong> ${data.place}</p>
`; <p class="card-text"><strong>Heure:</strong> ${data.time_start} - ${data.time_end}</p>
<div class="alert alert-warning" role="alert">
<h6 class="alert-heading">Aucun joueur ni personnel convoqué</h6>
<p>Il n'y a actuellement aucun joueur ni personnel convoqué pour ce match.</p>
</div>
</div>
</div>
`;
} else {
let staffHtml = '';
if (totalStaff > 0) {
staffHtml = `
<h6>Personnel (${totalStaff}):</h6>
<ul>${staffList.map(staff => {
return `<li><strong>${staff.role}:</strong> ${staff.fname} ${staff.lname}</li>`;
}).join('')}</ul>
`;
} else {
staffHtml = `
<div class="alert alert-info" role="alert">
<h6>Aucun personnel convoqué</h6>
<p>Il n'y a actuellement aucun personnel convoqué pour ce match.</p>
</div>
`;
}
if (totalPlayers === 0) {
eventDetailsContent.innerHTML = `
<h5>${data.title}</h5>
<p><strong>Type:</strong> ${data.type}</p>
<p><strong>Lieu:</strong> ${data.place}</p>
<p><strong>Heure:</strong> ${data.time_start} - ${data.time_end}</p>
<div class="alert alert-warning" role="alert">
<h6 class="alert-heading">Aucun joueur convoqué</h6>
<p>Il n'y a actuellement aucun joueur convoqué pour ce match.</p>
</div>
${staffHtml}
`;
} else {
eventDetailsContent.innerHTML = `
<h5>${data.title}</h5>
<p><strong>Type:</strong> ${data.type}</p>
<p><strong>Lieu:</strong> ${data.place}</p>
<p><strong>Heure:</strong> ${data.time_start} - ${data.time_end}</p>
<p><strong>Joueurs convoqués:</strong> ${totalPlayers} joueur${totalPlayers > 1 ? 's' : ''} (${positionBreakdown})</p>
<h6>Liste des joueurs:</h6>
<ul>${playersByPosition.map(player => {
let number = player.number ? player.number : "N/A";
let position = player.position ? player.position : "N/A";
return `<li>[${position}] ${number} - ${player.fname} ${player.lname} (${player.dob})</li>`;
}).join('')}</ul>
${staffHtml}
`;
}
}
new bootstrap.Modal(document.getElementById('eventDetailsModal')).show(); new bootstrap.Modal(document.getElementById('eventDetailsModal')).show();
}) })
.catch(error => console.error("Erreur lors du chargement des détails de l'événement:", error)); .catch(error => console.error("Erreur lors du chargement des détails de l'événement:", error));