add editing

This commit is contained in:
OMGeeky
2024-10-12 13:04:09 +02:00
parent 080c1a006c
commit 5ce5921481
4 changed files with 200 additions and 40 deletions

View File

@@ -1,11 +1,11 @@
use derive_more::{FromStr, FromStrError};
use rocket::State;
#[macro_use]
extern crate rocket;
use derive_more::FromStr;
use derive_more::FromStrError;
use rocket::request::FromParam;
use rocket::response::Responder;
use rocket::tokio::time::{sleep, Duration};
use rocket::State;
use rocket_dyn_templates::Template;
use std::sync::OnceLock;
use twba_common::init_tracing;
@@ -51,8 +51,9 @@ async fn main() -> Result<(), MainError> {
.mount(
"/services/",
routes![
services::service,
services::service_info,
services::service_index,
services::task_edit,
services::service_edit,
services::update_progress,
services::increment_progress,
services::increment_task_progress,

View File

@@ -1,11 +1,16 @@
use crate::DatabaseConnection;
use crate::{AvailableServices, ResponderError};
use crate::ResponderError;
use rocket::form::Form;
use rocket::State;
use rocket_dyn_templates::{context, Template};
use twba_common::prelude::twba_local_db::prelude::{Services, Tasks};
use twba_common::prelude::twba_local_db::prelude::Services;
use twba_common::prelude::twba_local_db::prelude::ServicesModel;
use twba_common::prelude::twba_local_db::prelude::Tasks;
use twba_common::prelude::twba_local_db::prelude::TasksModel;
use twba_common::prelude::twba_local_db::re_exports::sea_orm::ActiveModelTrait;
use twba_common::prelude::twba_local_db::re_exports::sea_orm::ActiveValue;
use twba_common::prelude::twba_local_db::re_exports::sea_orm::{EntityTrait, IntoActiveModel};
use twba_common::prelude::twba_local_db::re_exports::sea_orm::EntityTrait;
use twba_common::prelude::twba_local_db::re_exports::sea_orm::IntoActiveModel;
async fn get_services(db: &DatabaseConnection) -> Result<Vec<Service>, ResponderError> {
let mut list = vec![];
@@ -41,6 +46,11 @@ pub struct Service {
last_update: String,
}
#[derive(serde::Serialize, FromForm)]
pub struct IdValueForm<T> {
id: i32,
value: T,
}
#[derive(serde::Serialize)]
pub struct Task {
id: i32,
@@ -50,12 +60,37 @@ pub struct Task {
max_progress: i32,
}
#[get("/<service>/info")]
pub(super) fn service_info(service: AvailableServices) -> String {
format!("Here is some info about the service: name: {service}")
#[post("/edit-service", data = "<data>")]
pub async fn service_edit(
db: &State<DatabaseConnection>,
data: Form<IdValueForm<String>>,
) -> Result<(), ResponderError> {
let data = data.into_inner();
let model = get_service_by_id(data.id, db.inner()).await?;
let mut model = model.into_active_model();
let name_value: String = data.value;
model.name = ActiveValue::Set(name_value);
model.save(db.inner()).await?;
Ok(())
}
#[post("/edit-task", data = "<data>")]
pub async fn task_edit(
db: &State<DatabaseConnection>,
data: Form<IdValueForm<String>>,
) -> Result<(), ResponderError> {
let data = data.into_inner();
let model = get_task_by_id(data.id, db.inner()).await?;
let mut model = model.into_active_model();
let description: String = data.value;
model.description = ActiveValue::Set(Some(description));
model.save(db.inner()).await?;
Ok(())
}
#[get("/")]
pub(super) async fn service(db: &State<DatabaseConnection>) -> Result<Template, ResponderError> {
pub(super) async fn service_index(
db: &State<DatabaseConnection>,
) -> Result<Template, ResponderError> {
let services = get_services(db.inner()).await?;
Ok(Template::render(
@@ -80,6 +115,15 @@ pub async fn increment_task_progress(
db: &State<DatabaseConnection>,
) -> Result<(), ResponderError> {
let db = db.inner();
let task = get_task_by_id(task, db).await?;
let progress = task.progress;
let mut task = task.into_active_model();
task.progress = ActiveValue::Set(progress + 1);
task.save(db).await?;
Ok(())
}
async fn get_task_by_id(task: i32, db: &DatabaseConnection) -> Result<TasksModel, ResponderError> {
let task = Tasks::find_by_id(task)
.one(db)
.await?
@@ -87,12 +131,9 @@ pub async fn increment_task_progress(
table: "Tasks",
key: format!("{task}"),
})?;
let progress = task.progress;
let mut task = task.into_active_model();
task.progress = ActiveValue::Set(progress + 1);
task.save(db).await?;
Ok(())
Ok(task)
}
#[post("/<service>/increment-progress/<task>")]
pub async fn increment_progress(
service: i32,
@@ -101,14 +142,7 @@ pub async fn increment_progress(
) -> Result<(), ResponderError> {
let db = db_state.inner();
let service =
Services::find_by_id(service)
.one(db)
.await?
.ok_or(ResponderError::DbEntityNotFound {
table: "Services",
key: format!("{service}"),
})?;
let service = get_service_by_id(service, db).await?;
let datetime = chrono::offset::Utc::now().to_rfc3339();
@@ -120,6 +154,22 @@ pub async fn increment_progress(
service.save(db).await?;
Ok(())
}
async fn get_service_by_id(
service: i32,
db: &DatabaseConnection,
) -> Result<ServicesModel, ResponderError> {
let service =
Services::find_by_id(service)
.one(db)
.await?
.ok_or(ResponderError::DbEntityNotFound {
table: "Services",
key: format!("{service}"),
})?;
Ok(service)
}
#[get("/update_progress")]
pub async fn update_progress(db: &State<DatabaseConnection>) -> Result<Template, ResponderError> {
let services = get_services(db.inner()).await?;

View File

@@ -5,6 +5,7 @@
<title>Services and Tasks</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
@@ -13,14 +14,62 @@
<div class="row" id="services-container">
</div>
<div class="modal" id="editIdStringModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editForm" method="post" action="/services/edit-service/test">
<input type="hidden" id="idField" name="id">
<div class="form-group">
<label for="valueField">Name:</label>
<input type="text" class="form-control" id="valueField" name="value" required>
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
</div>
</div>
</div>
</div>
<button class="btn btn-primary" id="add-service">Add Service</button>
<div style="flex-direction: row; display: flex" class="container">
<button class="btn btn-primary" id="update-button">Update Progress</button>
<div id="last-update-element" data-timestamp="0">hi</div>
<input type="checkbox" id="auto-update-toggle" checked>
<label for="auto-update-toggle">Enable Auto Update</label>
</div>
</div>
<script>
function openEditServiceModal(serviceId, serviceName) {
setAutoUpdateActive(false);
$('#idField').val(serviceId);
$('#valueField').val(serviceName);
$('#valueField').name = "Name";
$('#editForm').attr("action", "/services/edit-service/");
$('#editIdStringModal').modal('show');
console.log('Edit Service ID: ' + serviceId);
}
function openEditTaskModal(taskId, taskName) {
setAutoUpdateActive(false);
$('#idField').val(taskId);
$('#valueField').val(taskName);
$('#valueField').name = "Description";
$('#editForm').attr("action", "/services/edit-task/");
$('#editIdStringModal').modal('show');
console.log('Edit Task ID: ' + taskId);
}
function add_service() {
$.ajax({
type: "POST",
@@ -65,36 +114,92 @@
console.log('updating progress: ' + lastUpdateElement.text());
}
// Auto-update functionality
const normalUpdateInterval = 5000;
const slowUpdateInterval = 30000;
let autoUpdateCheckboxValue = true;
let autoUpdateActiveOverride = autoUpdateCheckboxValue;
let updateInterval;
function startUpdateInterval(interval) {
clearInterval(updateInterval); // Clear any existing interval
clearInterval(updateInterval);
updateInterval = setInterval(updateProgress, interval);
}
function stopUpdateInterval() {
clearInterval(updateInterval);
}
function setAutoUpdateActive(value) {
autoUpdateActiveOverride = value;
console.log("autoUpdateActive: " + autoUpdateActiveOverride);
if (autoUpdateActiveOverride) {
// Checkbox is checked, start auto-update
startUpdateInterval(normalUpdateInterval);
} else {
// Checkbox is unchecked, stop auto-update
stopUpdateInterval();
}
}
function reloadAutoUpdateActiveFromCheckbox() {
setAutoUpdateActive(autoUpdateCheckboxValue);
}
$(document).ready(function () {
const normalUpdateInterval = 5000;
const slowUpdateInterval = 30000;
$("#update-button").click(updateProgress);
$("#add-service").click(add_service);
updateProgress();
// Initial update and fast interval
updateProgress();
startUpdateInterval(normalUpdateInterval);
// Detect visibility changes
$('#editForm').submit(function (event) {
event.preventDefault();
var form = $(this);
var url = form.attr('action');
var type = form.attr('method');
$.ajax({
type: type,
url: url,
data: form.serialize(),
success: function (data) {
$('#editIdStringModal').modal('hide');
updateProgress();
},
error: function (error) {
console.error("Error editing:", error);
}
});
})
// Toggle auto-update
$("#auto-update-toggle").change(function () {
autoUpdateCheckboxValue = this.checked;
reloadAutoUpdateActiveFromCheckbox();
});
autoUpdateCheckboxValue = $("#auto-update-toggle").is(":checked");
$('#editIdStringModal').on('hidden.bs.modal', function () {
reloadAutoUpdateActiveFromCheckbox();
});
// Detect visibility changes (adjust interval when tab is hidden)
document.addEventListener("visibilitychange", function () {
if (autoUpdateActiveOverride) {
if (document.visibilityState === "visible") {
// Fast updates when tab is visible
startUpdateInterval(normalUpdateInterval);
} else {
// Slow updates when tab is hidden
startUpdateInterval(slowUpdateInterval);
}
}
});
});
</script>

View File

@@ -1,12 +1,15 @@
{% for service in services %}
<div class="col-md-6">
<h2>{{ service.name }}</h2>
<h2>{{ service.name }}
<button class="btn btn-sm btn-primary" onclick="openEditServiceModal('{{ service.id }}', '{{ service.name }}')">Edit</button>
</h2>
<ul class="list-group">
{% for task in service.tasks %}
<li class="list-group-item">
{{ task.name }}
{{ task.description }}
<button class="btn btn-sm btn-primary" onclick="openEditTaskModal('{{ task.id }}', '{{ task.description }}')">Edit</button>
<div class="progress">
<div class="progress-bar" role="progressbar" style="width:{{ task.max_progress / task.progress * 100 }}%;" aria-valuenow="{{ task.progress }}" aria-valuemin="0" aria-valuemax="{{ task.max_progress }}">{{ task.progress }}%</div>
<div class="progress-bar" role="progressbar" style="width:{{ task.progress/task.max_progress *100 }}%;" aria-valuenow="{{ task.progress }}" aria-valuemin="0" aria-valuemax="{{ task.max_progress }}">{{ task.progress }}%</div>
</div>
<button id="increment-button" onclick="update_task_progress( '{{service.id}}','{{task.id}}' )">+</button>
</li>
@@ -14,3 +17,4 @@
</ul>
</div>
{% endfor %}