Skip to content

Commit

Permalink
feat: add more resume related functionality (#44)
Browse files Browse the repository at this point in the history
* feat: add miette for better error reporting

Signed-off-by: simonsan <[email protected]>

* feat: pretty print toml

Signed-off-by: simonsan <[email protected]>

* fix: remove 'autogenerate_ids' from config

Signed-off-by: simonsan <[email protected]>

* refactor: factor out 'hold_activity' in ActivityStateManagement

Signed-off-by: simonsan <[email protected]>

* refactor: cleanup Activity traits API from chrono types

Signed-off-by: simonsan <[email protected]>

* test: fix tests again after big refactoring to ActivityStatus enum

Signed-off-by: simonsan <[email protected]>

* test: fix a few more tests and implement pace flow test for resume

Signed-off-by: simonsan <[email protected]>

* feat(resume): implement resume procedure

Signed-off-by: simonsan <[email protected]>

* feat: create backups of activity log and config file in craft setup

Signed-off-by: simonsan <[email protected]>

* feat(resume): implement resume command

Signed-off-by: simonsan <[email protected]>

* docs: update status for commands

Signed-off-by: simonsan <[email protected]>

---------

Signed-off-by: simonsan <[email protected]>
  • Loading branch information
simonsan authored Feb 26, 2024
1 parent 7cde40e commit e5d9585
Show file tree
Hide file tree
Showing 24 changed files with 1,000 additions and 362 deletions.
98 changes: 97 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,19 @@ implemented yet (e.g. using activities instead of tasks).
what you're currently tracking.
- **Usage:** `pace now`

🪧 **`pace hold`**
🔍 **`pace hold`**

- **Description:** Pauses the time tracking for the specified task. This is
useful for taking breaks without ending the task.
- **Usage:** `pace hold` or `pace hold "Design Work"`

⏲️ **`pace resume`**
🔍 **`pace resume`**

- **Description:** Resumes time tracking for a previously paused task, allowing
you to continue where you left off.
- **Usage:** `pace resume "Design Work"`

📜 **`pace review`**
⏲️ **`pace review`**

- **Description:** Gain insight in your activities and tasks. You can specify
the time frame for daily, weekly, or monthly insights.
Expand Down
2 changes: 0 additions & 2 deletions config/pace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ activity_log_storage = "file"
activity_log_path = "C:\\Users\\dailyuse\\backup\\PARA\\Personal\\2 Areas\\Developer\\Maintenance\\pace\\pace-rs\\pace\\data\\activity_2024-02.toml"
# Specify the default format for new activity logs: "toml" or "yaml"
activity_log_format = "toml"
# Autogenerate identifiers for tasks, projects and activities that have been manually created
autogenerate_ids = true
# Category separator used in the cli
category_separator = "::"
# Default priority for new tasks
Expand Down
28 changes: 22 additions & 6 deletions crates/cli/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use dialoguer::{
};
use eyre::Result;
use getset::{Getters, MutGetters};
use tracing::debug;
use tracing::{debug, info};
use typed_builder::TypedBuilder;

use pace_core::{get_activity_log_paths, get_config_paths, toml, ActivityLog, PaceConfig};
Expand Down Expand Up @@ -118,7 +118,7 @@ pub(crate) fn env_knowledge_loop(term: &Term, config_root: &Path) -> Result<()>
.default(false)
.interact()?;

if ready_to_continue {
if !ready_to_continue {
break 'env;
}
}
Expand Down Expand Up @@ -151,6 +151,14 @@ pub(crate) fn write_config(
create_dir_all(config_root)?;

if config_root.exists() {
// Create a backup before writing the new configuration
if config_path.exists() {
info!("A configuration already exists, creating a backup next to the existing one.");
let backup_path = config_path.with_extension("toml.bak");

_ = std::fs::copy(config_path, backup_path)?;
}

// Write the pace.toml file
std::fs::write(config_path, config_content.as_bytes())?;

Expand Down Expand Up @@ -181,6 +189,14 @@ pub(crate) fn write_activity_log(final_paths: &FinalSetupPaths) -> Result<()> {
create_dir_all(&final_paths.activity_log_root)?;

if final_paths.activity_log_root.exists() {
// Create a backup before writing the new activity log
if final_paths.activity_log_path.exists() {
info!("An activity log already exists, creating a backup next to the existing one.");
let backup_path = &final_paths.activity_log_path.with_extension("toml.bak");

_ = std::fs::copy(&final_paths.activity_log_path, backup_path)?;
}

// Write the activity log file
std::fs::write(
&final_paths.activity_log_path,
Expand Down Expand Up @@ -259,7 +275,7 @@ to elevate your productivity with pace.";
.default(true)
.interact()?;

if confirmation {
if !confirmation {
eyre::bail!("Exiting setup assistant.");
}

Expand All @@ -286,11 +302,11 @@ pub(crate) fn confirmation_or_break(prompt: &str) -> Result<()> {
.default(true)
.interact()?;

if confirmation {
if !confirmation {
eyre::bail!("Exiting setup assistant. No changes were made.");
} else {
Ok(())
}

Ok(())
}

/// The `craft setup` commands interior for the pace application
Expand Down
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ getset = "0.1.2"
itertools = "0.12.1"
log = "0.4.20"
merge = "0.1.0"
miette = { version = "7.1.0", features = ["fancy"] }
rayon = "1.8.1"
rusqlite = { version = "0.31.0", features = ["bundled", "chrono", "uuid"], optional = true }
serde = "1.0.197"
Expand Down
23 changes: 22 additions & 1 deletion crates/core/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ pub mod resume;
use getset::Getters;
use typed_builder::TypedBuilder;

use crate::{HoldOptions, PaceDateTime};
use crate::{commands::resume::ResumeOptions, HoldOptions, PaceDateTime};

/// Options for ending an activity
#[derive(Debug, Clone, PartialEq, TypedBuilder, Eq, Hash, Default, Getters)]
#[getset(get = "pub")]
#[non_exhaustive]
pub struct EndOptions {
/// The end time
#[builder(default, setter(into))]
Expand All @@ -22,3 +23,23 @@ impl From<HoldOptions> for EndOptions {
}
}
}

impl From<ResumeOptions> for EndOptions {
fn from(resume_opts: ResumeOptions) -> Self {
Self {
end_time: resume_opts.resume_time().unwrap_or_else(PaceDateTime::now),
}
}
}

/// Options for updating an activity
#[derive(Debug, Clone, PartialEq, TypedBuilder, Eq, Hash, Default, Getters)]
#[getset(get = "pub")]
#[non_exhaustive]
pub struct UpdateOptions {}

/// Options for deleting an activity
#[derive(Debug, Clone, PartialEq, TypedBuilder, Eq, Hash, Default, Getters)]
#[getset(get = "pub")]
#[non_exhaustive]
pub struct DeleteOptions {}
1 change: 1 addition & 0 deletions crates/core/src/commands/hold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{IntermissionAction, PaceDateTime};
/// Options for holding an activity
#[derive(Debug, Clone, PartialEq, TypedBuilder, Eq, Hash, Default, Getters)]
#[getset(get = "pub")]
#[non_exhaustive]
pub struct HoldOptions {
/// The action to take on the intermission
#[builder(default)]
Expand Down
13 changes: 13 additions & 0 deletions crates/core/src/commands/resume.rs
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
use getset::Getters;
use typed_builder::TypedBuilder;

use crate::PaceDateTime;

/// Options for resuming an activity
#[derive(Debug, Clone, PartialEq, TypedBuilder, Eq, Hash, Default, Getters)]
#[getset(get = "pub")]
#[non_exhaustive]
pub struct ResumeOptions {
/// The resume time of the intermission
#[builder(default, setter(into))]
resume_time: Option<PaceDateTime>,
}
6 changes: 0 additions & 6 deletions crates/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,6 @@ pub struct GeneralConfig {
#[getset(get = "pub", get_mut = "pub")]
activity_log_options: ActivityLogOptions,

/// If IDs should be autogenerated for activities, otherwise it's a hard error
/// Default: `true`
#[serde(default, skip_serializing_if = "Option::is_none")]
autogenerate_ids: Option<bool>,

/// The default category separator
/// Default: `::`
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -147,7 +142,6 @@ impl Default for GeneralConfig {
fn default() -> Self {
Self {
activity_log_options: ActivityLogOptions::default(),
autogenerate_ids: Some(true),
category_separator: Some("::".to_string()),
default_priority: Some(ItemPriorityKind::default()),
most_recent_count: Some(9),
Expand Down
Loading

0 comments on commit e5d9585

Please sign in to comment.