Skip to content

Commit

Permalink
Merge pull request #6 from geofmureithi/chore/v0.1.0-beta
Browse files Browse the repository at this point in the history
v0.1.0 beta
  • Loading branch information
geofmureithi authored Jan 19, 2024
2 parents 77238f0 + 200dcdb commit 9cf6932
Show file tree
Hide file tree
Showing 18 changed files with 355 additions and 164 deletions.
148 changes: 95 additions & 53 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Kasuku.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[internals]
cache-path = "/tmp/kasuku-cache"
cache-path = "/tmp/kasuku-cache-99"

[vaults]
planning = { plugins = ["tasks", "dataview"], mount = "/home/geoff/Documents/kasuku" }
Expand Down
47 changes: 37 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
# Kasuku

Kasuku is a all-in-one personal management system using wasm
Kasuku is lightweight, extensible all-in-one planning tool that makes every day more efficient.

<!-- ![Kasuku Screenshot](screenshot.png) -->
## Features 🌟

## Todo Features
- **Efficient & Lightweight**: Built in Rust with a low memory footprint and light plugins.
- **Cross-Platform**: Runs smoothly on Web, Mobile, and Desktop.
- **Customizable**: Extend functionality with Rust-based plugins compiled into WASM.
- **Dynamic SQL Engine**: Powerful data management with an inbuilt SQL engine.

- [**📝Tasks:**](/plugins/tasks/) Stay on top of your to-do list and tasks. Mark tasks as complete, set priorities, and organize your day.
## Ready plugins 🎉

- **Notes:** Capture your thoughts, ideas, and inspirations. Organize notes into categories and easily search for them.
### 📝 Tasks

- **Fitness:** Track your workouts, diet plans, and health metrics. Set fitness goals and monitor your progress.
Prioritize, organize, and tackle your goals. [🔗](/plugins/tasks/)

- **Finance:** Manage your budgets, expenses, and income. Gain insights into your financial health and savings.
### 🤓 DataView

- **Files:** Organize important files and documents of various formats. Easily access and store your files securely.
SQL + Markdown = Magic! Query your heart out and manipulate data like a wizard. [🔗](/plugins/dataview/)

- **Schedule:** Keep your schedule organized. Schedule events, meetings, and appointments with ease.
### 🎨 Templates

- **Growth:** Cultivate personal growth by tracking skills learned and knowledge gained. Set goals and measure progress.
Say goodbye to monotony. Automate with templates and free up time for the fun stuff. [🔗](/plugins/template/)

## But Wait, There's More! 🚀 Upcoming Plugins:

### 🌐 Web Clipper

Soon, you'll be able to snag bits of the web directly into Kasuku. Research, resources, inspirations—clip it all!

### 📊 Dashboard

Visualize your progress with customizable dashboards. See your productivity soar in vibrant charts and graphs.

### 🕹️ Gamify

Turn tasks into a game. Earn points, level up, and make productivity an adventure.

### 📅 Calendar Sync

Seamlessly integrate with your favorite calendars. Never miss a beat, meeting, or milestone.

### 🧠 Mind Mapper

Brainstorming made beautiful. Organize thoughts, ideas, and plans in visually stunning mind maps.

Stay tuned for these exciting additions! With Kasuku, your productivity journey just keeps getting better. ✨

## Installation

