feature: add MIEM employees parser service with admin UI and MCP
This commit is contained in:
28
app/templates/base.html
Normal file
28
app/templates/base.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}MIEM Employees{% endblock %}</title>
|
||||
<link rel="stylesheet" href="/static/admin.css">
|
||||
</head>
|
||||
<body class="admin">
|
||||
<header class="admin__header">
|
||||
<h1 class="admin__brand">MIEM Employees</h1>
|
||||
<nav class="admin__nav">
|
||||
<a class="admin__link" href="/admin">Dashboard</a>
|
||||
<a class="admin__link" href="/admin/employees">Employees</a>
|
||||
<a class="admin__link" href="/admin/runs">Runs</a>
|
||||
<form method="post" action="/admin/logout">
|
||||
<button class="button button--ghost" type="submit">Logout</button>
|
||||
</form>
|
||||
</nav>
|
||||
</header>
|
||||
<main class="admin__main">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
<footer class="admin__footer">
|
||||
Backend {{ backend_version }} · Frontend {{ frontend_version }}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
21
app/templates/dashboard.html
Normal file
21
app/templates/dashboard.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Dashboard · MIEM Employees{% endblock %}
|
||||
{% block content %}
|
||||
<section class="admin__grid">
|
||||
<div class="metric"><div class="metric__label">Active</div><div class="metric__value">{{ counts.active }}</div></div>
|
||||
<div class="metric"><div class="metric__label">Dismissed</div><div class="metric__value">{{ counts.dismissed }}</div></div>
|
||||
<div class="metric"><div class="metric__label">Runs</div><div class="metric__value">{{ counts.runs }}</div></div>
|
||||
<div class="metric"><div class="metric__label">Errors</div><div class="metric__value">{{ counts.errors }}</div></div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">Latest runs</h2>
|
||||
<table class="table">
|
||||
<thead><tr><th class="table__head">ID</th><th class="table__head">Status</th><th class="table__head">Parsed</th><th class="table__head">Errors</th><th class="table__head">Started</th></tr></thead>
|
||||
<tbody>
|
||||
{% for run in runs %}
|
||||
<tr><td class="table__cell">{{ run.id }}</td><td class="table__cell">{{ run.status }}</td><td class="table__cell">{{ run.parsed_count }}</td><td class="table__cell">{{ run.error_count }}</td><td class="table__cell">{{ run.started_at }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{% endblock %}
|
||||
28
app/templates/employee_detail.html
Normal file
28
app/templates/employee_detail.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ employee.full_name }} · MIEM Employees{% endblock %}
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">{{ employee.full_name or employee.profile_key }}</h2>
|
||||
<p><span class="badge {% if employee.status == "dismissed" %}badge--dismissed{% endif %}">{{ employee.status }}</span></p>
|
||||
<p><a class="admin__link" href="{{ employee.canonical_url }}">{{ employee.canonical_url }}</a></p>
|
||||
<h3>Tabs</h3>
|
||||
<ul>
|
||||
{% for tab in employee.tabs %}
|
||||
<li><a class="admin__link" href="{{ tab.href }}">{{ tab.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3>Current data</h3>
|
||||
<pre class="code">{{ employee.current_data | tojson(indent=2) }}</pre>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">Snapshots</h2>
|
||||
<table class="table">
|
||||
<thead><tr><th class="table__head">Captured</th><th class="table__head">Checksum</th><th class="table__head">Parser</th></tr></thead>
|
||||
<tbody>
|
||||
{% for snapshot in snapshots %}
|
||||
<tr><td class="table__cell">{{ snapshot.captured_at }}</td><td class="table__cell">{{ snapshot.checksum }}</td><td class="table__cell">{{ snapshot.parser_version }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{% endblock %}
|
||||
29
app/templates/employees.html
Normal file
29
app/templates/employees.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Employees · MIEM Employees{% endblock %}
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">Employees</h2>
|
||||
<form class="form" method="get" action="/admin/employees">
|
||||
<input class="form__input" name="q" value="{{ q }}" placeholder="Name or URL">
|
||||
<select class="form__select" name="status">
|
||||
<option value="" {% if not status %}selected{% endif %}>All</option>
|
||||
<option value="active" {% if status == "active" %}selected{% endif %}>Active</option>
|
||||
<option value="dismissed" {% if status == "dismissed" %}selected{% endif %}>Dismissed</option>
|
||||
</select>
|
||||
<button class="button" type="submit">Search</button>
|
||||
</form>
|
||||
<table class="table">
|
||||
<thead><tr><th class="table__head">Name</th><th class="table__head">Status</th><th class="table__head">Last seen</th><th class="table__head">Profile</th></tr></thead>
|
||||
<tbody>
|
||||
{% for employee in employees %}
|
||||
<tr>
|
||||
<td class="table__cell"><a class="admin__link" href="/admin/employees/{{ employee.id }}">{{ employee.full_name or employee.profile_key }}</a></td>
|
||||
<td class="table__cell"><span class="badge {% if employee.status == "dismissed" %}badge--dismissed{% endif %}">{{ employee.status }}</span></td>
|
||||
<td class="table__cell">{{ employee.last_seen_at }}</td>
|
||||
<td class="table__cell"><a class="admin__link" href="{{ employee.canonical_url }}">{{ employee.canonical_url }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{% endblock %}
|
||||
25
app/templates/login.html
Normal file
25
app/templates/login.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Login · MIEM Employees</title>
|
||||
<link rel="stylesheet" href="/static/admin.css">
|
||||
</head>
|
||||
<body class="admin">
|
||||
<main class="admin__main">
|
||||
<section class="panel">
|
||||
<h1 class="panel__title">Admin login</h1>
|
||||
{% if error %}<p>{{ error }}</p>{% endif %}
|
||||
<form class="form" method="post" action="/admin/login">
|
||||
<label class="form__label">Login <input class="form__input" name="username" autocomplete="username"></label>
|
||||
<label class="form__label">Password <input class="form__input" name="password" type="password" autocomplete="current-password"></label>
|
||||
<button class="button" type="submit">Sign in</button>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="admin__footer">
|
||||
Backend {{ backend_version }} · Frontend {{ frontend_version }}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
27
app/templates/runs.html
Normal file
27
app/templates/runs.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Runs · MIEM Employees{% endblock %}
|
||||
{% block content %}
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">Crawl runs</h2>
|
||||
<form method="post" action="/admin/runs"><button class="button" type="submit">Start crawl</button></form>
|
||||
<table class="table">
|
||||
<thead><tr><th class="table__head">ID</th><th class="table__head">Status</th><th class="table__head">Found</th><th class="table__head">Parsed</th><th class="table__head">Errors</th><th class="table__head">Dismissed</th></tr></thead>
|
||||
<tbody>
|
||||
{% for run in runs %}
|
||||
<tr><td class="table__cell">{{ run.id }}</td><td class="table__cell">{{ run.status }}</td><td class="table__cell">{{ run.found_count }}</td><td class="table__cell">{{ run.parsed_count }}</td><td class="table__cell">{{ run.error_count }}</td><td class="table__cell">{{ run.dismissed_count }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<h2 class="panel__title">Recent errors</h2>
|
||||
<table class="table">
|
||||
<thead><tr><th class="table__head">Run</th><th class="table__head">Profile</th><th class="table__head">Error</th></tr></thead>
|
||||
<tbody>
|
||||
{% for error in errors %}
|
||||
<tr><td class="table__cell">{{ error.crawl_run_id }}</td><td class="table__cell">{{ error.profile_url }}</td><td class="table__cell">{{ error.error_type }}: {{ error.message }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user