c2vi dash working
This commit is contained in:
1773
Cargo.lock
generated
1773
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
139
flake.nix
139
flake.nix
@@ -35,7 +35,7 @@ let
|
||||
];
|
||||
wasmCrane = (crane.mkLib pkgs).overrideToolchain wasmToolchain;
|
||||
|
||||
osToolchain = fenix.packages.${system}.nightly.toolchain;
|
||||
osToolchain = fenix.packages.${system}.latest.toolchain;
|
||||
|
||||
osCrane = (crane.mkLib pkgs).overrideToolchain osToolchain;
|
||||
|
||||
@@ -120,11 +120,67 @@ in {
|
||||
});
|
||||
};
|
||||
};
|
||||
fileSetForCrate =
|
||||
crate:
|
||||
pkgs.lib.fileset.toSource {
|
||||
root = ./.;
|
||||
fileset = pkgs.lib.fileset.unions [
|
||||
./Cargo.toml
|
||||
./Cargo.lock
|
||||
(craneLib.fileset.commonCargoSources ./packages/marts)
|
||||
(craneLib.fileset.commonCargoSources ./packages/mize)
|
||||
(craneLib.fileset.commonCargoSources ./packages/ppc/spacetimedb)
|
||||
(craneLib.fileset.commonCargoSources ./packages/mme)
|
||||
(craneLib.fileset.commonCargoSources ./packages/vic)
|
||||
(craneLib.fileset.commonCargoSources ./packages/ac_mize_macros)
|
||||
(craneLib.fileset.commonCargoSources crate)
|
||||
];
|
||||
};
|
||||
ppc = osCrane.buildPackage {
|
||||
src = fileSetForCrate ./packages/ppc;
|
||||
cargoExtraArgs = "-p ppc";
|
||||
nativeBuildInputs = [
|
||||
pkgs.pkg-config
|
||||
pkgs.gobject-introspection
|
||||
pkgs.gobject-introspection.dev
|
||||
];
|
||||
|
||||
default = osCrane.buildPackage {
|
||||
src = "${self}";
|
||||
cargoExtraArgs = "--bin mize --features target-os";
|
||||
buildInputs = with pkgs; [
|
||||
git # needed to build spacetimedb as it needs to get it's git hash for setting it's version
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
pango
|
||||
webkitgtk_4_1
|
||||
openssl
|
||||
wasm-bindgen-cli
|
||||
lld_20
|
||||
xdotool
|
||||
];
|
||||
|
||||
LD_LIBRARY_PATH = with pkgs; pkgs.lib.makeLibraryPath [
|
||||
xdotool
|
||||
webkitgtk_4_1
|
||||
pango
|
||||
openssl
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
];
|
||||
};
|
||||
#SPACETIMEDB_NIX_BUILD_GIT_COMMIT =
|
||||
|
||||
wasm = wasmCrane.buildPackage {
|
||||
src = "${self}";
|
||||
@@ -213,6 +269,81 @@ in {
|
||||
|
||||
|
||||
#default = (mizeLib.buildMizeForSystem system).modules.mize.devShell;
|
||||
buildShell = pkgs.mkShell {
|
||||
|
||||
MIZE_BUILD_CONFIG = let
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
in settingsFormat.generate "mize-build-config.toml" {
|
||||
config = {
|
||||
namespace = "mize.buildtime.ns";
|
||||
module_url = "c2vi.dev";
|
||||
};
|
||||
};
|
||||
shellHook = ''
|
||||
mize_project_root=$(${pkgs.lib.getExe pkgs.git} rev-parse --show-toplevel)
|
||||
export MIZE_CONFIG_FILES=$mize_project_root/mize_config.toml
|
||||
'';
|
||||
nativeBuildInputs = [
|
||||
pkgs.wasm-pack
|
||||
pkgs.pkg-config
|
||||
pkgs.gobject-introspection
|
||||
pkgs.gobject-introspection.dev
|
||||
|
||||
# thanks to: https://github.com/NixOS/nixpkgs/pull/496279/changes
|
||||
(pkgs.buildWasmBindgenCli rec {
|
||||
src = pkgs.fetchCrate {
|
||||
pname = "wasm-bindgen-cli";
|
||||
version = "0.2.114";
|
||||
hash = "sha256-xrCym+rFY6EUQFWyWl6OPA+LtftpUAE5pIaElAIVqW0=";
|
||||
};
|
||||
|
||||
cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
|
||||
inherit src;
|
||||
inherit (src) pname version;
|
||||
hash = "sha256-Z8+dUXPQq7S+Q7DWNr2Y9d8GMuEdSnq00quUR0wDNPM=";
|
||||
};
|
||||
})
|
||||
(fenix.packages.${system}.combine [
|
||||
fenix.packages.${system}.latest.toolchain
|
||||
fenix.packages.${system}.targets.wasm32-unknown-unknown.latest.toolchain
|
||||
])
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
pango
|
||||
webkitgtk_4_1
|
||||
openssl
|
||||
wasm-bindgen-cli
|
||||
lld_20
|
||||
xdotool
|
||||
];
|
||||
|
||||
LD_LIBRARY_PATH = with pkgs; pkgs.lib.makeLibraryPath [
|
||||
xdotool
|
||||
webkitgtk_4_1
|
||||
pango
|
||||
openssl
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
];
|
||||
|
||||
};
|
||||
default = pkgs.mkShell {
|
||||
|
||||
MIZE_BUILD_CONFIG = let
|
||||
|
||||
19
md
19
md
@@ -2,7 +2,7 @@
|
||||
set -e
|
||||
|
||||
MIZE_SRC="/home/me/work/mize" # hardcoded for now
|
||||
RSYNC_EXCLUDES="--exclude=.git --exclude=node_modules --exclude=target --exclude=mize_config.toml --exclude=rust_dist --exclude=deno_dist --exclude=dist --exclude=result --exclude=pkg"
|
||||
RSYNC_EXCLUDES="--exclude=node_modules --exclude=target --exclude=mize_config.toml --exclude=rust_dist --exclude=deno_dist --exclude=dist --exclude=result --exclude=pkg"
|
||||
|
||||
function main {
|
||||
if [[ "$1" == "dlu" ]]; then
|
||||
@@ -23,13 +23,22 @@ function deploy_lush {
|
||||
echo "c2vi: Deploying to lush..."
|
||||
|
||||
# Copy files to lush
|
||||
rsync -r -u -v --delete --mkpath $RSYNC_EXCLUDES $MIZE_SRC/* lush:here/mize
|
||||
rsync -r -u -v -a --delete --include=".git/" --include=".git/**" --mkpath $RSYNC_EXCLUDES $MIZE_SRC lush:here
|
||||
|
||||
# compile
|
||||
ssh lush nix develop /home/me/here/mize --impure -v -L -c sh -c "cargo build --release --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml"
|
||||
ssh lush << EOF
|
||||
if ! tmux has-session -t ppc-deploy 2>/dev/null; then
|
||||
echo "Created new tmux session...."
|
||||
tmux new-session -d -s ppc-deploy "nix develop git+file:///home/me/here/mize#buildShell"
|
||||
tmux send-keys -t ppc-deploy "cargo build --featuers desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter
|
||||
tmux send-keys -t ppc-deploy "systemctl --user restart ppc" Enter
|
||||
else
|
||||
echo "using existing session..."
|
||||
tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter
|
||||
tmux send-keys -t ppc-deploy "systemctl --user restart ppc" Enter
|
||||
fi
|
||||
EOF
|
||||
|
||||
# restart service
|
||||
ssh lush "sudo systemctl restart ppc"
|
||||
}
|
||||
|
||||
function deploy_main_website {
|
||||
|
||||
@@ -11,7 +11,7 @@ futures = "0.3.32"
|
||||
mize = { path = "../mize/", default-features = false }
|
||||
tokio = "1.49.0"
|
||||
# https://github.com/rscarson/rustyscript/pull/415
|
||||
rustyscript = { git = 'https://github.com/rscarson/rustyscript', rev = 'e39529eac2c5d37cfcbb7d7d63da7264d7a5afdb', optional = true }
|
||||
#rustyscript = { git = 'https://github.com/rscarson/rustyscript', rev = 'e39529eac2c5d37cfcbb7d7d63da7264d7a5afdb', optional = true }
|
||||
#deno_core = { version = "0.380.1", optional = true }
|
||||
chrono = "0.4.44"
|
||||
reqwest = { version = "0.13.2", features = ["blocking", "json"] }
|
||||
@@ -22,7 +22,7 @@ dioxus = { version = "0.7.1", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["target-os", "desktop", "server"]
|
||||
target-os = [ "clap", "mize/target-os", "rustyscript", "rusqlite", "dioxus" ]
|
||||
target-os = [ "clap", "mize/target-os", "rusqlite", "dioxus" ]
|
||||
desktop = ["dioxus/desktop"]
|
||||
server = []
|
||||
target-js = [ "mize/target-js" ]
|
||||
|
||||
@@ -51,7 +51,7 @@ pub fn c2vi(mize: &mut Mize) -> MizeResult<()> {
|
||||
pub fn c2vi_client(mize: &mut Mize) -> MizeResult<()> {
|
||||
//let storage_path = mize.get_config("c2vi.local_storage_path")?.as_
|
||||
let storage_path = "/home/me/work/app-data/ppc";
|
||||
println!("storage_path: {}", storage_path);
|
||||
//println!("storage_path: {}", storage_path);
|
||||
let db_path = std::path::PathBuf::from(&storage_path).join("data.db");
|
||||
let conn = Connection::open(&db_path)
|
||||
.map_err(|e| mize_err!("Failed to open C2vi database at {:?}: {}", db_path, e))?;
|
||||
|
||||
@@ -51,14 +51,11 @@ pub fn gather_config(mize: &mut Mize) -> MizeResult<()> {
|
||||
println!("reading config file: {config_file_path}");
|
||||
let content = std::fs::read_to_string(config_file_path)?;
|
||||
let mut data = ItemData::from_toml(content.as_str())?;
|
||||
println!("config data: {data}");
|
||||
for path in data.get_paths_recursive()? {
|
||||
let mut conf_name = path.replace("/", ".");
|
||||
if conf_name.starts_with(".") {
|
||||
conf_name.remove(0);
|
||||
}
|
||||
println!("adding config {conf_name} from config file {config_file_path}");
|
||||
println!("path: {:?}", path);
|
||||
let val = data.get_path(path.split("/").filter(|s| s != &"").collect::<Vec<&str>>())?;
|
||||
match config_opts.get_mut(&conf_name) {
|
||||
Some(opt) => {
|
||||
|
||||
@@ -869,7 +869,7 @@ impl Mize {
|
||||
|
||||
// get the cached value
|
||||
if let Some(val) = opt.val.clone() {
|
||||
println!("get_config: {name} has cached value: {val}");
|
||||
//println!("get_config: {name} has cached value: {val}");
|
||||
return Ok(val);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ path = "lib.rs"
|
||||
name = "ppc"
|
||||
|
||||
[features]
|
||||
default = ["target-os", "server", "client"]
|
||||
default = ["target-os", "server", "client", "desktop"]
|
||||
target-os = [ "clap", "mize/target-os", "marts/target-os", "tracing", "webbrowser", "base64", "serde_json", "serde" ]
|
||||
target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-js", "marts/target-js", "base64", "serde_json", "serde", "openidconnect", "dioxus", "dioxus-web", "web-sys", "web-sys/Document", "dioxus/web" ]
|
||||
server = [ "axum", "axum-extra", "openidconnect", "serde", "serde_json", "reqwest", "rand", "url", "time", "tokio", "dioxus/ssr", "dioxus/server", "dioxus/fullstack", "dioxus/router", "dioxus-ssr", "html-escape", "axum-oidc", "tower", "tower-sessions", "marts/server", "target-os" ]
|
||||
|
||||
@@ -3,17 +3,19 @@ use base64::{
|
||||
alphabet::STANDARD,
|
||||
engine::{DecodePaddingMode, GeneralPurpose, GeneralPurposeConfig},
|
||||
};
|
||||
use dioxus::{fullstack::ClientResponse, html::ol};
|
||||
use mize::{Mize, MizeError, MizePart, MizeResult, item::ItemData, mize_err, mize_part};
|
||||
use openidconnect::{
|
||||
AuthorizationCode, ClientId, CsrfToken, DeviceAuthorizationResponse,
|
||||
AccessToken, AuthorizationCode, ClientId, CsrfToken, DeviceAuthorizationResponse,
|
||||
EmptyExtraDeviceAuthorizationFields, IssuerUrl, Nonce, OAuth2TokenResponse, PkceCodeChallenge,
|
||||
PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
|
||||
PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenResponse,
|
||||
core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
path::PathBuf,
|
||||
thread,
|
||||
};
|
||||
|
||||
// console_log macro
|
||||
@@ -45,7 +47,7 @@ pub struct ClientAuth {
|
||||
secrets: Option<ClientSecrets>,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct ClientSecrets {
|
||||
id_token: String,
|
||||
access_token: String,
|
||||
@@ -79,23 +81,64 @@ impl ClientAuth {
|
||||
}
|
||||
Ok(&self.secrets.as_ref().unwrap().refresh_token)
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self) -> MizeResult<()> {
|
||||
let secrets = self.secrets.clone().ok_or(mize_err!(
|
||||
"no client secrets, meaning the refresh thread can't use the refresh token"
|
||||
))?;
|
||||
self.mize.spawn_async_blocking(
|
||||
"auth.refresh_flow",
|
||||
refresh_flow(self.mize.clone(), secrets),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start_refresh_thread(&mut self) -> MizeResult<()> {
|
||||
let mut mize_clone = self.mize.clone();
|
||||
self.mize.spawn_background("auth.refresh", move || {
|
||||
loop {
|
||||
thread::sleep(Duration::from_hours(23));
|
||||
let mut auth = mize_clone.get_part_native::<ClientAuth>("auth")?;
|
||||
auth.refresh()?;
|
||||
drop(auth);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_auth(mize: &mut Mize) -> MizeResult<()> {
|
||||
let mize_clone = mize.clone();
|
||||
|
||||
let secrets = match read_secrets(mize) {
|
||||
let mut secrets = match read_secrets(mize) {
|
||||
Ok(secrets) => Some(secrets),
|
||||
Err(_) => None,
|
||||
Err(err) => {
|
||||
println!("err reading secrets: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "target-os")]
|
||||
{
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
cli.subcommand(Command::new("login"), |_, mut mize| {
|
||||
let secrets = mize.spawn_async_blocking("client_auth", auth_flow(mize_clone))?;
|
||||
write_secrets(&mut mize, &secrets)?;
|
||||
let mut auth = mize.get_part_native::<ClientAuth>("client_auth")?;
|
||||
println!("secrets: {:?}", auth.secrets);
|
||||
let secrets = if auth.secrets.is_some() {
|
||||
match mize.spawn_async_blocking(
|
||||
"client_auth",
|
||||
refresh_flow(mize.clone(), auth.secrets.clone().unwrap()),
|
||||
) {
|
||||
Ok(secrets) => secrets,
|
||||
Err(err) => {
|
||||
println!("err refreshing secrets: {:?}", err);
|
||||
mize.spawn_async_blocking("client_auth", auth_flow(mize_clone))?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mize.spawn_async_blocking("client_auth", auth_flow(mize_clone))?
|
||||
};
|
||||
write_secrets(&mut mize, &secrets)?;
|
||||
auth.secrets = Some(secrets);
|
||||
Ok(())
|
||||
});
|
||||
@@ -104,6 +147,16 @@ pub fn client_auth(mize: &mut Mize) -> MizeResult<()> {
|
||||
#[cfg(feature = "target-obsidian")]
|
||||
{}
|
||||
|
||||
// check if login token is stil valid refresh if not
|
||||
/*
|
||||
if secrets.is_some() {
|
||||
secrets = Some(mize.spawn_async_blocking(
|
||||
"client_auth",
|
||||
refresh_flow(mize.clone(), secrets.clone().unwrap()),
|
||||
)?);
|
||||
}
|
||||
*/
|
||||
|
||||
mize.register_part(Box::new(ClientAuth {
|
||||
secrets,
|
||||
mize: mize.clone(),
|
||||
@@ -143,13 +196,79 @@ struct Combined<'a> {
|
||||
state: &'a str,
|
||||
}
|
||||
|
||||
use openidconnect::DeviceAuthorizationUrl;
|
||||
use openidconnect::reqwest::Client as HttpClient;
|
||||
use openidconnect::{AuthUrl, DeviceAuthorizationUrl};
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
async fn refresh_flow(mut mize: Mize, old_secrets: ClientSecrets) -> MizeResult<ClientSecrets> {
|
||||
println!("Refresh flow...");
|
||||
let issuer = mize.get_config("auth.client.issuer")?.value_string()?;
|
||||
let client_id = mize.get_config("auth.client.client_id")?.value_string()?;
|
||||
|
||||
let issuer = IssuerUrl::new(issuer)?;
|
||||
let client_id = ClientId::new(client_id);
|
||||
|
||||
let http_client = HttpClient::new();
|
||||
|
||||
// Teach openidconnect-rs about the device authorization url.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
struct MyExtraProviderMetadata {
|
||||
device_authorization_endpoint: String,
|
||||
}
|
||||
use openidconnect::AdditionalProviderMetadata;
|
||||
use openidconnect::ProviderMetadata;
|
||||
use openidconnect::core::{
|
||||
CoreAuthDisplay, CoreClaimName, CoreClaimType, CoreClient, CoreClientAuthMethod,
|
||||
CoreDeviceAuthorizationResponse, CoreGrantType, CoreJsonWebKey, CoreJsonWebKeyType,
|
||||
CoreJsonWebKeyUse, CoreJweContentEncryptionAlgorithm, CoreJweKeyManagementAlgorithm,
|
||||
CoreJwsSigningAlgorithm, CoreResponseMode, CoreResponseType, CoreSubjectIdentifierType,
|
||||
};
|
||||
impl AdditionalProviderMetadata for MyExtraProviderMetadata {}
|
||||
type MyProviderMetadata = ProviderMetadata<
|
||||
MyExtraProviderMetadata,
|
||||
CoreAuthDisplay,
|
||||
CoreClientAuthMethod,
|
||||
CoreClaimName,
|
||||
CoreClaimType,
|
||||
CoreGrantType,
|
||||
CoreJweContentEncryptionAlgorithm,
|
||||
CoreJweKeyManagementAlgorithm,
|
||||
CoreJsonWebKey,
|
||||
CoreResponseMode,
|
||||
CoreResponseType,
|
||||
CoreSubjectIdentifierType,
|
||||
>;
|
||||
|
||||
// Discover provider metadata
|
||||
let provider_metadata: MyProviderMetadata =
|
||||
MyProviderMetadata::discover_async(issuer, &http_client).await?;
|
||||
|
||||
let device_auth_url = provider_metadata
|
||||
.additional_metadata()
|
||||
.device_authorization_endpoint
|
||||
.clone();
|
||||
|
||||
let client = CoreClient::from_provider_metadata(
|
||||
provider_metadata,
|
||||
client_id,
|
||||
None, // public client
|
||||
)
|
||||
.set_device_authorization_url(DeviceAuthorizationUrl::new(device_auth_url)?);
|
||||
|
||||
let refresh_token = RefreshToken::new(old_secrets.refresh_token);
|
||||
let res = client
|
||||
.exchange_refresh_token(&refresh_token)?
|
||||
.request_async(&http_client)
|
||||
.await?;
|
||||
|
||||
return Ok(ClientSecrets {
|
||||
id_token: res.id_token().unwrap().to_string(),
|
||||
access_token: res.access_token().secret().to_owned(),
|
||||
refresh_token: res.refresh_token().unwrap().secret().to_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
async fn auth_flow(mut mize: Mize) -> MizeResult<ClientSecrets> {
|
||||
// ===== CONFIG =====
|
||||
let issuer = mize.get_config("auth.client.issuer")?.value_string()?;
|
||||
let client_id = mize.get_config("auth.client.client_id")?.value_string()?;
|
||||
|
||||
|
||||
60
packages/ppc/generated/action_type.rs
Normal file
60
packages/ppc/generated/action_type.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct Action {
|
||||
pub name: String,
|
||||
pub activity: Option<u64>,
|
||||
pub task: Option<u64>,
|
||||
pub start: Option<__sdk::Timestamp>,
|
||||
pub end: Option<__sdk::Timestamp>,
|
||||
pub duration: Option<u64>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for Action {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
/// Column accessor struct for the table `Action`.
|
||||
///
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct ActionCols {
|
||||
pub name: __sdk::__query_builder::Col<Action, String>,
|
||||
pub activity: __sdk::__query_builder::Col<Action, Option<u64>>,
|
||||
pub task: __sdk::__query_builder::Col<Action, Option<u64>>,
|
||||
pub start: __sdk::__query_builder::Col<Action, Option<__sdk::Timestamp>>,
|
||||
pub end: __sdk::__query_builder::Col<Action, Option<__sdk::Timestamp>>,
|
||||
pub duration: __sdk::__query_builder::Col<Action, Option<u64>>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for Action {
|
||||
type Cols = ActionCols;
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
ActionCols {
|
||||
name: __sdk::__query_builder::Col::new(table_name, "name"),
|
||||
activity: __sdk::__query_builder::Col::new(table_name, "activity"),
|
||||
task: __sdk::__query_builder::Col::new(table_name, "task"),
|
||||
start: __sdk::__query_builder::Col::new(table_name, "start"),
|
||||
end: __sdk::__query_builder::Col::new(table_name, "end"),
|
||||
duration: __sdk::__query_builder::Col::new(table_name, "duration"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexed column accessor struct for the table `Action`.
|
||||
///
|
||||
/// Provides typed access to indexed columns for query building.
|
||||
pub struct ActionIxCols {}
|
||||
|
||||
impl __sdk::__query_builder::HasIxCols for Action {
|
||||
type IxCols = ActionIxCols;
|
||||
fn ix_cols(table_name: &'static str) -> Self::IxCols {
|
||||
ActionIxCols {}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::CanBeLookupTable for Action {}
|
||||
@@ -1,53 +0,0 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::activity_type::Activity;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct Event {
|
||||
pub start: __sdk::Timestamp,
|
||||
pub end: __sdk::Timestamp,
|
||||
pub activity: Activity,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for Event {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
/// Column accessor struct for the table `Event`.
|
||||
///
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct EventCols {
|
||||
pub start: __sdk::__query_builder::Col<Event, __sdk::Timestamp>,
|
||||
pub end: __sdk::__query_builder::Col<Event, __sdk::Timestamp>,
|
||||
pub activity: __sdk::__query_builder::Col<Event, Activity>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for Event {
|
||||
type Cols = EventCols;
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
EventCols {
|
||||
start: __sdk::__query_builder::Col::new(table_name, "start"),
|
||||
end: __sdk::__query_builder::Col::new(table_name, "end"),
|
||||
activity: __sdk::__query_builder::Col::new(table_name, "activity"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexed column accessor struct for the table `Event`.
|
||||
///
|
||||
/// Provides typed access to indexed columns for query building.
|
||||
pub struct EventIxCols {}
|
||||
|
||||
impl __sdk::__query_builder::HasIxCols for Event {
|
||||
type IxCols = EventIxCols;
|
||||
fn ix_cols(table_name: &'static str) -> Self::IxCols {
|
||||
EventIxCols {}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::CanBeLookupTable for Event {}
|
||||
@@ -1,112 +0,0 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use super::activity_type::Activity;
|
||||
use super::event_type::Event;
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
/// Table handle for the table `events`.
|
||||
///
|
||||
/// Obtain a handle from the [`EventsTableAccess::events`] method on [`super::RemoteTables`],
|
||||
/// like `ctx.db.events()`.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.events().on_insert(...)`.
|
||||
pub struct EventsTableHandle<'ctx> {
|
||||
imp: __sdk::TableHandle<Event>,
|
||||
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the table `events`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteTables`].
|
||||
pub trait EventsTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Obtain a [`EventsTableHandle`], which mediates access to the table `events`.
|
||||
fn events(&self) -> EventsTableHandle<'_>;
|
||||
}
|
||||
|
||||
impl EventsTableAccess for super::RemoteTables {
|
||||
fn events(&self) -> EventsTableHandle<'_> {
|
||||
EventsTableHandle {
|
||||
imp: self.imp.get_table::<Event>("events"),
|
||||
ctx: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventsInsertCallbackId(__sdk::CallbackId);
|
||||
pub struct EventsDeleteCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::Table for EventsTableHandle<'ctx> {
|
||||
type Row = Event;
|
||||
type EventContext = super::EventContext;
|
||||
|
||||
fn count(&self) -> u64 {
|
||||
self.imp.count()
|
||||
}
|
||||
fn iter(&self) -> impl Iterator<Item = Event> + '_ {
|
||||
self.imp.iter()
|
||||
}
|
||||
|
||||
type InsertCallbackId = EventsInsertCallbackId;
|
||||
|
||||
fn on_insert(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> EventsInsertCallbackId {
|
||||
EventsInsertCallbackId(self.imp.on_insert(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_insert(&self, callback: EventsInsertCallbackId) {
|
||||
self.imp.remove_on_insert(callback.0)
|
||||
}
|
||||
|
||||
type DeleteCallbackId = EventsDeleteCallbackId;
|
||||
|
||||
fn on_delete(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> EventsDeleteCallbackId {
|
||||
EventsDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_delete(&self, callback: EventsDeleteCallbackId) {
|
||||
self.imp.remove_on_delete(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
|
||||
let _table = client_cache.get_or_make_table::<Event>("events");
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn parse_table_update(
|
||||
raw_updates: __ws::v2::TableUpdate,
|
||||
) -> __sdk::Result<__sdk::TableUpdate<Event>> {
|
||||
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
|
||||
__sdk::InternalError::failed_parse("TableUpdate<Event>", "TableUpdate")
|
||||
.with_cause(e)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for query builder access to the table `Event`.
|
||||
///
|
||||
/// Implemented for [`__sdk::QueryTableAccessor`].
|
||||
pub trait eventsQueryTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Get a query builder for the table `Event`.
|
||||
fn events(&self) -> __sdk::__query_builder::Table<Event>;
|
||||
}
|
||||
|
||||
impl eventsQueryTableAccess for __sdk::QueryTableAccessor {
|
||||
fn events(&self) -> __sdk::__query_builder::Table<Event> {
|
||||
__sdk::__query_builder::Table::new("events")
|
||||
}
|
||||
}
|
||||
60
packages/ppc/generated/log_event_type.rs
Normal file
60
packages/ppc/generated/log_event_type.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::action_type::Action;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct LogEvent {
|
||||
pub id: u64,
|
||||
pub start: __sdk::Timestamp,
|
||||
pub end: __sdk::Timestamp,
|
||||
pub action: Action,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for LogEvent {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
/// Column accessor struct for the table `LogEvent`.
|
||||
///
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct LogEventCols {
|
||||
pub id: __sdk::__query_builder::Col<LogEvent, u64>,
|
||||
pub start: __sdk::__query_builder::Col<LogEvent, __sdk::Timestamp>,
|
||||
pub end: __sdk::__query_builder::Col<LogEvent, __sdk::Timestamp>,
|
||||
pub action: __sdk::__query_builder::Col<LogEvent, Action>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for LogEvent {
|
||||
type Cols = LogEventCols;
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
LogEventCols {
|
||||
id: __sdk::__query_builder::Col::new(table_name, "id"),
|
||||
start: __sdk::__query_builder::Col::new(table_name, "start"),
|
||||
end: __sdk::__query_builder::Col::new(table_name, "end"),
|
||||
action: __sdk::__query_builder::Col::new(table_name, "action"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexed column accessor struct for the table `LogEvent`.
|
||||
///
|
||||
/// Provides typed access to indexed columns for query building.
|
||||
pub struct LogEventIxCols {
|
||||
pub id: __sdk::__query_builder::IxCol<LogEvent, u64>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasIxCols for LogEvent {
|
||||
type IxCols = LogEventIxCols;
|
||||
fn ix_cols(table_name: &'static str) -> Self::IxCols {
|
||||
LogEventIxCols {
|
||||
id: __sdk::__query_builder::IxCol::new(table_name, "id"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::CanBeLookupTable for LogEvent {}
|
||||
160
packages/ppc/generated/log_events_table.rs
Normal file
160
packages/ppc/generated/log_events_table.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use super::action_type::Action;
|
||||
use super::log_event_type::LogEvent;
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
/// Table handle for the table `log_events`.
|
||||
///
|
||||
/// Obtain a handle from the [`LogEventsTableAccess::log_events`] method on [`super::RemoteTables`],
|
||||
/// like `ctx.db.log_events()`.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.log_events().on_insert(...)`.
|
||||
pub struct LogEventsTableHandle<'ctx> {
|
||||
imp: __sdk::TableHandle<LogEvent>,
|
||||
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the table `log_events`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteTables`].
|
||||
pub trait LogEventsTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Obtain a [`LogEventsTableHandle`], which mediates access to the table `log_events`.
|
||||
fn log_events(&self) -> LogEventsTableHandle<'_>;
|
||||
}
|
||||
|
||||
impl LogEventsTableAccess for super::RemoteTables {
|
||||
fn log_events(&self) -> LogEventsTableHandle<'_> {
|
||||
LogEventsTableHandle {
|
||||
imp: self.imp.get_table::<LogEvent>("log_events"),
|
||||
ctx: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LogEventsInsertCallbackId(__sdk::CallbackId);
|
||||
pub struct LogEventsDeleteCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::Table for LogEventsTableHandle<'ctx> {
|
||||
type Row = LogEvent;
|
||||
type EventContext = super::EventContext;
|
||||
|
||||
fn count(&self) -> u64 {
|
||||
self.imp.count()
|
||||
}
|
||||
fn iter(&self) -> impl Iterator<Item = LogEvent> + '_ {
|
||||
self.imp.iter()
|
||||
}
|
||||
|
||||
type InsertCallbackId = LogEventsInsertCallbackId;
|
||||
|
||||
fn on_insert(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> LogEventsInsertCallbackId {
|
||||
LogEventsInsertCallbackId(self.imp.on_insert(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_insert(&self, callback: LogEventsInsertCallbackId) {
|
||||
self.imp.remove_on_insert(callback.0)
|
||||
}
|
||||
|
||||
type DeleteCallbackId = LogEventsDeleteCallbackId;
|
||||
|
||||
fn on_delete(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
|
||||
) -> LogEventsDeleteCallbackId {
|
||||
LogEventsDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_delete(&self, callback: LogEventsDeleteCallbackId) {
|
||||
self.imp.remove_on_delete(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LogEventsUpdateCallbackId(__sdk::CallbackId);
|
||||
|
||||
impl<'ctx> __sdk::TableWithPrimaryKey for LogEventsTableHandle<'ctx> {
|
||||
type UpdateCallbackId = LogEventsUpdateCallbackId;
|
||||
|
||||
fn on_update(
|
||||
&self,
|
||||
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
|
||||
) -> LogEventsUpdateCallbackId {
|
||||
LogEventsUpdateCallbackId(self.imp.on_update(Box::new(callback)))
|
||||
}
|
||||
|
||||
fn remove_on_update(&self, callback: LogEventsUpdateCallbackId) {
|
||||
self.imp.remove_on_update(callback.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Access to the `id` unique index on the table `log_events`,
|
||||
/// which allows point queries on the field of the same name
|
||||
/// via the [`LogEventsIdUnique::find`] method.
|
||||
///
|
||||
/// Users are encouraged not to explicitly reference this type,
|
||||
/// but to directly chain method calls,
|
||||
/// like `ctx.db.log_events().id().find(...)`.
|
||||
pub struct LogEventsIdUnique<'ctx> {
|
||||
imp: __sdk::UniqueConstraintHandle<LogEvent, u64>,
|
||||
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
|
||||
}
|
||||
|
||||
impl<'ctx> LogEventsTableHandle<'ctx> {
|
||||
/// Get a handle on the `id` unique index on the table `log_events`.
|
||||
pub fn id(&self) -> LogEventsIdUnique<'ctx> {
|
||||
LogEventsIdUnique {
|
||||
imp: self.imp.get_unique_constraint::<u64>("id"),
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> LogEventsIdUnique<'ctx> {
|
||||
/// Find the subscribed row whose `id` column value is equal to `col_val`,
|
||||
/// if such a row is present in the client cache.
|
||||
pub fn find(&self, col_val: &u64) -> Option<LogEvent> {
|
||||
self.imp.find(col_val)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
|
||||
let _table = client_cache.get_or_make_table::<LogEvent>("log_events");
|
||||
_table.add_unique_constraint::<u64>("id", |row| &row.id);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) fn parse_table_update(
|
||||
raw_updates: __ws::v2::TableUpdate,
|
||||
) -> __sdk::Result<__sdk::TableUpdate<LogEvent>> {
|
||||
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
|
||||
__sdk::InternalError::failed_parse("TableUpdate<LogEvent>", "TableUpdate")
|
||||
.with_cause(e)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for query builder access to the table `LogEvent`.
|
||||
///
|
||||
/// Implemented for [`__sdk::QueryTableAccessor`].
|
||||
pub trait log_eventsQueryTableAccess {
|
||||
#[allow(non_snake_case)]
|
||||
/// Get a query builder for the table `LogEvent`.
|
||||
fn log_events(&self) -> __sdk::__query_builder::Table<LogEvent>;
|
||||
}
|
||||
|
||||
impl log_eventsQueryTableAccess for __sdk::QueryTableAccessor {
|
||||
fn log_events(&self) -> __sdk::__query_builder::Table<LogEvent> {
|
||||
__sdk::__query_builder::Table::new("log_events")
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,13 @@
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
pub mod action_type;
|
||||
pub mod activities_table;
|
||||
pub mod activity_type;
|
||||
pub mod add_activity_reducer;
|
||||
pub mod event_type;
|
||||
pub mod events_table;
|
||||
pub mod log_event_type;
|
||||
pub mod log_events_table;
|
||||
pub mod next_action_reducer;
|
||||
pub mod profile_type;
|
||||
pub mod profiles_table;
|
||||
pub mod remove_activity_reducer;
|
||||
@@ -20,12 +22,15 @@ pub mod task_part_type;
|
||||
pub mod task_type;
|
||||
pub mod tasks_table;
|
||||
pub mod update_activity_reducer;
|
||||
pub mod update_upcoming_reducer;
|
||||
|
||||
pub use action_type::Action;
|
||||
pub use activities_table::*;
|
||||
pub use activity_type::Activity;
|
||||
pub use add_activity_reducer::add_activity;
|
||||
pub use event_type::Event;
|
||||
pub use events_table::*;
|
||||
pub use log_event_type::LogEvent;
|
||||
pub use log_events_table::*;
|
||||
pub use next_action_reducer::next_action;
|
||||
pub use profile_type::Profile;
|
||||
pub use profiles_table::*;
|
||||
pub use remove_activity_reducer::remove_activity;
|
||||
@@ -35,6 +40,7 @@ pub use task_part_type::TaskPart;
|
||||
pub use task_type::Task;
|
||||
pub use tasks_table::*;
|
||||
pub use update_activity_reducer::update_activity;
|
||||
pub use update_upcoming_reducer::update_upcoming;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
||||
@@ -45,9 +51,11 @@ pub use update_activity_reducer::update_activity;
|
||||
|
||||
pub enum Reducer {
|
||||
AddActivity { name: String },
|
||||
NextAction,
|
||||
RemoveActivity { activity: Activity },
|
||||
SetActivityName { id: u64, name: String },
|
||||
UpdateActivity { activity: Activity },
|
||||
UpdateUpcoming { upcoming: Vec<Action> },
|
||||
}
|
||||
|
||||
impl __sdk::InModule for Reducer {
|
||||
@@ -58,9 +66,11 @@ impl __sdk::Reducer for Reducer {
|
||||
fn reducer_name(&self) -> &'static str {
|
||||
match self {
|
||||
Reducer::AddActivity { .. } => "add_activity",
|
||||
Reducer::NextAction => "next_action",
|
||||
Reducer::RemoveActivity { .. } => "remove_activity",
|
||||
Reducer::SetActivityName { .. } => "set_activity_name",
|
||||
Reducer::UpdateActivity { .. } => "update_activity",
|
||||
Reducer::UpdateUpcoming { .. } => "update_upcoming",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -70,6 +80,7 @@ impl __sdk::Reducer for Reducer {
|
||||
Reducer::AddActivity { name } => {
|
||||
__sats::bsatn::to_vec(&add_activity_reducer::AddActivityArgs { name: name.clone() })
|
||||
}
|
||||
Reducer::NextAction => __sats::bsatn::to_vec(&next_action_reducer::NextActionArgs {}),
|
||||
Reducer::RemoveActivity { activity } => {
|
||||
__sats::bsatn::to_vec(&remove_activity_reducer::RemoveActivityArgs {
|
||||
activity: activity.clone(),
|
||||
@@ -86,6 +97,11 @@ impl __sdk::Reducer for Reducer {
|
||||
activity: activity.clone(),
|
||||
})
|
||||
}
|
||||
Reducer::UpdateUpcoming { upcoming } => {
|
||||
__sats::bsatn::to_vec(&update_upcoming_reducer::UpdateUpcomingArgs {
|
||||
upcoming: upcoming.clone(),
|
||||
})
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -96,7 +112,7 @@ impl __sdk::Reducer for Reducer {
|
||||
#[doc(hidden)]
|
||||
pub struct DbUpdate {
|
||||
activities: __sdk::TableUpdate<Activity>,
|
||||
events: __sdk::TableUpdate<Event>,
|
||||
log_events: __sdk::TableUpdate<LogEvent>,
|
||||
profiles: __sdk::TableUpdate<Profile>,
|
||||
task_part: __sdk::TableUpdate<TaskPart>,
|
||||
tasks: __sdk::TableUpdate<Task>,
|
||||
@@ -111,9 +127,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate {
|
||||
"activities" => db_update
|
||||
.activities
|
||||
.append(activities_table::parse_table_update(table_update)?),
|
||||
"events" => db_update
|
||||
.events
|
||||
.append(events_table::parse_table_update(table_update)?),
|
||||
"log_events" => db_update
|
||||
.log_events
|
||||
.append(log_events_table::parse_table_update(table_update)?),
|
||||
"profiles" => db_update
|
||||
.profiles
|
||||
.append(profiles_table::parse_table_update(table_update)?),
|
||||
@@ -152,7 +168,9 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
diff.activities = cache
|
||||
.apply_diff_to_table::<Activity>("activities", &self.activities)
|
||||
.with_updates_by_pk(|row| &row.id);
|
||||
diff.events = cache.apply_diff_to_table::<Event>("events", &self.events);
|
||||
diff.log_events = cache
|
||||
.apply_diff_to_table::<LogEvent>("log_events", &self.log_events)
|
||||
.with_updates_by_pk(|row| &row.id);
|
||||
diff.profiles = cache
|
||||
.apply_diff_to_table::<Profile>("profiles", &self.profiles)
|
||||
.with_updates_by_pk(|row| &row.identity);
|
||||
@@ -172,8 +190,8 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
"activities" => db_update
|
||||
.activities
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
"events" => db_update
|
||||
.events
|
||||
"log_events" => db_update
|
||||
.log_events
|
||||
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
|
||||
"profiles" => db_update
|
||||
.profiles
|
||||
@@ -200,8 +218,8 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
"activities" => db_update
|
||||
.activities
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
"events" => db_update
|
||||
.events
|
||||
"log_events" => db_update
|
||||
.log_events
|
||||
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
|
||||
"profiles" => db_update
|
||||
.profiles
|
||||
@@ -228,7 +246,7 @@ impl __sdk::DbUpdate for DbUpdate {
|
||||
#[doc(hidden)]
|
||||
pub struct AppliedDiff<'r> {
|
||||
activities: __sdk::TableAppliedDiff<'r, Activity>,
|
||||
events: __sdk::TableAppliedDiff<'r, Event>,
|
||||
log_events: __sdk::TableAppliedDiff<'r, LogEvent>,
|
||||
profiles: __sdk::TableAppliedDiff<'r, Profile>,
|
||||
task_part: __sdk::TableAppliedDiff<'r, TaskPart>,
|
||||
tasks: __sdk::TableAppliedDiff<'r, Task>,
|
||||
@@ -246,7 +264,7 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
|
||||
callbacks: &mut __sdk::DbCallbacks<RemoteModule>,
|
||||
) {
|
||||
callbacks.invoke_table_row_callbacks::<Activity>("activities", &self.activities, event);
|
||||
callbacks.invoke_table_row_callbacks::<Event>("events", &self.events, event);
|
||||
callbacks.invoke_table_row_callbacks::<LogEvent>("log_events", &self.log_events, event);
|
||||
callbacks.invoke_table_row_callbacks::<Profile>("profiles", &self.profiles, event);
|
||||
callbacks.invoke_table_row_callbacks::<TaskPart>("task_part", &self.task_part, event);
|
||||
callbacks.invoke_table_row_callbacks::<Task>("tasks", &self.tasks, event);
|
||||
@@ -911,11 +929,11 @@ impl __sdk::SpacetimeModule for RemoteModule {
|
||||
|
||||
fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {
|
||||
activities_table::register_table(client_cache);
|
||||
events_table::register_table(client_cache);
|
||||
log_events_table::register_table(client_cache);
|
||||
profiles_table::register_table(client_cache);
|
||||
task_part_table::register_table(client_cache);
|
||||
tasks_table::register_table(client_cache);
|
||||
}
|
||||
const ALL_TABLE_NAMES: &'static [&'static str] =
|
||||
&["activities", "events", "profiles", "task_part", "tasks"];
|
||||
&["activities", "log_events", "profiles", "task_part", "tasks"];
|
||||
}
|
||||
|
||||
62
packages/ppc/generated/next_action_reducer.rs
Normal file
62
packages/ppc/generated/next_action_reducer.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub(super) struct NextActionArgs {}
|
||||
|
||||
impl From<NextActionArgs> for super::Reducer {
|
||||
fn from(args: NextActionArgs) -> Self {
|
||||
Self::NextAction
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::InModule for NextActionArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the reducer `next_action`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteReducers`].
|
||||
pub trait next_action {
|
||||
/// Request that the remote module invoke the reducer `next_action` to run as soon as possible.
|
||||
///
|
||||
/// This method returns immediately, and errors only if we are unable to send the request.
|
||||
/// The reducer will run asynchronously in the future,
|
||||
/// and this method provides no way to listen for its completion status.
|
||||
/// /// Use [`next_action:next_action_then`] to run a callback after the reducer completes.
|
||||
fn next_action(&self) -> __sdk::Result<()> {
|
||||
self.next_action_then(|_, _| {})
|
||||
}
|
||||
|
||||
/// Request that the remote module invoke the reducer `next_action` to run as soon as possible,
|
||||
/// registering `callback` to run when we are notified that the reducer completed.
|
||||
///
|
||||
/// This method returns immediately, and errors only if we are unable to send the request.
|
||||
/// The reducer will run asynchronously in the future,
|
||||
/// and its status can be observed with the `callback`.
|
||||
fn next_action_then(
|
||||
&self,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
impl next_action for super::RemoteReducers {
|
||||
fn next_action_then(
|
||||
&self,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(NextActionArgs {}, callback)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use super::activity_type::Activity;
|
||||
use super::action_type::Action;
|
||||
use super::task_part_type::TaskPart;
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::activity_type::Activity;
|
||||
use super::action_type::Action;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub struct TaskPart {
|
||||
pub identity: __sdk::Identity,
|
||||
pub current_activity: Activity,
|
||||
pub start_of_current: __sdk::Timestamp,
|
||||
pub current: Action,
|
||||
pub upcoming: Vec<Action>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for TaskPart {
|
||||
@@ -22,7 +24,9 @@ impl __sdk::InModule for TaskPart {
|
||||
/// Provides typed access to columns for query building.
|
||||
pub struct TaskPartCols {
|
||||
pub identity: __sdk::__query_builder::Col<TaskPart, __sdk::Identity>,
|
||||
pub current_activity: __sdk::__query_builder::Col<TaskPart, Activity>,
|
||||
pub start_of_current: __sdk::__query_builder::Col<TaskPart, __sdk::Timestamp>,
|
||||
pub current: __sdk::__query_builder::Col<TaskPart, Action>,
|
||||
pub upcoming: __sdk::__query_builder::Col<TaskPart, Vec<Action>>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for TaskPart {
|
||||
@@ -30,7 +34,9 @@ impl __sdk::__query_builder::HasCols for TaskPart {
|
||||
fn cols(table_name: &'static str) -> Self::Cols {
|
||||
TaskPartCols {
|
||||
identity: __sdk::__query_builder::Col::new(table_name, "identity"),
|
||||
current_activity: __sdk::__query_builder::Col::new(table_name, "current_activity"),
|
||||
start_of_current: __sdk::__query_builder::Col::new(table_name, "start_of_current"),
|
||||
current: __sdk::__query_builder::Col::new(table_name, "current"),
|
||||
upcoming: __sdk::__query_builder::Col::new(table_name, "upcoming"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
70
packages/ppc/generated/update_upcoming_reducer.rs
Normal file
70
packages/ppc/generated/update_upcoming_reducer.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::action_type::Action;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub(super) struct UpdateUpcomingArgs {
|
||||
pub upcoming: Vec<Action>,
|
||||
}
|
||||
|
||||
impl From<UpdateUpcomingArgs> for super::Reducer {
|
||||
fn from(args: UpdateUpcomingArgs) -> Self {
|
||||
Self::UpdateUpcoming {
|
||||
upcoming: args.upcoming,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl __sdk::InModule for UpdateUpcomingArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the reducer `update_upcoming`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteReducers`].
|
||||
pub trait update_upcoming {
|
||||
/// Request that the remote module invoke the reducer `update_upcoming` to run as soon as possible.
|
||||
///
|
||||
/// This method returns immediately, and errors only if we are unable to send the request.
|
||||
/// The reducer will run asynchronously in the future,
|
||||
/// and this method provides no way to listen for its completion status.
|
||||
/// /// Use [`update_upcoming:update_upcoming_then`] to run a callback after the reducer completes.
|
||||
fn update_upcoming(&self, upcoming: Vec<Action>) -> __sdk::Result<()> {
|
||||
self.update_upcoming_then(upcoming, |_, _| {})
|
||||
}
|
||||
|
||||
/// Request that the remote module invoke the reducer `update_upcoming` to run as soon as possible,
|
||||
/// registering `callback` to run when we are notified that the reducer completed.
|
||||
///
|
||||
/// This method returns immediately, and errors only if we are unable to send the request.
|
||||
/// The reducer will run asynchronously in the future,
|
||||
/// and its status can be observed with the `callback`.
|
||||
fn update_upcoming_then(
|
||||
&self,
|
||||
upcoming: Vec<Action>,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
impl update_upcoming for super::RemoteReducers {
|
||||
fn update_upcoming_then(
|
||||
&self,
|
||||
upcoming: Vec<Action>,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(UpdateUpcomingArgs { upcoming }, callback)
|
||||
}
|
||||
}
|
||||
@@ -39,14 +39,28 @@ fn os_main(mize: &mut Mize) -> MizeResult<()> {
|
||||
#[cfg(feature = "server")]
|
||||
ppc::server(mize)?;
|
||||
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
#[cfg(feature = "desktop")]
|
||||
cli.subcommand(Command::new("gui"), |_, _| {
|
||||
ppc::ui::launch_desktop_app();
|
||||
Ok(())
|
||||
});
|
||||
{
|
||||
cli.subcommand(Command::new("gui"), |_, _| {
|
||||
ppc::ui::launch_desktop_app();
|
||||
Ok(())
|
||||
});
|
||||
cli.subcommand(Command::new("c2vi-dash"), |_, mut mize| {
|
||||
// refresh the credentials every 23h
|
||||
// as this is basically running as a daemon
|
||||
use ppc::auth::client::ClientAuth;
|
||||
let mut auth = mize.get_part_native::<ClientAuth>("auth")?;
|
||||
auth.refresh()?;
|
||||
auth.start_refresh_thread()?;
|
||||
drop(auth);
|
||||
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
ppc::ui::launch_c2vi_dashboard(&mut mize);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
cli.with_cmd(|_, cmd| {
|
||||
Ok(cmd
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
// Minimal cross-platform UI component
|
||||
use dioxus::prelude::*;
|
||||
use mize::Mize;
|
||||
|
||||
use crate::{
|
||||
generated::{
|
||||
Action, ActivitiesTableAccess, Activity, DbConnection, TaskPart, TaskPartTableAccess,
|
||||
activitiesQueryTableAccess, next_action, remove_activity, task_partQueryTableAccess,
|
||||
update_activity, update_upcoming,
|
||||
},
|
||||
spacetime::SpacetimePart,
|
||||
};
|
||||
use spacetimedb_sdk::{
|
||||
DbContext, Error, Event, Identity, Status, SubscriptionHandle, Table, TableWithPrimaryKey,
|
||||
credentials,
|
||||
};
|
||||
|
||||
pub fn hello_world() -> Element {
|
||||
rsx! {
|
||||
@@ -12,6 +25,126 @@ pub fn hello_world() -> Element {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn c2vi_dash_main() -> Element {
|
||||
let mut current = use_signal_sync(|| "".to_string());
|
||||
use_effect(move || {
|
||||
let mut mize = use_context::<Mize>();
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime").unwrap();
|
||||
let con = spacetime.con();
|
||||
con.subscription_builder()
|
||||
.on_applied(move |ctx| {
|
||||
let data = ctx.db.task_part().identity().find(&ctx.identity()).unwrap();
|
||||
current.set(data.current.name.clone());
|
||||
})
|
||||
.add_query(|q| q.from.task_part())
|
||||
.subscribe();
|
||||
con.db
|
||||
.task_part()
|
||||
.on_update(move |_, old: &TaskPart, new: &TaskPart| {
|
||||
current.set(new.current.name.clone());
|
||||
});
|
||||
});
|
||||
rsx! {
|
||||
div {
|
||||
style: "text-align: center; padding: 2rem; font-size: 50px;",
|
||||
p {
|
||||
"{current}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn launch_desktop_app() {
|
||||
dioxus::launch(hello_world);
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn launch_c2vi_dashboard(mize: &mut Mize) {
|
||||
use dioxus::desktop::{Config, WindowBuilder, muda::Menu};
|
||||
let mize_clone = mize.clone();
|
||||
LaunchBuilder::new()
|
||||
.with_context_provider(move || Box::new(mize_clone.clone()))
|
||||
.with_cfg(desktop! {
|
||||
Config::new().with_window(WindowBuilder::new().with_decorations(false).with_title("PPC"))
|
||||
})
|
||||
.launch(c2vi_dash_main);
|
||||
}
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
/*
|
||||
pub fn use_spacetime_row<T>() -> {
|
||||
let mut mize = use_context::<Mize>();
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime").unwrap();
|
||||
let con = spacetime.con();
|
||||
|
||||
let data = use_signal(|| None:: <T>);
|
||||
|
||||
let a = con.db.task_part();
|
||||
let table = con.db.
|
||||
|
||||
use_effect(cx, (), {});
|
||||
|
||||
}
|
||||
|
||||
pub fn use_spacetime_users() -> Signal<Vec<User>> {
|
||||
let mut mize = use_context::<Mize>();
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime").unwrap();
|
||||
let con = spacetime.con();
|
||||
|
||||
let users = use_signal(|| Vec::<User>::new());
|
||||
|
||||
use_effect(cx, (), {
|
||||
let users = users.clone();
|
||||
let conn = ctx.conn.clone();
|
||||
|
||||
move |_| {
|
||||
conn.on_connect(move |db_ctx| {
|
||||
// initial subscription
|
||||
db_ctx.subscription_builder()
|
||||
.on_applied({
|
||||
let users = users.clone();
|
||||
move |ctx| {
|
||||
let all: Vec<_> =
|
||||
ctx.db.user().iter().cloned().collect();
|
||||
users.set(all);
|
||||
}
|
||||
})
|
||||
.subscribe(["SELECT * FROM user"]);
|
||||
|
||||
// incremental updates
|
||||
db_ctx.db.user().on_insert({
|
||||
let users = users.clone();
|
||||
move |_, row| {
|
||||
users.with_mut(|v| v.push(row.clone()));
|
||||
}
|
||||
});
|
||||
|
||||
db_ctx.db.user().on_delete({
|
||||
let users = users.clone();
|
||||
move |_, row| {
|
||||
users.with_mut(|v| {
|
||||
v.retain(|u| u.id != row.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
db_ctx.db.user().on_update({
|
||||
let users = users.clone();
|
||||
move |_, old, new| {
|
||||
users.with_mut(|v| {
|
||||
if let Some(u) = v.iter_mut().find(|u| u.id == old.id) {
|
||||
*u = new.clone();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async move {}
|
||||
}
|
||||
});
|
||||
|
||||
users
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use std::task;
|
||||
|
||||
use log::*;
|
||||
use spacetimedb::{reducer, table, Identity, ReducerContext, Table, Timestamp};
|
||||
use spacetimedb::{
|
||||
reducer, table, view, Deserialize, Identity, ReducerContext, Serialize, SpacetimeType, Table,
|
||||
Timestamp, ViewContext,
|
||||
};
|
||||
|
||||
#[table(accessor = profiles, public)]
|
||||
pub struct Profile {
|
||||
@@ -13,7 +18,9 @@ pub struct Profile {
|
||||
pub struct TaskPart {
|
||||
#[primary_key]
|
||||
identity: Identity,
|
||||
current_activity: Activity,
|
||||
start_of_current: Timestamp,
|
||||
current: Action,
|
||||
upcoming: Vec<Action>,
|
||||
}
|
||||
|
||||
#[table(accessor = activities, public)]
|
||||
@@ -36,14 +43,26 @@ pub struct Task {
|
||||
parent: Option<u64>,
|
||||
}
|
||||
|
||||
#[table(accessor = events, public)]
|
||||
pub struct Event {
|
||||
start: Timestamp,
|
||||
end: Timestamp,
|
||||
activity: Activity,
|
||||
#[table(accessor = action)]
|
||||
#[derive(Clone)]
|
||||
pub struct Action {
|
||||
name: String,
|
||||
activity: Option<u64>,
|
||||
task: Option<u64>,
|
||||
start: Option<Timestamp>,
|
||||
end: Option<Timestamp>,
|
||||
duration: Option<u64>,
|
||||
}
|
||||
|
||||
// TODO....
|
||||
#[table(accessor = log_events, public)]
|
||||
pub struct LogEvent {
|
||||
#[primary_key]
|
||||
#[auto_inc]
|
||||
id: u64,
|
||||
start: Timestamp,
|
||||
end: Timestamp,
|
||||
action: Action,
|
||||
}
|
||||
|
||||
#[reducer(init)]
|
||||
pub fn init(_ctx: &ReducerContext) {
|
||||
@@ -106,6 +125,57 @@ pub fn set_activity_name(ctx: &ReducerContext, id: u64, name: String) {
|
||||
}
|
||||
}
|
||||
|
||||
#[reducer]
|
||||
pub fn update_upcoming(ctx: &ReducerContext, upcoming: Vec<Action>) {
|
||||
if ctx.db.task_part().identity().find(ctx.sender()).is_none() {
|
||||
ctx.db.task_part().insert(TaskPart {
|
||||
upcoming,
|
||||
identity: ctx.sender(),
|
||||
current: Action {
|
||||
name: "filler".to_string(),
|
||||
activity: None,
|
||||
task: None,
|
||||
start: None,
|
||||
end: None,
|
||||
duration: None,
|
||||
},
|
||||
start_of_current: ctx.timestamp,
|
||||
});
|
||||
} else {
|
||||
ctx.db.task_part().identity().update(TaskPart {
|
||||
upcoming,
|
||||
..ctx.db.task_part().identity().find(&ctx.sender()).unwrap()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[reducer]
|
||||
pub fn next_action(ctx: &ReducerContext) -> Result<(), String> {
|
||||
if let Some(mut task_part) = ctx.db.task_part().identity().find(&ctx.sender()) {
|
||||
if task_part.upcoming.is_empty() {
|
||||
return Err("No upcoming actions".to_string());
|
||||
}
|
||||
let action = task_part.upcoming.remove(0);
|
||||
let start_of_old_action = task_part.start_of_current;
|
||||
ctx.db.task_part().identity().update(TaskPart {
|
||||
upcoming: task_part.upcoming,
|
||||
identity: task_part.identity,
|
||||
current: action.clone(),
|
||||
start_of_current: ctx.timestamp,
|
||||
});
|
||||
// create log event
|
||||
ctx.db.log_events().insert(LogEvent {
|
||||
start: start_of_old_action,
|
||||
end: ctx.timestamp,
|
||||
action: task_part.current,
|
||||
id: 0,
|
||||
});
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Task part data not found for this user".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[reducer]
|
||||
pub fn update_activity(ctx: &ReducerContext, activity: Activity) {
|
||||
if activity.id == 0 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{io::Read, sync::oneshot, thread, time::Duration};
|
||||
|
||||
use clap::{ArgMatches, Command};
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use mize::{Mize, MizeError, MizePart, MizePartGuard, MizeResult, mize_err, mize_part};
|
||||
use spacetimedb_sdk::{
|
||||
DbContext, Error, Event, Identity, Status, SubscriptionHandle, Table, TableWithPrimaryKey,
|
||||
@@ -9,8 +9,9 @@ use spacetimedb_sdk::{
|
||||
|
||||
use crate::{
|
||||
generated::{
|
||||
ActivitiesTableAccess, Activity, DbConnection, activitiesQueryTableAccess, remove_activity,
|
||||
update_activity,
|
||||
Action, ActivitiesTableAccess, Activity, DbConnection, TaskPartTableAccess,
|
||||
activitiesQueryTableAccess, next_action, remove_activity, task_partQueryTableAccess,
|
||||
update_activity, update_upcoming,
|
||||
},
|
||||
spacetime::SpacetimePart,
|
||||
};
|
||||
@@ -24,6 +25,23 @@ pub struct TimeTrack {
|
||||
pub fn timetrack(mize: &mut Mize) -> MizeResult<()> {
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
|
||||
cli.subcommand(
|
||||
Command::new("editActionList").alias("aal").arg(
|
||||
Arg::new("defaultTemplate")
|
||||
.short('d')
|
||||
.action(ArgAction::SetTrue),
|
||||
),
|
||||
command_edit_action_list,
|
||||
);
|
||||
cli.subcommand(Command::new("nextAction").alias("ne"), command_next_action);
|
||||
cli.subcommand(
|
||||
Command::new("printCurrentAction").alias("cu"),
|
||||
command_current_action,
|
||||
);
|
||||
cli.subcommand(
|
||||
Command::new("listActions").alias("la"),
|
||||
command_list_actions,
|
||||
);
|
||||
cli.subcommand(
|
||||
Command::new("listActivities").alias("lac"),
|
||||
command_list_activities,
|
||||
@@ -43,9 +61,58 @@ impl MizePart for TimeTrack {
|
||||
}
|
||||
}
|
||||
|
||||
fn command_next_action(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
let con = spacetime.con();
|
||||
let (wait_tx, waiter_rx) = std::sync::oneshot::channel::<()>();
|
||||
con.reducers.next_action_then(|_, _| {
|
||||
wait_tx.send(()).unwrap();
|
||||
})?;
|
||||
waiter_rx.recv()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn command_current_action(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
let action = get_current_action(&mut mize, spacetime.con())?;
|
||||
println!("{}", action.name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_current_action(mize: &mut Mize, con: &DbConnection) -> MizeResult<Action> {
|
||||
let (wait_tx, wait_rx) = std::sync::oneshot::channel::<Action>();
|
||||
con.subscription_builder()
|
||||
.on_applied(|ctx| {
|
||||
let task_part_data = ctx.db.task_part().identity().find(&ctx.identity());
|
||||
if task_part_data.is_none() {
|
||||
wait_tx
|
||||
.send(Action {
|
||||
name: "fillier".to_string(),
|
||||
activity: None,
|
||||
task: None,
|
||||
start: None,
|
||||
end: None,
|
||||
duration: None,
|
||||
})
|
||||
.unwrap();
|
||||
} else {
|
||||
wait_tx.send(task_part_data.unwrap().current).unwrap();
|
||||
}
|
||||
})
|
||||
.add_query(|q| {
|
||||
q.from.task_part()
|
||||
//.r#where(|row| row.identity.eq(con.identity()))
|
||||
})
|
||||
.subscribe();
|
||||
let action = wait_rx.recv().unwrap();
|
||||
Ok(action)
|
||||
}
|
||||
|
||||
fn command_list_activities(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
let activities = get_activities(&mut mize, spacetime.con())?;
|
||||
|
||||
for ac in activities.clone() {
|
||||
print!("ac {}: {}", ac.id, ac.name);
|
||||
if !ac.parents_ids.is_empty() {
|
||||
@@ -60,6 +127,121 @@ fn command_list_activities(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn command_list_actions(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
|
||||
let actions = get_actions(spacetime.con())?;
|
||||
|
||||
for action in actions {
|
||||
println!("{}", action.name)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn command_edit_action_list(matches: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
|
||||
// maybe append a template to the action list
|
||||
if matches.get_flag("defaultTemplate") {
|
||||
println!("Appending template...");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// get list of actions
|
||||
let mut actions = get_actions(spacetime.con())?;
|
||||
|
||||
// write to tmp file
|
||||
let mut tmp_file_content = actions_to_string(&actions)?;
|
||||
let tmp_file = std::env::temp_dir().join(format!(
|
||||
"ppc-edit-actions-{}.txt",
|
||||
chrono::Utc::now().timestamp()
|
||||
));
|
||||
std::fs::write(&tmp_file, tmp_file_content)
|
||||
.map_err(|e| mize_err!("Failed to write temp file: {}", e))?;
|
||||
|
||||
// open $EDITOR blocking
|
||||
std::process::Command::new("nvim")
|
||||
.arg(&tmp_file)
|
||||
.status()
|
||||
.map_err(|e| mize_err!("Failed to run nvim: {}", e))?;
|
||||
|
||||
// read file and update db
|
||||
let new_file_content = std::fs::read_to_string(&tmp_file)
|
||||
.map_err(|e| mize_err!("Failed to read temp file: {}", e))?;
|
||||
|
||||
actions = actions_from_string(actions, new_file_content)?;
|
||||
set_actions(actions, spacetime.con())?;
|
||||
|
||||
// delete tmpfile
|
||||
let _ = std::fs::remove_file(&tmp_file);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_actions(con: &DbConnection) -> MizeResult<Vec<Action>> {
|
||||
let (exit_tx, exit_rx) = std::sync::oneshot::channel::<Vec<Action>>();
|
||||
con.subscription_builder()
|
||||
.on_applied(|ctx| {
|
||||
let task_part_data = ctx.db.task_part().identity().find(&ctx.identity());
|
||||
if task_part_data.is_none() {
|
||||
exit_tx.send(Vec::new()).unwrap();
|
||||
} else {
|
||||
exit_tx.send(task_part_data.unwrap().upcoming).unwrap();
|
||||
}
|
||||
})
|
||||
.add_query(|q| {
|
||||
q.from.task_part()
|
||||
//.r#where(|row| row.identity.eq(con.identity()))
|
||||
})
|
||||
.subscribe();
|
||||
let activities = exit_rx.recv().unwrap();
|
||||
Ok(activities)
|
||||
}
|
||||
|
||||
fn set_actions(actions: Vec<Action>, con: &DbConnection) -> MizeResult<()> {
|
||||
let (wait_tx, waiter_rx) = std::sync::oneshot::channel::<()>();
|
||||
con.reducers
|
||||
.update_upcoming_then(actions, |_, _| wait_tx.send(()).unwrap())?;
|
||||
waiter_rx.recv().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn actions_to_string(actions: &Vec<Action>) -> MizeResult<String> {
|
||||
let mut string = String::new();
|
||||
|
||||
for action in actions.iter() {
|
||||
string.push_str(format!("{}\n", action.name).as_str());
|
||||
}
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
fn actions_from_string(mut old_actions: Vec<Action>, string: String) -> MizeResult<Vec<Action>> {
|
||||
let mut new_actions = Vec::new();
|
||||
for line in string.lines() {
|
||||
if line.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut action = Action {
|
||||
name: line.to_owned(),
|
||||
activity: None,
|
||||
task: None,
|
||||
start: None,
|
||||
end: None,
|
||||
duration: None,
|
||||
};
|
||||
parse_action(&mut action);
|
||||
new_actions.push(action);
|
||||
}
|
||||
Ok(new_actions)
|
||||
}
|
||||
|
||||
fn parse_action(action: &mut Action) {
|
||||
let parts: Vec<&str> = action.name.split_whitespace().collect();
|
||||
}
|
||||
|
||||
fn command_edit_activities(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> {
|
||||
let mut spacetime = mize.get_part_native::<SpacetimePart>("spacetime")?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user