Expand Down
2 changes: 1 addition & 1 deletion core/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ plugy = { version = "0.3.1", default-features = false, features = [
anyhow = "1"
bincode = "1"
heck = "0.4"
hirola = { version = "0.4.0-beta.0", default-features = false }
hirola = { version = "0.4.0", default-features = false }
serde_json = "1"
figment = { version = "0.10", features = ["toml", "env"] }
async-walkdir = "0.2.0"
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl KasukuRuntime {
let mut glue_db = Glue::new(kasuku_database);
glue_db
.execute(
" DROP TABLE IF EXISTS subscriptions;
"DROP TABLE IF EXISTS subscriptions;
DROP TABLE IF EXISTS vaults;
DROP TABLE IF EXISTS entries;
DROP TABLE IF EXISTS tasks;
Expand Down Expand Up @@ -125,7 +125,7 @@ impl KasukuRuntime {
))?
)))
.await
.map_err(|err| types::Error::DatabaseError(err.to_string()))?
// .map_err(|err| types::Error::DatabaseError(err.to_string()))?
.map_err(|err| types::Error::DatabaseError(err.to_string()))?;
let mv_act = mv_act.clone();
tokio::spawn(async move {
Expand Down
87 changes: 48 additions & 39 deletions core/backend/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use async_graphql::*;
use interface::PluginWrapper;
use kasuku_database::prelude::Payload;
use markdown::AsMarkdown;
use markdown::IsMatched;
use markdown::MarkdownEvent;
use node::Node;
use serde::Deserialize;
use serde::Serialize;

Expand Down Expand Up @@ -54,63 +54,72 @@ impl QueryRoot {
.database
.lock()
.unwrap()
.execute("SELECT * FROM subscriptions WHERE event = 'MarkdownEvent';")
.execute("SELECT * FROM subscriptions WHERE event = 'markdown::MarkdownEvent';")
.unwrap();
let subscriptions = res.get(0).unwrap();

Check failure on line 59 in core/backend/src/query.rs

View workflow job for this annotation

GitHub Actions / Clippy

accessing first element with `res.get(0)`
match subscriptions {

let render = match subscriptions {
Payload::Select { rows, .. } => {
let _filters: Vec<MarkdownEvent> = rows
let filters: Vec<(MarkdownEvent, String)> = rows
.iter()
.map(|row| match row.get(3).unwrap() {
kasuku_database::prelude::Value::Str(val) => {
serde_json::from_str(val).unwrap()
}
_ => unreachable!(),
.map(|row| {
(
match row.get(3).unwrap() {
kasuku_database::prelude::Value::Str(val) => {
serde_json::from_str(val).unwrap()
}
_ => unreachable!(),
},
row.get(0)

Check failure on line 73 in core/backend/src/query.rs

View workflow job for this annotation

GitHub Actions / Clippy

accessing first element with `row.get(0)`
.map(|s| match s {
kasuku_database::prelude::Value::Str(txt) => txt.clone(),
_ => unreachable!(),
})
.unwrap(),
)
})
.collect();
let tasks: PluginWrapper<BackendPlugin, _> =
runtime.get_plugin_by_name("tasks").unwrap();
let dataview: PluginWrapper<BackendPlugin, _> =
runtime.get_plugin_by_name("dataview").unwrap();
let mut md = {
let md = tokio::fs::read_to_string(&path).await.unwrap();
let md = tokio::fs::read_to_string(&path).await.unwrap();

let events = markdown::parse(&md).unwrap();
let events = markdown::parse(&md).unwrap();
let plugins: Vec<String> = events
.events
.iter()
.flat_map(move |event| {
filters
.clone()
.iter()
.filter(move |filter| filter.0.is_matched(event).unwrap())
.map(|c| c.1.clone())
.collect::<Vec<_>>()
})
.collect::<std::collections::HashSet<String>>()
.into_iter()
.collect::<Vec<String>>();
let mut md = {
::types::File {
data: ::types::FileType::Markdown(bincode::serialize(&events).unwrap()),
path,
}
};
md = tasks
.process_file(::context::Context::acquire(), md)
.await
.unwrap();
md = dataview
.process_file(::context::Context::acquire(), md)
.await
.unwrap();
for plugin in plugins {
println!("{plugin:?}");
let plugin: PluginWrapper<BackendPlugin, _> =
runtime.get_plugin_by_name(&plugin).unwrap();
md = plugin
.process_file(::context::Context::acquire(), md)
.await
.unwrap();
}
let mut buf = String::new();
let md_events = &md.data.to_markdown().unwrap().events;
pulldown_cmark_to_cmark::cmark(md_events.iter(), &mut buf).unwrap();
println!("{buf}");
buf
}
_ => unreachable!(),
};

let plugin: PluginWrapper<BackendPlugin, _> = runtime.get_plugin_by_name("tasks").unwrap();
let res = plugin
.render(
::context::Context::acquire(),
Event {
namespace: "".to_string(),
data: vec![],
},
)
.await
.unwrap();
let nodes: Node = res.try_into().unwrap();

serde_json::to_value(&nodes).unwrap()
serde_json::to_value(render).unwrap()
}
async fn vaults(&self, ctx: &Context<'_>) -> Vec<Vault> {
let runtime: &KasukuRuntime = ctx.data().unwrap();
Expand Down
6 changes: 5 additions & 1 deletion core/frontend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
hirola = { version = "0.4.0-beta.0", features = ["dom"] }
hirola = { version = "0.4.0", features = ["dom"] }
wasm-bindgen = "0.2.87"
js-sys = "0.3"
gloo-file = "0.3.0"
gloo-net = "0.3.0"
serde = "1"
serde_json = "1"
wasm-bindgen-futures = "0.4"

[dependencies.web-sys]
version = "0.3.22"
Expand Down
6 changes: 5 additions & 1 deletion core/frontend/Trunk.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[build]
target = "index.html"
dist = "dist"
dist = "dist"

[[proxy]]
rewrite = "/api/v1/graphql"
backend = "http://localhost:3001/"
60 changes: 60 additions & 0 deletions core/frontend/src/graphql.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use gloo_net::http::Request;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct GraphQLQuery {
query: String,
variables: Variables,
}

#[derive(Serialize)]
struct Variables {
path: String,
renderer: Option<String>,
}

#[derive(Deserialize)]
struct GraphQLResponse<T> {
data: T,
errors: Option<Vec<GraphQLError>>,
}

#[derive(Deserialize)]
struct GraphQLError {
message: String,
// other fields...
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenderFileResponse {
pub render_file: String,
}

pub async fn render_file(
path: String,
renderer: Option<String>,
) -> Result<RenderFileResponse, String> {
let query = GraphQLQuery {
query: "query RenderFile($path: String!, $renderer: String) { renderFile(path: $path, renderer: $renderer) }".to_string(),
variables: Variables { path, renderer },
};
let response = Request::post("/api/v1/graphql")
.json(&query)
.expect("Failed to build request")
.send()
.await
.map_err(|err| err.to_string())?;

if !response.ok() {
return Err("Network error".to_string());
}

let response_body: GraphQLResponse<RenderFileResponse> =
response.json().await.map_err(|err| err.to_string())?;

if let Some(errors) = response_body.errors {
return Err(errors[0].message.clone());
}

Ok(response_body.data)
}
65 changes: 17 additions & 48 deletions core/frontend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
mod graphql;
mod tab_view;

use crate::tab_view::TabView;
use hirola::dom::app::App;
use hirola::dom::Dom;
use hirola::dom::*;
use hirola::prelude::*;

#[component]
Expand Down Expand Up @@ -105,53 +106,21 @@ extern "C" {
#[component]
fn MarkdownPage() -> Dom {
let fut = async {
let _editor = createTipTapEditor(
"content",
"# Prototyping from A to Z \n This **word** is bold.
- [x] #739
- [ ] https://github.com/octo-org/octo-repo/issues/740
- [ ] Add delight to the experience when all tasks are complete :tada:
| Syntax | Description |
| ----------- | ----------- |
| Header | Title |
| Paragraph | Text |
```sql
SELECT * FROM tasks WHERE completed = FALSE;
```
",
);
graphql::render_file(
"/home/geoff/Documents/kasuku/Tasks/apalis/v0.5/2023-07-28.md".to_string(),
None,
)
.await
.map(|page| {
let _editor = createTipTapEditor("content", &page.render_file);
})
.unwrap();
};
html! {
<>
<TabView/>
<div class="menu-1"><button class="h-8 w-8 i-gridicons-heading-h1">"H1"</button></div>
<article use:fut id="content" un-cloak="">
// <h1>"Prototyping from A to Z"</h1>
// <h2>"When does design come in handy?"</h2>
// <p>
// "While it might seem like extra work at a first glance, here are some key moments in which prototyping will come in handy:"
// </p>
// <ol>
// <li>
// <strong>"Usability testing"</strong>
// ". Does your user know how to exit out of screens? Can they follow your intended user journey and buy something from the site you’ve designed? By running a usability test, you’ll be able to see how users will interact with your design once it’s live;"
// </li>
// <li>
// <strong>"Involving stakeholders"</strong>
// ". Need to check if your GDPR consent boxes are displaying properly? Pass your prototype to your data protection team and they can test it for real;"
// </li>
// <li>
// <strong>"Impressing a client"</strong>
// ". Prototypes can help explain or even sell your idea by providing your client with a hands-on experience;"
// </li>
// <li>
// <strong>"Communicating your vision"</strong>
// ". By using an interactive medium to preview and test design elements, designers and developers can understand each other — and the project — better."
// </li>
// </ol>
<article use:future={fut} id="content" un-cloak="">
</article>

</>
Expand Down Expand Up @@ -283,11 +252,11 @@ fn home(_: &App<()>) -> Dom {
fn main() {
let mut app = App::new(());
app.route("/", home);
app.route("/vault/:vault/:file", home); // View a specific file
app.route("/quick/:plugin/:view", home); // Render a specific quick view
app.route("/plugins", home); // View plugins
app.route("/plugins/:plugin", home); // View specific plugin
app.route("/plugins/:plugin/config", home); // Config specific plugin
// app.route("/vault/:vault/:file", home); // View a specific file
// app.route("/quick/:plugin/:view", home); // Render a specific quick view
// app.route("/plugins", home); // View plugins
// app.route("/plugins/:plugin", home); // View specific plugin
// app.route("/plugins/:plugin/config", home); // Config specific plugin

let parent_node = web_sys::window()
.unwrap()
Expand Down
Loading

0 comments on commit 9cf6932

Please sign in to comment.