Add delete buttons to history page
This commit is contained in:
@ -1,2 +1,5 @@
|
|||||||
pub mod unversioned;
|
pub mod unversioned;
|
||||||
pub mod v1;
|
pub mod v1;
|
||||||
|
|
||||||
|
pub const SCHEMA_VERSION: unversioned::global::schema_version::V = 1;
|
||||||
|
pub use self::v1 as latest;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
pub mod global {
|
pub mod global {
|
||||||
pub mod schema_version {
|
pub mod schema_version {
|
||||||
pub const K: &str = "SCHEMA_VERSION";
|
pub const K: &str = "SCHEMA_VERSION";
|
||||||
pub type V = (u32, u32, u32);
|
pub type V = u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,8 +35,13 @@ pub mod trees {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct V {
|
pub struct V {
|
||||||
|
/// The UUID of the category to which this session belongs
|
||||||
pub category: trees::categories::K,
|
pub category: trees::categories::K,
|
||||||
|
|
||||||
|
/// The time when this session was started
|
||||||
pub started: NaiveDateTime,
|
pub started: NaiveDateTime,
|
||||||
|
|
||||||
|
/// The time when this session was ended
|
||||||
pub ended: NaiveDateTime,
|
pub ended: NaiveDateTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/main.rs
22
src/main.rs
@ -4,6 +4,8 @@ mod handlebars_util;
|
|||||||
mod routes;
|
mod routes;
|
||||||
mod status_json;
|
mod status_json;
|
||||||
|
|
||||||
|
use bincode::{deserialize, serialize};
|
||||||
|
use database::{unversioned::global::schema_version, SCHEMA_VERSION};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use rocket_contrib::serve::StaticFiles;
|
use rocket_contrib::serve::StaticFiles;
|
||||||
use rocket_contrib::templates::Template;
|
use rocket_contrib::templates::Template;
|
||||||
@ -15,6 +17,21 @@ fn main() -> io::Result<()> {
|
|||||||
let db_path = env::var("DB_PATH").expect("DB_PATH not set");
|
let db_path = env::var("DB_PATH").expect("DB_PATH not set");
|
||||||
|
|
||||||
let sled = sled::open(db_path)?;
|
let sled = sled::open(db_path)?;
|
||||||
|
match sled.insert(
|
||||||
|
serialize(schema_version::K).unwrap(),
|
||||||
|
serialize(&SCHEMA_VERSION).unwrap(),
|
||||||
|
)? {
|
||||||
|
Some(prev_schema_version) => {
|
||||||
|
let prev_schema_version: schema_version::V = deserialize(&prev_schema_version).unwrap();
|
||||||
|
println!(
|
||||||
|
"Schema version: {}, previously: {}",
|
||||||
|
SCHEMA_VERSION, prev_schema_version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Schema version: {}, previously: None", SCHEMA_VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let rocket = rocket::ignite()
|
let rocket = rocket::ignite()
|
||||||
.attach(Template::custom(|engines| {
|
.attach(Template::custom(|engines| {
|
||||||
@ -28,8 +45,9 @@ fn main() -> io::Result<()> {
|
|||||||
routes::pages::index,
|
routes::pages::index,
|
||||||
routes::pages::history,
|
routes::pages::history,
|
||||||
routes::api::create_category,
|
routes::api::create_category,
|
||||||
routes::api::activate_category,
|
routes::api::start_session,
|
||||||
routes::api::deactivate_category,
|
routes::api::end_session,
|
||||||
|
routes::api::delete_session,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use crate::database::v1::trees::{categories, past_sessions};
|
use crate::database::latest::trees::{categories, past_sessions};
|
||||||
|
use crate::routes::pages;
|
||||||
use crate::status_json::StatusJson;
|
use crate::status_json::StatusJson;
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::request::{Form, FromForm};
|
use rocket::request::{Form, FromForm};
|
||||||
use rocket::{post, State};
|
use rocket::response::Redirect;
|
||||||
|
use rocket::{post, uri, State};
|
||||||
use sled::Transactional;
|
use sled::Transactional;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -34,23 +36,23 @@ pub fn create_category(
|
|||||||
Ok(Status::Ok.into())
|
Ok(Status::Ok.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/set_category/<category_uuid>/active")]
|
#[post("/category/<category_uuid>/start_session")]
|
||||||
pub fn activate_category(
|
pub fn start_session(
|
||||||
category_uuid: String,
|
category_uuid: String,
|
||||||
db: State<'_, sled::Db>,
|
db: State<'_, sled::Db>,
|
||||||
) -> Result<StatusJson, StatusJson> {
|
) -> Result<StatusJson, StatusJson> {
|
||||||
toggle_category(category_uuid, true, db)
|
toggle_category_session(category_uuid, true, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/set_category/<category_uuid>/inactive")]
|
#[post("/category/<category_uuid>/end_session")]
|
||||||
pub fn deactivate_category(
|
pub fn end_session(
|
||||||
category_uuid: String,
|
category_uuid: String,
|
||||||
db: State<'_, sled::Db>,
|
db: State<'_, sled::Db>,
|
||||||
) -> Result<StatusJson, StatusJson> {
|
) -> Result<StatusJson, StatusJson> {
|
||||||
toggle_category(category_uuid, false, db)
|
toggle_category_session(category_uuid, false, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_category(
|
pub fn toggle_category_session(
|
||||||
category_uuid: String,
|
category_uuid: String,
|
||||||
set_active: bool,
|
set_active: bool,
|
||||||
db: State<'_, sled::Db>,
|
db: State<'_, sled::Db>,
|
||||||
@ -101,3 +103,30 @@ pub fn toggle_category(
|
|||||||
},
|
},
|
||||||
)??)
|
)??)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/session/<session_uuid>/delete")]
|
||||||
|
pub fn delete_session(
|
||||||
|
session_uuid: String,
|
||||||
|
db: State<'_, sled::Db>,
|
||||||
|
) -> Result<Redirect, StatusJson> {
|
||||||
|
let session_uuid = Uuid::parse_str(&session_uuid)?;
|
||||||
|
let session_uuid_s = sled::IVec::from(serialize(&session_uuid)?);
|
||||||
|
|
||||||
|
let past_sessions_tree = db.open_tree(past_sessions::NAME)?;
|
||||||
|
|
||||||
|
match past_sessions_tree.remove(session_uuid_s)? {
|
||||||
|
Some(_) => Ok(Redirect::to(uri!(pages::history))),
|
||||||
|
None => Err(Status::NotFound.into()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: mark as deleted instead of removing
|
||||||
|
// Ok(past_sessions_tree.transaction(|tx_past_sessions| {
|
||||||
|
// match tx_past_sessions.get(&session_uuid_s)? {
|
||||||
|
// None => return Ok(Err(Status::NotFound)),
|
||||||
|
// Some(data) => {
|
||||||
|
// let mut past_session: past_sessions::V = deserialize(&data).unwrap();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Ok(Ok(Redirect::to(uri!(pages::history))))
|
||||||
|
// })??)
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::database::v1::trees::{categories, past_sessions};
|
use crate::database::latest::trees::{categories, past_sessions};
|
||||||
use crate::status_json::StatusJson;
|
use crate::status_json::StatusJson;
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
@ -35,6 +35,7 @@ pub fn history(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
|||||||
struct HistoryEntryContext {
|
struct HistoryEntryContext {
|
||||||
category: categories::V,
|
category: categories::V,
|
||||||
session: past_sessions::V,
|
session: past_sessions::V,
|
||||||
|
session_id: Uuid,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,19 +61,17 @@ pub fn history(db: State<'_, sled::Db>) -> Result<Template, StatusJson> {
|
|||||||
})
|
})
|
||||||
.collect::<Result<Result<_, _>, _>>()??;
|
.collect::<Result<Result<_, _>, _>>()??;
|
||||||
|
|
||||||
let mut context = dbg!(TemplateContext {
|
let mut context = TemplateContext {
|
||||||
entries: past_sessions
|
entries: past_sessions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, session)| {
|
.map(|(session_id, session)| HistoryEntryContext {
|
||||||
let category = categories.get(&session.category).unwrap().clone();
|
duration: (session.ended - session.started).to_std().unwrap(),
|
||||||
HistoryEntryContext {
|
category: categories.get(&session.category).unwrap().clone(),
|
||||||
duration: (session.ended - session.started).to_std().unwrap(),
|
session,
|
||||||
category,
|
session_id,
|
||||||
session,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
};
|
||||||
|
|
||||||
// Newest entries first
|
// Newest entries first
|
||||||
context.entries.sort_by_key(|entry| entry.session.started);
|
context.entries.sort_by_key(|entry| entry.session.started);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use duplicate::duplicate;
|
use duplicate::duplicate;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
|
|||||||
@ -100,3 +100,6 @@ ul.striped_list > li:nth-of-type(odd) {
|
|||||||
color: #9f2727;
|
color: #9f2727;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history_entry_delete_button {
|
||||||
|
color: #aa0000;
|
||||||
|
}
|
||||||
|
|||||||
@ -17,13 +17,16 @@
|
|||||||
<ul class="striped_list">
|
<ul class="striped_list">
|
||||||
{{#each entries}}
|
{{#each entries}}
|
||||||
<li class="history_entry">
|
<li class="history_entry">
|
||||||
<span class="history_entry_category">{{this.category.name}}</span>
|
<form action="/session/{{this.session_id}}/delete" method="post">
|
||||||
<span> for </span>
|
<span class="history_entry_category">{{this.category.name}}</span>
|
||||||
<span class="history_entry_duration">{{pretty_seconds this.duration.secs}}</span>
|
<span> under </span>
|
||||||
<span> from </span>
|
<span class="history_entry_duration">{{pretty_seconds this.duration.secs}}</span>
|
||||||
<span class="history_entry_started">{{pretty_datetime this.session.started}}</span>
|
<span> från </span>
|
||||||
<span> to </span>
|
<span class="history_entry_started">{{pretty_datetime this.session.started}}</span>
|
||||||
<span class="history_entry_ended">{{pretty_datetime this.session.ended}}</span>
|
<span> tills </span>
|
||||||
|
<span class="history_entry_ended">{{pretty_datetime this.session.ended}}</span>
|
||||||
|
<button type="submit" class="history_entry_delete_button">✕</button>
|
||||||
|
</form>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -20,10 +20,10 @@
|
|||||||
// Get the corresponding route to activate/inactivate the category
|
// Get the corresponding route to activate/inactivate the category
|
||||||
let url;
|
let url;
|
||||||
if(active) {
|
if(active) {
|
||||||
url = "/set_category/" + id + "/inactive";
|
url = "/category/" + id + "/end_session";
|
||||||
cl.remove(toggled_class);
|
cl.remove(toggled_class);
|
||||||
} else {
|
} else {
|
||||||
url = "/set_category/" + id + "/active";
|
url = "/category/" + id + "/start_session";
|
||||||
cl.add(toggled_class);
|
cl.add(toggled_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +42,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1 class="title">stl</h1>
|
<h1 class="title">stl</h1>
|
||||||
|
|
||||||
{{#each categories}}
|
|
||||||
<form action="/toggle_category/{{this.0}}" method="post" id="{{this.0}}"></form>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
<ul class="striped_list">
|
<ul class="striped_list">
|
||||||
{{#each categories}}
|
{{#each categories}}
|
||||||
<li class="category_entry">
|
<li class="category_entry">
|
||||||
|
|||||||
Reference in New Issue
Block a user