feat: header on main page
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
use crate::pages::edit_wall::EditWall;
|
use crate::pages;
|
||||||
use crate::pages::wall::Wall;
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_router::components::*;
|
use leptos_router::components::*;
|
||||||
use leptos_router::path;
|
use leptos_router::path;
|
||||||
@@ -42,8 +41,9 @@ pub fn App() -> impl leptos::IntoView {
|
|||||||
<Router>
|
<Router>
|
||||||
<main>
|
<main>
|
||||||
<Routes fallback=|| "Not found">
|
<Routes fallback=|| "Not found">
|
||||||
<Route path=path!("/wall") view=Wall />
|
<Route path=path!("/") view=pages::wall::Wall />
|
||||||
<Route path=path!("/wall/edit") view=EditWall />
|
<Route path=path!("/wall/edit") view=pages::edit_wall::EditWall />
|
||||||
|
<Route path=path!("/wall/routes") view=pages::routes::Routes />
|
||||||
</Routes>
|
</Routes>
|
||||||
</main>
|
</main>
|
||||||
</Router>
|
</Router>
|
||||||
|
|||||||
@@ -11,6 +11,52 @@ pub struct HeaderItem {
|
|||||||
pub link: Option<String>,
|
pub link: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Header with background color etc.
|
||||||
|
#[component]
|
||||||
|
pub fn StyledHeader(items: HeaderItems) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="flex">
|
||||||
|
// Left gradient chunk
|
||||||
|
<div class="flex-grow">
|
||||||
|
<div class="h-2/5" style="background: #eaac53" />
|
||||||
|
<div
|
||||||
|
class="h-3/5"
|
||||||
|
style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-none container mx-auto text-black" style="background: #eaac53">
|
||||||
|
<Header items />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Right gradient chunk
|
||||||
|
<div class="flex-grow" style="background: #eaac53" />
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
// Left gradient chunk
|
||||||
|
<div class="flex-grow" />
|
||||||
|
|
||||||
|
<div class="flex-none container mx-auto">
|
||||||
|
// Background color gradient
|
||||||
|
<div
|
||||||
|
class="h-6"
|
||||||
|
style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// Right gradient chunk
|
||||||
|
<div class="flex-grow">
|
||||||
|
<div class="h-4/5" style="background: #eaac53" />
|
||||||
|
<div
|
||||||
|
class="h-1/5"
|
||||||
|
style="background: linear-gradient(to bottom right, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function header without styling
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Header(items: HeaderItems) -> impl IntoView {
|
pub fn Header(items: HeaderItems) -> impl IntoView {
|
||||||
let HeaderItems { left, middle, right } = items;
|
let HeaderItems { left, middle, right } = items;
|
||||||
@@ -18,17 +64,17 @@ pub fn Header(items: HeaderItems) -> impl IntoView {
|
|||||||
view! {
|
view! {
|
||||||
<div class="grid grid-cols-[1fr_3fr_1fr] text-xl font-semibold p-4">
|
<div class="grid grid-cols-[1fr_3fr_1fr] text-xl font-semibold p-4">
|
||||||
// Left side of header
|
// Left side of header
|
||||||
<div>
|
<div class="justify-self-start">
|
||||||
<Items items=left />
|
<Items items=left />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
// Expanding space in the middle
|
// Expanding space in the middle
|
||||||
<div class="w-fit mx-auto font-semibold">
|
<div class="justify-self-center font-semibold">
|
||||||
<Items items=middle />
|
<Items items=middle />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
// Right side of header
|
// Right side of header
|
||||||
<div>
|
<div class="justify-self-end">
|
||||||
<Items items=right />
|
<Items items=right />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,7 +83,12 @@ pub fn Header(items: HeaderItems) -> impl IntoView {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn Items(items: Vec<HeaderItem>) -> impl IntoView {
|
fn Items(items: Vec<HeaderItem>) -> impl IntoView {
|
||||||
items.into_iter().map(|item| view! { <Item item /> }).collect_view()
|
let items = items.into_iter().map(|item| view! { <Item item /> }).collect_view();
|
||||||
|
view! {
|
||||||
|
<div class="flex gap-4">
|
||||||
|
{ items }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod pages {
|
pub mod pages {
|
||||||
pub mod edit_wall;
|
pub mod edit_wall;
|
||||||
|
pub mod routes;
|
||||||
pub mod wall;
|
pub mod wall;
|
||||||
}
|
}
|
||||||
pub mod components {
|
pub mod components {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::codec::ron::RonCodec;
|
use crate::codec::ron::RonCodec;
|
||||||
use crate::components::header::Header;
|
|
||||||
use crate::components::header::HeaderItem;
|
use crate::components::header::HeaderItem;
|
||||||
use crate::components::header::HeaderItems;
|
use crate::components::header::HeaderItems;
|
||||||
|
use crate::components::header::StyledHeader;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
use crate::models::HoldPosition;
|
use crate::models::HoldPosition;
|
||||||
use crate::models::Wall;
|
use crate::models::Wall;
|
||||||
@@ -26,7 +26,7 @@ pub fn EditWall() -> impl leptos::IntoView {
|
|||||||
let header_items = HeaderItems {
|
let header_items = HeaderItems {
|
||||||
left: vec![HeaderItem {
|
left: vec![HeaderItem {
|
||||||
text: "← Ascend".to_string(),
|
text: "← Ascend".to_string(),
|
||||||
link: Some("/wall".to_string()),
|
link: Some("/".to_string()),
|
||||||
}],
|
}],
|
||||||
middle: vec![HeaderItem {
|
middle: vec![HeaderItem {
|
||||||
text: "EDIT WALL".to_string(),
|
text: "EDIT WALL".to_string(),
|
||||||
@@ -37,44 +37,7 @@ pub fn EditWall() -> impl leptos::IntoView {
|
|||||||
|
|
||||||
leptos::view! {
|
leptos::view! {
|
||||||
<div class="min-w-screen min-h-screen bg-slate-900">
|
<div class="min-w-screen min-h-screen bg-slate-900">
|
||||||
<div class="flex">
|
<StyledHeader items=header_items />
|
||||||
// Left gradient chunk
|
|
||||||
<div class="flex-grow">
|
|
||||||
<div class="h-2/5" style="background: #eaac53" />
|
|
||||||
<div
|
|
||||||
class="h-3/5"
|
|
||||||
style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-none container mx-auto text-black" style="background: #eaac53">
|
|
||||||
<Header items=header_items />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
// Right gradient chunk
|
|
||||||
<div class="flex-grow" style="background: #eaac53" />
|
|
||||||
</div>
|
|
||||||
<div class="flex">
|
|
||||||
// Left gradient chunk
|
|
||||||
<div class="flex-grow" />
|
|
||||||
|
|
||||||
<div class="flex-none container mx-auto">
|
|
||||||
// Background color gradient
|
|
||||||
<div
|
|
||||||
class="h-6"
|
|
||||||
style="background: linear-gradient(to bottom left, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
// Right gradient chunk
|
|
||||||
<div class="flex-grow">
|
|
||||||
<div class="h-4/5" style="background: #eaac53" />
|
|
||||||
<div
|
|
||||||
class="h-1/5"
|
|
||||||
style="background: linear-gradient(to bottom right, #eaac53 49.5%, rgb(15 23 42) 50.5%)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mx-auto mt-2">
|
<div class="container mx-auto mt-2">
|
||||||
<Await future=load let:data>
|
<Await future=load let:data>
|
||||||
@@ -94,7 +57,7 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
|
|||||||
holds.push(view! { <Hold hold /> });
|
holds.push(view! { <Hold hold /> });
|
||||||
}
|
}
|
||||||
|
|
||||||
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-2", data.wall.rows, data.wall.cols);
|
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-3", data.wall.rows, data.wall.cols);
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
85
crates/ascend/src/pages/routes.rs
Normal file
85
crates/ascend/src/pages/routes.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use crate::codec::ron::RonCodec;
|
||||||
|
use crate::components::header::HeaderItem;
|
||||||
|
use crate::components::header::HeaderItems;
|
||||||
|
use crate::components::header::StyledHeader;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Routes() -> impl leptos::IntoView {
|
||||||
|
let load = async move {
|
||||||
|
// TODO: What to do about this unwrap?
|
||||||
|
load_initial_data().await.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let header_items = HeaderItems {
|
||||||
|
left: vec![HeaderItem {
|
||||||
|
text: "← Ascend".to_string(),
|
||||||
|
link: Some("/".to_string()),
|
||||||
|
}],
|
||||||
|
middle: vec![HeaderItem {
|
||||||
|
text: "ROUTES".to_string(),
|
||||||
|
link: None,
|
||||||
|
}],
|
||||||
|
right: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
leptos::view! {
|
||||||
|
<div class="min-w-screen min-h-screen bg-slate-900">
|
||||||
|
<StyledHeader items=header_items />
|
||||||
|
|
||||||
|
<div class="container mx-auto mt-2">
|
||||||
|
<Await future=load let:data>
|
||||||
|
<Ready data=data.deref().to_owned() />
|
||||||
|
</Await>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Ready(data: InitialData) -> impl leptos::IntoView {
|
||||||
|
tracing::debug!("ready");
|
||||||
|
|
||||||
|
// let import_from_mini_moonboard = Action::from(ServerAction::<ImportFromMiniMoonboard>::new());
|
||||||
|
|
||||||
|
view! {
|
||||||
|
// <p>"Import problems from"</p>
|
||||||
|
// <button on:click=import_from_mini_moonboard>"Mini Moonboard"</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct InitialData {}
|
||||||
|
|
||||||
|
#[server]
|
||||||
|
async fn load_initial_data() -> Result<RonCodec<InitialData>, ServerFnError> {
|
||||||
|
// use crate::server::state::State;
|
||||||
|
// let state = expect_context::<State>();
|
||||||
|
|
||||||
|
Ok(RonCodec::new(InitialData {}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[server(name = ImportFromMiniMoonboard)]
|
||||||
|
#[tracing::instrument]
|
||||||
|
async fn import_from_mini_moonboard() -> Result<(), ServerFnError> {
|
||||||
|
tracing::info!("Importing mini moonboard problems");
|
||||||
|
|
||||||
|
let file_path: PathBuf = todo!();
|
||||||
|
|
||||||
|
let problems = crate::server::import_mini_moonboard_problems(&file_path).await?;
|
||||||
|
|
||||||
|
use crate::server::state::State;
|
||||||
|
let state = expect_context::<State>();
|
||||||
|
state
|
||||||
|
.persistent
|
||||||
|
.update(|s| {
|
||||||
|
s.problems.problems.extend(problems);
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::codec::ron::RonCodec;
|
use crate::codec::ron::RonCodec;
|
||||||
use crate::components::header::Header;
|
|
||||||
use crate::components::header::HeaderItem;
|
use crate::components::header::HeaderItem;
|
||||||
use crate::components::header::HeaderItems;
|
use crate::components::header::HeaderItems;
|
||||||
|
use crate::components::header::StyledHeader;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
use crate::models::HoldRole;
|
use crate::models::HoldRole;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
@@ -23,16 +23,23 @@ pub fn Wall() -> impl leptos::IntoView {
|
|||||||
text: "Ascend".to_string(),
|
text: "Ascend".to_string(),
|
||||||
link: None,
|
link: None,
|
||||||
}],
|
}],
|
||||||
right: vec![HeaderItem {
|
right: vec![
|
||||||
text: "Edit wall".to_string(),
|
HeaderItem {
|
||||||
|
text: "Routes".to_string(),
|
||||||
|
link: Some("/wall/routes".to_string()),
|
||||||
|
},
|
||||||
|
HeaderItem {
|
||||||
|
text: "Holds".to_string(),
|
||||||
link: Some("/wall/edit".to_string()),
|
link: Some("/wall/edit".to_string()),
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
leptos::view! {
|
leptos::view! {
|
||||||
<div class="min-w-screen min-h-screen bg-slate-900">
|
<div class="min-w-screen min-h-screen bg-slate-900">
|
||||||
<div class="container mx-auto">
|
<StyledHeader items=header_items />
|
||||||
<Header items=header_items />
|
|
||||||
|
<div class="container mx-auto mt-2">
|
||||||
<Await future=load let:data>
|
<Await future=load let:data>
|
||||||
<Ready data=data.deref().to_owned() />
|
<Ready data=data.deref().to_owned() />
|
||||||
</Await>
|
</Await>
|
||||||
@@ -64,7 +71,7 @@ fn Ready(data: InitialData) -> impl leptos::IntoView {
|
|||||||
cells.push(cell);
|
cells.push(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-2", data.wall.rows, data.wall.cols);
|
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-3", data.wall.rows, data.wall.cols);
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div class=move || { grid_classes.clone() }>{cells}</div>
|
<div class=move || { grid_classes.clone() }>{cells}</div>
|
||||||
@@ -83,7 +90,7 @@ fn Hold(hold: models::Hold, #[prop(into)] role: Signal<Option<HoldRole>>) -> imp
|
|||||||
// None => Some("brightness-50"),
|
// None => Some("brightness-50"),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let mut s = "bg-indigo-100 aspect-square rounded".to_string();
|
let mut s = "bg-sky-100 aspect-square rounded".to_string();
|
||||||
if let Some(c) = role_classes {
|
if let Some(c) = role_classes {
|
||||||
s.push(' ');
|
s.push(' ');
|
||||||
s.push_str(c);
|
s.push_str(c);
|
||||||
@@ -93,7 +100,7 @@ fn Hold(hold: models::Hold, #[prop(into)] role: Signal<Option<HoldRole>>) -> imp
|
|||||||
|
|
||||||
let img = hold.image.map(|img| {
|
let img = hold.image.map(|img| {
|
||||||
let src = format!("/files/holds/{}", img.filename);
|
let src = format!("/files/holds/{}", img.filename);
|
||||||
view! { <img class="hover:object-scale-down object-cover w-full h-full" src=src /> }
|
view! { <img class="object-cover w-full h-full" src=src /> }
|
||||||
});
|
});
|
||||||
|
|
||||||
view! { <div class=class>{img}</div> }
|
view! { <div class=class>{img}</div> }
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ pub mod state {
|
|||||||
|
|
||||||
pub mod persistence;
|
pub mod persistence;
|
||||||
|
|
||||||
pub const STATE_FILE: &str = "state.ron";
|
pub const STATE_FILE: &str = "datastore/private/state.ron";
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
@@ -127,6 +127,8 @@ async fn serve() -> Result<(), Error> {
|
|||||||
use leptos_axum::LeptosRoutes;
|
use leptos_axum::LeptosRoutes;
|
||||||
use leptos_axum::generate_route_list;
|
use leptos_axum::generate_route_list;
|
||||||
|
|
||||||
|
run_migrations().await.map_err(self::Error::Migration)?;
|
||||||
|
|
||||||
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
||||||
// For deployment these variables are:
|
// For deployment these variables are:
|
||||||
// <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
|
// <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
|
||||||
@@ -166,10 +168,11 @@ async fn load_state() -> Result<State, Error> {
|
|||||||
tracing::info!("Loading state");
|
tracing::info!("Loading state");
|
||||||
|
|
||||||
let p = PathBuf::from(STATE_FILE);
|
let p = PathBuf::from(STATE_FILE);
|
||||||
|
|
||||||
let persistent = if p.try_exists()? {
|
let persistent = if p.try_exists()? {
|
||||||
tracing::info!("No state found at {STATE_FILE}, creating default state");
|
|
||||||
Persistent::<PersistentState>::load(&p).await?
|
Persistent::<PersistentState>::load(&p).await?
|
||||||
} else {
|
} else {
|
||||||
|
tracing::info!("No state found at {STATE_FILE}, creating default state");
|
||||||
Persistent::<PersistentState>::new(PersistentState::default(), p)
|
Persistent::<PersistentState>::new(PersistentState::default(), p)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -177,7 +180,7 @@ async fn load_state() -> Result<State, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
async fn import_mini_moonboard_problems(file_path: &Path) -> Result<Vec<Problem>, Error> {
|
pub(crate) async fn import_mini_moonboard_problems(file_path: &Path) -> Result<Vec<Problem>, Error> {
|
||||||
let mut problems = Vec::new();
|
let mut problems = Vec::new();
|
||||||
|
|
||||||
tracing::info!("Parsing mini moonboard problems from {}", file_path.display());
|
tracing::info!("Parsing mini moonboard problems from {}", file_path.display());
|
||||||
@@ -203,10 +206,28 @@ async fn import_mini_moonboard_problems(file_path: &Path) -> Result<Vec<Problem>
|
|||||||
Ok(problems)
|
Ok(problems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn run_migrations() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// State file moved to datastore/private
|
||||||
|
{
|
||||||
|
let m = PathBuf::from("state.ron");
|
||||||
|
if m.try_exists()? {
|
||||||
|
tracing::warn!("MIGRATING STATE FILE");
|
||||||
|
let p = PathBuf::from(STATE_FILE);
|
||||||
|
tokio::fs::create_dir_all(p.parent().unwrap()).await?;
|
||||||
|
tokio::fs::rename(m, &p).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
|
#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
|
||||||
#[display("Server crash")]
|
#[display("Server crash: {_variant}")]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
Persistence(persistence::Error),
|
Persistence(persistence::Error),
|
||||||
Parser(moonboard_parser::Error),
|
Parser(moonboard_parser::Error),
|
||||||
|
|
||||||
|
#[display("Failed migration")]
|
||||||
|
Migration(Box<dyn std::error::Error>),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ impl<T> Persistent<T> {
|
|||||||
{
|
{
|
||||||
tracing::debug!("Persisting state");
|
tracing::debug!("Persisting state");
|
||||||
let serialized = ron::ser::to_string_pretty(state, ron::ser::PrettyConfig::default()).map_err(|source| Error::Serialize { source })?;
|
let serialized = ron::ser::to_string_pretty(state, ron::ser::PrettyConfig::default()).map_err(|source| Error::Serialize { source })?;
|
||||||
|
if let Some(parent) = file_path.parent() {
|
||||||
|
tokio::fs::create_dir_all(parent).await.map_err(|source| Error::CreateDir {
|
||||||
|
source,
|
||||||
|
dir: parent.to_owned(),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
tokio::fs::write(file_path, serialized).await.map_err(|source| Error::Write {
|
tokio::fs::write(file_path, serialized).await.map_err(|source| Error::Write {
|
||||||
file_path: file_path.to_owned(),
|
file_path: file_path.to_owned(),
|
||||||
source,
|
source,
|
||||||
@@ -122,4 +128,7 @@ pub enum Error {
|
|||||||
|
|
||||||
#[display("Failed to write file: {}", file_path.display())]
|
#[display("Failed to write file: {}", file_path.display())]
|
||||||
Write { file_path: PathBuf, source: std::io::Error },
|
Write { file_path: PathBuf, source: std::io::Error },
|
||||||
|
|
||||||
|
#[display("Failed to create directory: {}", dir.display())]
|
||||||
|
CreateDir { dir: PathBuf, source: std::io::Error },
|
||||||
}
|
}
|
||||||
|
|||||||
5
justfile
5
justfile
@@ -30,3 +30,8 @@ reset-state:
|
|||||||
# Open firewall port for development
|
# Open firewall port for development
|
||||||
open-firewall:
|
open-firewall:
|
||||||
sudo nixos-firewall-tool open tcp 1337
|
sudo nixos-firewall-tool open tcp 1337
|
||||||
|
|
||||||
|
# Remove local datastore and copy prod datastore
|
||||||
|
cp-prod-datastore:
|
||||||
|
rm -r datastore
|
||||||
|
rsync --human-readable --recursive --info=stats1,progress2 --archive 192.168.1.3:/home/ascend/datastore .
|
||||||
|
|||||||
Reference in New Issue
Block a user