move admin overview and fixup

This commit is contained in:
4cuck committed 2025-12-23 00:50:59 +01:00
1 parent 49fd5b14fb
commit f6622564d2
5 files changed
+144 -113

No files matched your search

+2 -36
View File
@@ -56,6 +56,7 @@ pub use logs::log_view;
pub use stats::stats_view;
pub use stats::health_csv_api;
pub use stats::stats_csv_api;
pub use stats::overview_csv_api;
/// Stored session login information
#[derive(Serialize, Deserialize, Default)]
@@ -332,7 +333,7 @@ pub async fn overview(
context.insert("instances", &hosts);
context.insert("is_admin", &login.admin);
let res = Html(template.render("admin.html.j2", &context)?).into_response();
let res = Html(template.render("admin_index.html.j2", &context)?).into_response();
drop(guard);
res
};
@@ -367,41 +368,6 @@ pub async fn history_json(
.into_response())
}
pub async fn history_json_specific(
State(ref db): State<DatabaseConnection>,
session: Session,
Path(host): Path<i32>,
Json(input): Json<DateRangeInput>,
) -> Result<axum::response::Response> {
let (host, _login) = get_specific_login_host(host, &session, db).await?;
#[derive(Debug, Serialize)]
struct ReturnData {
pub stats: Vec<instance_stats::Model>,
pub health: Vec<health_check::Model>,
}
let history_health: Vec<health_check::Model> = health_check::Entity::find()
.filter(health_check::Column::Host.eq(host.id))
.order_by_asc(health_check::Column::Time)
.filter(health_check::Column::Time.between(input.start.timestamp(), input.end.timestamp()))
.all(db)
.await?;
let history_stats: Vec<instance_stats::Model> = instance_stats::Entity::find()
.filter(instance_stats::Column::Host.eq(host.id))
.order_by_asc(instance_stats::Column::Time)
.filter(
instance_stats::Column::Time.between(input.start.timestamp(), input.end.timestamp()),
)
.all(db)
.await?;
Ok(Json(ReturnData {
health: history_health,
stats: history_stats,
})
.into_response())
}
pub async fn history_view(
State(ref app_state): State<AppState>,
State(ref template): State<Arc<tera::Tera>>,
+73
View File
@@ -0,0 +1,73 @@
document.addEventListener("DOMContentLoaded", function (event) {
const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate');
const submitTime = document.getElementById('submitDateRange');
// Set initial values in UTC
const initialEndDate = moment.utc();
const initialStartDate = moment().subtract(30, 'days').utc();
startDateInput.value = initialStartDate.format('YYYY-MM-DD');
endDateInput.value = initialEndDate.format('YYYY-MM-DD');;
submitTime.addEventListener('click', function() {
const startDate = moment(startDateInput.value, 'YYYY-MM-DD');
const endDate = moment(endDateInput.value, 'YYYY-MM-DD');
if (!startDate.isValid() || !endDate.isValid()) {
alert('Invalid date format. Please use the YYYY-MM-DD format.');
} else if (startDate.isAfter(endDate)) {
alert('Invalid date range. Start date must be before the end date.');
} else {
fetchDataAndCreateChart(startDate,endDate);
}
});
fetchDataAndCreateChart(initialStartDate,initialEndDate);
});
async function fetchDataAndCreateChart(startDate,endDate) {
let graphDiv = document.getElementById('graph-health');
try {
let g = new Dygraph(
graphDiv,
"/admin/api/graphs/overview",
{
title: 'Health Overview Instances',
showRangeSelector: true,
width: '100%',
rangeSelectorPlotFillColor: 'MediumSlateBlue',
rangeSelectorPlotFillGradientColor: 'rgba(123, 104, 238, 0)',
colorValue: 0.9,
fillAlpha: 0.4,
drawPoints: true,
strokeWidth: 0.0,
colors: ['#008000', '#ffa500'],
ylabel: 'Nitter Instances',
}
);
g.ready(function () {
g.setAnnotations([
{
series: "Healthy",
x: "2023-08-15T07:10:17Z",
shortText: "G",
text: "First API Change"
},
{
series: "Dead",
x: "2023-10-21T14:37:44Z",
shortText: "C",
text: "Wiki Cleanup"
},
{
series: "Healthy",
x: "2024-01-25T15:24:16Z",
shortText: "R",
text: "API Shutdown"
}
]);
});
} catch (error) {
console.error('Failed to fetch data:', error);
graphDiv.textContent = "Failed to load data.";
}
}
-18
View File
@@ -25,24 +25,6 @@ document.addEventListener("DOMContentLoaded", function() {
fetchDataAndCreateChart(initialStartDate,initialEndDate);
});
function mapKey(key) {
const keyMappings = {
"limited_accs": "Limited Accs",
"total_accs": "Total Accs",
"total_requests": "Total Requests",
"req_photo_rail": "PhotoRail Requests",
"req_user_screen_name": "UserScreeName Req.",
"req_search": "Search Requests",
"req_list_tweets": "ListTeweets Req.",
"req_user_media": "UserMedia Req.",
"req_tweet_detail": "TweetDetail Req.",
"req_list": "List Requests",
"req_user_tweets": "UserTweets Req.",
"req_user_tweets_and_replies": "UserTweetsAndReplies Req.",
}
return keyMappings[key];
}
async function fetchDataAndCreateChart(startDate,endDate) {
let jsonData;
try {
-59
View File
@@ -1,59 +0,0 @@
{# SPDX-License-Identifier: AGPL-3.0-only #}
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<link href="/static/bootstrap.min.css" rel="stylesheet">
<meta name="robots" content="noindex,nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="" />
<title>Admin Interface</title>
</head>
<body>
<div class="container">
<h1>Admin Interface</h1>
<p><a href="/admin/logout">Logout</a> <a href="/admin/login">Add more instances</a></p>
{% if is_admin %}<p><a href="/admin/logs">Settings Logs</a></p>{% endif %}
<h4>Instances</h4>
{% if is_admin %}<p class="text-danger-emphasis">root mode</p>{% endif %}
<div><canvas id="graph-health" width="600" height="200"></canvas><noscript>History feature works only with javascript enabled.</noscript></div>
<div class="container mt-5">
<form>
<div class="row">
<div class="col">
<label for="startDate">Start Date:</label>
<input type="date" class="form-control" id="startDate" name="startDate">
</div>
<div class="col">
<label for="endDate">End Date:</label>
<input type="date" class="form-control" id="endDate" name="endDate">
</div>
</div>
<button type="button" class="btn btn-primary mt-1" id="submitDateRange">Change</button>
</form>
</div>
<div class="table-responsive">
<table id="status-tbl" class="table sortable table-hover table-sm">
<thead>
<tr>
<th scope="col">Instance</th>
</tr>
</thead>
<tbody>
{% for instance in instances -%}
<tr>
<td>{{instance.domain}}</td>
<td><a href="/admin/instance/stats/{{instance.id}}">Stats</a></td>
<td><a href="/admin/instance/errors/{{instance.id}}">Errors</a> <a href="/admin/instance/settings/{{instance.id}}">Settings</a></td>
</tr>
{%- endfor %}
</tbody>
</table>
</div>
<script src="/static/moment.min_2.29.4.js"></script>
<script src="/static/chart.min_4.4.0.js"></script>
<script src="/static/chartjs-adapter-moment_1.0.1.js"></script>
<script src="/static/admin.js"></script>
</body>
</html>
+69
View File
@@ -0,0 +1,69 @@
{# SPDX-License-Identifier: AGPL-3.0-only #}
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<link href="/static/bootstrap.min.css" rel="stylesheet">
<link href="/static/dygraph.min.css" rel="stylesheet">
{% include "dygraph_fix.html.j2" %}
<meta name="robots" content="noindex,nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="" />
<title>Admin Interface</title>
</head>
<body>
<div class="container">
<h1>Admin Interface</h1>
<p><a href="/admin/logout">Logout</a> <a href="/admin/login">Add more instances</a></p>
{% if is_admin %}<p><a href="/admin/logs">Settings Logs</a></p>{% endif %}
<h4>Instances</h4>
{% if is_admin %}<p class="text-danger-emphasis">root mode</p>{% endif %}
<div class="container">
<div class="row">
<div class="col">
<div id="graph-health" class="graph" style="height: 400px;"></div>
</div>
</div>
<form>
<div class="row">
<div class="col">
<label for="startDate">Start Date:</label>
<input type="date" class="form-control" id="startDate" name="startDate">
</div>
<div class="col">
<label for="endDate">End Date:</label>
<input type="date" class="form-control" id="endDate" name="endDate">
</div>
</div>
<button type="button" class="btn btn-primary mt-1" id="submitDateRange">Change</button>
</form>
</div>
<div class="table-responsive">
<table id="status-tbl" class="table sortable table-hover table-sm">
<thead>
<tr>
<th scope="col">Instance</th>
</tr>
</thead>
<tbody>
{% for instance in instances -%}
<tr>
<td>{{instance.domain}}</td>
<td><a href="/admin/instance/stats/{{instance.id}}">Stats</a></td>
<td><a href="/admin/instance/errors/{{instance.id}}">Errors</a> <a
href="/admin/instance/settings/{{instance.id}}">Settings</a></td>
</tr>
{%- endfor %}
</tbody>
</table>
</div>
</div>
<script src="/static/moment.min_2.29.4.js"></script>
<script src="/static/dygraph.min.js"></script>
<script src="/static/admin_index.js"></script>
</body>
</html>