Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
710fb431f7
commit
9587c60e72
@ -37,6 +37,7 @@ service Graph {
|
||||
rpc CreateItem(CreateItemRequest) returns (CreateItemResponse);
|
||||
rpc UpdateItem(UpdateItemRequest) returns (UpdateItemResponse);
|
||||
rpc ToggleItem(ToggleItemRequest) returns (ToggleItemResponse);
|
||||
rpc Archive(ArchiveRequest) returns (ArchiveResponse);
|
||||
|
||||
// Queriers
|
||||
rpc GetAvailableRoots(GetAvailableRootsRequest) returns (GetAvailableRootsResponse);
|
||||
@ -76,6 +77,12 @@ message ToggleItemRequest {
|
||||
}
|
||||
message ToggleItemResponse {}
|
||||
|
||||
message ArchiveRequest {
|
||||
string root = 1;
|
||||
repeated string path = 2;
|
||||
}
|
||||
message ArchiveResponse {}
|
||||
|
||||
// Queries
|
||||
message GetAvailableRootsRequest {}
|
||||
message GetAvailableRootsResponse {
|
||||
|
@ -0,0 +1,3 @@
|
||||
-- Add migration script here
|
||||
|
||||
ALTER TABLE nodes ADD COLUMN status VARCHAR(20) DEFAULT 'active' NOT NULL;
|
@ -2,6 +2,7 @@ use hyperlog_core::log::ItemState;
|
||||
|
||||
use crate::{
|
||||
services::{
|
||||
archive::{self, Archive, ArchiveExt},
|
||||
create_item::{self, CreateItem, CreateItemExt},
|
||||
create_root::{self, CreateRoot, CreateRootExt},
|
||||
create_section::{self, CreateSection, CreateSectionExt},
|
||||
@ -43,6 +44,10 @@ pub enum Command {
|
||||
src: Vec<String>,
|
||||
dest: Vec<String>,
|
||||
},
|
||||
Archive {
|
||||
root: String,
|
||||
path: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -52,6 +57,7 @@ pub struct Commander {
|
||||
create_item: CreateItem,
|
||||
update_item: UpdateItem,
|
||||
toggle_item: ToggleItem,
|
||||
archive: Archive,
|
||||
}
|
||||
|
||||
impl Commander {
|
||||
@ -61,6 +67,7 @@ impl Commander {
|
||||
create_item: CreateItem,
|
||||
update_item: UpdateItem,
|
||||
toggle_item: ToggleItem,
|
||||
archive: Archive,
|
||||
) -> Self {
|
||||
Self {
|
||||
create_root,
|
||||
@ -68,6 +75,7 @@ impl Commander {
|
||||
create_item,
|
||||
update_item,
|
||||
toggle_item,
|
||||
archive,
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +141,13 @@ impl Commander {
|
||||
Ok(())
|
||||
}
|
||||
Command::Move { .. } => todo!(),
|
||||
Command::Archive { root, path } => {
|
||||
self.archive
|
||||
.execute(archive::Request { root, path })
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,6 +164,7 @@ impl CommanderExt for SharedState {
|
||||
self.create_item_service(),
|
||||
self.update_item_service(),
|
||||
self.toggle_item_service(),
|
||||
self.archive_service(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -380,6 +380,38 @@ impl Graph for Server {
|
||||
|
||||
Ok(Response::new(ToggleItemResponse {}))
|
||||
}
|
||||
|
||||
async fn archive(
|
||||
&self,
|
||||
request: tonic::Request<ArchiveRequest>,
|
||||
) -> std::result::Result<tonic::Response<ArchiveResponse>, tonic::Status> {
|
||||
let req = request.into_inner();
|
||||
tracing::trace!("update item: req({:?})", req);
|
||||
|
||||
if req.root.is_empty() {
|
||||
return Err(tonic::Status::new(
|
||||
tonic::Code::InvalidArgument,
|
||||
"root cannot be empty".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if req.path.is_empty() {
|
||||
return Err(tonic::Status::new(
|
||||
tonic::Code::InvalidArgument,
|
||||
"path cannot be empty".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.commander
|
||||
.execute(Command::Archive {
|
||||
root: req.root,
|
||||
path: req.path,
|
||||
})
|
||||
.await
|
||||
.map_err(to_tonic_err)?;
|
||||
|
||||
Ok(Response::new(ArchiveResponse {}))
|
||||
}
|
||||
}
|
||||
|
||||
fn to_native(from: &hyperlog_core::log::GraphItem) -> anyhow::Result<GraphItem> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod archive;
|
||||
pub mod create_item;
|
||||
pub mod create_root;
|
||||
pub mod create_section;
|
||||
|
70
crates/hyperlog-server/src/services/archive.rs
Normal file
70
crates/hyperlog-server/src/services/archive.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use crate::state::SharedState;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Archive {
|
||||
db: sqlx::PgPool,
|
||||
}
|
||||
|
||||
pub struct Request {
|
||||
pub root: String,
|
||||
pub path: Vec<String>,
|
||||
}
|
||||
pub struct Response {}
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct Root {
|
||||
id: uuid::Uuid,
|
||||
}
|
||||
|
||||
impl Archive {
|
||||
pub fn new(db: sqlx::PgPool) -> Self {
|
||||
Self { db }
|
||||
}
|
||||
|
||||
pub async fn execute(&self, req: Request) -> anyhow::Result<Response> {
|
||||
let Root { id: root_id, .. } =
|
||||
sqlx::query_as(r#"SELECT * FROM roots WHERE root_name = $1"#)
|
||||
.bind(req.root)
|
||||
.fetch_one(&self.db)
|
||||
.await?;
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE nodes
|
||||
SET status = 'archive'
|
||||
WHERE
|
||||
root_id = $1
|
||||
AND path = $2;
|
||||
"#,
|
||||
)
|
||||
.bind(root_id)
|
||||
.bind(req.path.join("."))
|
||||
.execute(&self.db)
|
||||
.await?;
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE nodes
|
||||
SET status = 'archive'
|
||||
WHERE root_id = $1
|
||||
AND path LIKE $2;
|
||||
"#,
|
||||
)
|
||||
.bind(root_id)
|
||||
.bind(format!("{}.%", req.path.join(".")))
|
||||
.execute(&self.db)
|
||||
.await?;
|
||||
|
||||
Ok(Response {})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArchiveExt {
|
||||
fn archive_service(&self) -> Archive;
|
||||
}
|
||||
|
||||
impl ArchiveExt for SharedState {
|
||||
fn archive_service(&self) -> Archive {
|
||||
Archive::new(self.db.clone())
|
||||
}
|
||||
}
|
@ -60,6 +60,7 @@ impl GetGraph {
|
||||
nodes
|
||||
WHERE
|
||||
root_id = $1
|
||||
AND status = 'active'
|
||||
LIMIT
|
||||
1000
|
||||
"#,
|
||||
|
@ -92,7 +92,8 @@ impl<'a> App<'a> {
|
||||
Msg::ItemCreated(IOEvent::Success(()))
|
||||
| Msg::ItemUpdated(IOEvent::Success(()))
|
||||
| Msg::SectionCreated(IOEvent::Success(()))
|
||||
| Msg::ItemToggled(IOEvent::Success(())) => {
|
||||
| Msg::ItemToggled(IOEvent::Success(()))
|
||||
| Msg::Archive(IOEvent::Success(())) => {
|
||||
batch.with(self.graph_explorer.new_update_graph());
|
||||
}
|
||||
Msg::MoveRight => self.graph_explorer.move_right()?,
|
||||
|
@ -39,6 +39,10 @@ pub enum Command {
|
||||
src: Vec<String>,
|
||||
dest: Vec<String>,
|
||||
},
|
||||
Archive {
|
||||
root: String,
|
||||
path: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -74,6 +74,9 @@ impl Commander {
|
||||
state,
|
||||
},
|
||||
)?,
|
||||
Command::Archive { root, path } => self
|
||||
.engine
|
||||
.archive(&root, &path.iter().map(|p| p.as_str()).collect::<Vec<_>>())?,
|
||||
}
|
||||
|
||||
self.storage.store(&self.engine)?;
|
||||
|
@ -27,7 +27,6 @@ impl Commander {
|
||||
let request = tonic::Request::new(CreateRootRequest { root });
|
||||
let response = client.create_root(request).await?;
|
||||
let res = response.into_inner();
|
||||
//self.engine.create_root(&root)?;
|
||||
}
|
||||
Command::CreateSection { root, path } => {
|
||||
let channel = self.channel.clone();
|
||||
@ -37,12 +36,6 @@ impl Commander {
|
||||
let request = tonic::Request::new(CreateSectionRequest { root, path });
|
||||
let response = client.create_section(request).await?;
|
||||
let res = response.into_inner();
|
||||
|
||||
// self.engine.create(
|
||||
// &root,
|
||||
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||
// GraphItem::Section(BTreeMap::default()),
|
||||
// )?;
|
||||
}
|
||||
Command::CreateItem {
|
||||
root,
|
||||
@ -73,23 +66,9 @@ impl Commander {
|
||||
});
|
||||
let response = client.create_item(request).await?;
|
||||
let res = response.into_inner();
|
||||
// self.engine.create(
|
||||
// &root,
|
||||
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||
// GraphItem::Item {
|
||||
// title,
|
||||
// description,
|
||||
// state,
|
||||
// },
|
||||
// )?
|
||||
}
|
||||
Command::Move { root, src, dest } => {
|
||||
todo!()
|
||||
// self.engine.section_move(
|
||||
// &root,
|
||||
// &src.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||
// &dest.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||
// )?
|
||||
}
|
||||
Command::ToggleItem { root, path } => {
|
||||
let channel = self.channel.clone();
|
||||
@ -129,21 +108,18 @@ impl Commander {
|
||||
});
|
||||
let response = client.update_item(request).await?;
|
||||
let res = response.into_inner();
|
||||
// self.engine.update_item(
|
||||
// &root,
|
||||
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||
// GraphItem::Item {
|
||||
// title,
|
||||
// description,
|
||||
// state,
|
||||
// },
|
||||
// )?
|
||||
}
|
||||
Command::Archive { root, path } => {
|
||||
let channel = self.channel.clone();
|
||||
|
||||
let mut client = GraphClient::new(channel);
|
||||
|
||||
let request = tonic::Request::new(ArchiveRequest { root, path });
|
||||
let response = client.archive(request).await?;
|
||||
let res = response.into_inner();
|
||||
}
|
||||
}
|
||||
|
||||
// self.storage.store(&self.engine)?;
|
||||
// self.events.enque_command(cmd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
|
||||
pub mod batch;
|
||||
|
||||
pub mod archive;
|
||||
pub mod create_item;
|
||||
pub mod create_section;
|
||||
pub mod open_update_item_dialog;
|
||||
|
58
crates/hyperlog-tui/src/commands/archive.rs
Normal file
58
crates/hyperlog-tui/src/commands/archive.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use hyperlog_core::log::ItemState;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
commander::{self, Commander},
|
||||
models::{IOEvent, Msg},
|
||||
state::SharedState,
|
||||
};
|
||||
|
||||
pub struct ArchiveCommand {
|
||||
commander: Commander,
|
||||
}
|
||||
|
||||
impl ArchiveCommand {
|
||||
pub fn new(commander: Commander) -> Self {
|
||||
Self { commander }
|
||||
}
|
||||
|
||||
pub fn command(self, root: &str, path: &[&str]) -> super::Command {
|
||||
let root = root.to_owned();
|
||||
let path = path.iter().map(|s| s.to_string()).collect_vec();
|
||||
|
||||
super::Command::new(|dispatch| {
|
||||
tokio::spawn(async move {
|
||||
dispatch.send(Msg::Archive(IOEvent::Initialized));
|
||||
|
||||
match self
|
||||
.commander
|
||||
.execute(commander::Command::Archive { root, path })
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
dispatch.send(Msg::Archive(IOEvent::Success(())));
|
||||
}
|
||||
Err(e) => {
|
||||
dispatch.send(Msg::Archive(IOEvent::Failure(e.to_string())));
|
||||
}
|
||||
}
|
||||
});
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArchiveCommandExt {
|
||||
fn archive_command(&self) -> ArchiveCommand;
|
||||
}
|
||||
|
||||
impl ArchiveCommandExt for SharedState {
|
||||
fn archive_command(&self) -> ArchiveCommand {
|
||||
ArchiveCommand::new(self.commander.clone())
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ use ratatui::{prelude::*, widgets::*};
|
||||
use crate::{
|
||||
command_parser::Commands,
|
||||
commands::{
|
||||
batch::BatchCommand, create_item::CreateItemCommandExt,
|
||||
archive::ArchiveCommandExt, batch::BatchCommand, create_item::CreateItemCommandExt,
|
||||
create_section::CreateSectionCommandExt,
|
||||
open_update_item_dialog::OpenUpdateItemDialogCommandExt, toggle_item::ToggleItemCommandExt,
|
||||
update_graph::UpdateGraphCommandExt, Command, IntoCommand,
|
||||
@ -236,7 +236,19 @@ impl<'a> GraphExplorer<'a> {
|
||||
match command {
|
||||
Commands::Archive => {
|
||||
if !self.get_current_path().is_empty() {
|
||||
tracing::debug!("archiving path: {:?}", self.get_current_path())
|
||||
batch.with(
|
||||
self.state
|
||||
.archive_command()
|
||||
.command(
|
||||
&self.inner.root,
|
||||
&self
|
||||
.get_current_path()
|
||||
.iter()
|
||||
.map(|i| i.as_str())
|
||||
.collect_vec(),
|
||||
)
|
||||
.into_command(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Commands::CreateSection { name } => {
|
||||
@ -244,13 +256,6 @@ impl<'a> GraphExplorer<'a> {
|
||||
let mut path = self.get_current_path();
|
||||
path.push(name.replace(".", "-"));
|
||||
|
||||
// self.state
|
||||
// .commander
|
||||
// .execute(commander::Command::CreateSection {
|
||||
// root: self.inner.root.clone(),
|
||||
// path,
|
||||
// })?;
|
||||
|
||||
let cmd = self.state.create_section_command().command(
|
||||
&self.inner.root,
|
||||
&path.iter().map(|i| i.as_str()).collect_vec(),
|
||||
|
@ -204,6 +204,12 @@ impl Engine {
|
||||
Some(items)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn archive(&mut self, root: &str, path: &[&str]) -> anyhow::Result<()> {
|
||||
self.delete(root, path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Engine {
|
||||
|
@ -27,6 +27,7 @@ pub enum Msg {
|
||||
ItemUpdated(IOEvent<()>),
|
||||
SectionCreated(IOEvent<()>),
|
||||
ItemToggled(IOEvent<()>),
|
||||
Archive(IOEvent<()>),
|
||||
|
||||
OpenUpdateItemDialog(IOEvent<()>),
|
||||
}
|
||||
|
@ -69,4 +69,8 @@ impl SharedEngine {
|
||||
pub(crate) fn get_roots(&self) -> Option<Vec<String>> {
|
||||
self.inner.read().unwrap().get_roots()
|
||||
}
|
||||
|
||||
pub fn archive(&self, root: &str, path: &[&str]) -> anyhow::Result<()> {
|
||||
self.inner.write().unwrap().archive(root, path)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user