strankovani u deploys a styly pro pocitadla
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import html
|
||||
import math
|
||||
from datetime import datetime
|
||||
from urllib.parse import quote
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from fastapi.responses import HTMLResponse, PlainTextResponse
|
||||
|
||||
from app.auth import require_user
|
||||
from app.db.apps import (
|
||||
count_deployments,
|
||||
get_deployment,
|
||||
get_deployment_filter_options,
|
||||
get_deployment_stats,
|
||||
@@ -19,6 +21,7 @@ router = APIRouter()
|
||||
SUCCESS_STATUSES = {"ok", "success", "succeeded", "done", "deployed", "completed"}
|
||||
RUNNING_STATUSES = {"running", "pending", "queued", "in_progress", "starting"}
|
||||
FAILED_STATUSES = {"failed", "failure", "error", "cancelled", "canceled"}
|
||||
DEFAULT_PAGE_SIZE = 20
|
||||
|
||||
|
||||
def normalize_status(status: str | None) -> str:
|
||||
@@ -115,18 +118,43 @@ def render_options(values: list[str], selected: str | None, empty_label: str) ->
|
||||
return "".join(options)
|
||||
|
||||
|
||||
def pagination_url(page_number: int, status: str, app_id: str, source: str) -> str:
|
||||
params = {"page": page_number}
|
||||
if status:
|
||||
params["status"] = status
|
||||
if app_id:
|
||||
params["app_id"] = app_id
|
||||
if source:
|
||||
params["source"] = source
|
||||
return f"/portal/deployments?{urlencode(params)}"
|
||||
|
||||
|
||||
@router.get("/deployments", response_class=HTMLResponse)
|
||||
async def deployments_page(
|
||||
request: Request,
|
||||
status: str = Query(""),
|
||||
app_id: str = Query(""),
|
||||
source: str = Query(""),
|
||||
page_number: int = Query(1, alias="page", ge=1),
|
||||
user=Depends(require_user),
|
||||
):
|
||||
selected_status = status.strip()
|
||||
selected_app = app_id.strip()
|
||||
selected_source = source.strip()
|
||||
offset = (page_number - 1) * DEFAULT_PAGE_SIZE
|
||||
total_deployments = count_deployments(
|
||||
status=selected_status or None,
|
||||
app_id=selected_app or None,
|
||||
source=selected_source or None,
|
||||
)
|
||||
total_pages = max(1, math.ceil(total_deployments / DEFAULT_PAGE_SIZE))
|
||||
if page_number > total_pages:
|
||||
page_number = total_pages
|
||||
offset = (page_number - 1) * DEFAULT_PAGE_SIZE
|
||||
|
||||
deployments = get_deployments(
|
||||
limit=DEFAULT_PAGE_SIZE,
|
||||
offset=offset,
|
||||
status=selected_status or None,
|
||||
app_id=selected_app or None,
|
||||
source=selected_source or None,
|
||||
@@ -179,6 +207,22 @@ async def deployments_page(
|
||||
status_options = render_options(status_values, selected_status, "Všechny statusy")
|
||||
app_options = render_options(options["apps"], selected_app, "Všechny aplikace")
|
||||
source_options = render_options(options["sources"], selected_source, "Všechny zdroje")
|
||||
first_item = offset + 1 if total_deployments else 0
|
||||
last_item = min(offset + len(deployments), total_deployments)
|
||||
previous_disabled = " disabled" if page_number <= 1 else ""
|
||||
next_disabled = " disabled" if page_number >= total_pages else ""
|
||||
previous_href = pagination_url(max(1, page_number - 1), selected_status, selected_app, selected_source)
|
||||
next_href = pagination_url(min(total_pages, page_number + 1), selected_status, selected_app, selected_source)
|
||||
pagination = f"""
|
||||
<div class="pagination">
|
||||
<span>Zobrazeno {first_item}-{last_item} z {total_deployments}</span>
|
||||
<div class="pagination-actions">
|
||||
<a class="btn btn-secondary{previous_disabled}" href="{previous_href}" aria-disabled="{str(page_number <= 1).lower()}">Předchozí</a>
|
||||
<span class="page-indicator">Strana {page_number} / {total_pages}</span>
|
||||
<a class="btn btn-secondary{next_disabled}" href="{next_href}" aria-disabled="{str(page_number >= total_pages).lower()}">Další</a>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return page(
|
||||
"Nasazení",
|
||||
@@ -191,10 +235,10 @@ async def deployments_page(
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card"><span>Total deploys</span><strong>{stats.get("total") or 0}</strong></div>
|
||||
<div class="stat-card"><span>Failed deploys</span><strong>{stats.get("failed") or 0}</strong></div>
|
||||
<div class="stat-card"><span>Running deploys</span><strong>{stats.get("running") or 0}</strong></div>
|
||||
<div class="stat-card"><span>Success rate</span><strong>{stats.get("success_rate") or 0}%</strong></div>
|
||||
<div class="stat-card stat-total"><span>Total deploys</span><strong>{stats.get("total") or 0}</strong></div>
|
||||
<div class="stat-card stat-danger"><span>Failed deploys</span><strong>{stats.get("failed") or 0}</strong></div>
|
||||
<div class="stat-card stat-warning"><span>Running deploys</span><strong>{stats.get("running") or 0}</strong></div>
|
||||
<div class="stat-card stat-success"><span>Success rate</span><strong>{stats.get("success_rate") or 0}%</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@@ -203,6 +247,7 @@ async def deployments_page(
|
||||
<select name="status">{status_options}</select>
|
||||
<select name="app_id">{app_options}</select>
|
||||
<select name="source">{source_options}</select>
|
||||
<input type="hidden" name="page" value="1">
|
||||
<button type="submit">Filtrovat</button>
|
||||
<a class="btn btn-secondary" href="/portal/deployments">Reset</a>
|
||||
</form>
|
||||
@@ -210,6 +255,7 @@ async def deployments_page(
|
||||
|
||||
<div class="card">
|
||||
<h2>Nasazení</h2>
|
||||
{pagination}
|
||||
<table>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
@@ -224,6 +270,7 @@ async def deployments_page(
|
||||
</tr>
|
||||
{rows}
|
||||
</table>
|
||||
{pagination}
|
||||
</div>
|
||||
""",
|
||||
user=user,
|
||||
|
||||
Reference in New Issue
Block a user