forked from janek/mostr
1
0
Fork 0

docs: expand Readme and adjust code comments

This commit is contained in:
xeruf 2024-08-14 15:59:43 +03:00
parent 8588fb9a04
commit 1e0cc319b8
4 changed files with 80 additions and 22 deletions

View File

@ -99,7 +99,7 @@ To stop time-tracking completely, simply move to the root of all tasks.
+ match by task name prefix: if one or more tasks match, filter / activate (tries case-sensitive then case-insensitive) + match by task name prefix: if one or more tasks match, filter / activate (tries case-sensitive then case-insensitive)
+ no match: create & activate task + no match: create & activate task
- `.2` - set view depth to `2`, which can be substituted for any number (how many subtask levels to show, default 1) - `.2` - set view depth to `2`, which can be substituted for any number (how many subtask levels to show, default 1)
- `/[TEXT]` - like `.`, but never creates a task - `/[TEXT]` - like `.`, but never creates a task and filters beyond currently visible tasks
- `||TASK` - create and activate a new task procedure (where subtasks automatically depend on the previously created task) - `||TASK` - create and activate a new task procedure (where subtasks automatically depend on the previously created task)
- `|[TASK]` - (un)mark current task as procedure or create a sibling task depending on the current one and move up - `|[TASK]` - (un)mark current task as procedure or create a sibling task depending on the current one and move up
@ -109,12 +109,13 @@ Dots and slashes can be repeated to move to parent tasks.
- `::[PROP]` - Sort by property PROP (multiple space-separated values allowed) - `::[PROP]` - Sort by property PROP (multiple space-separated values allowed)
- `([TIME]` - insert timetracking with the specified offset in minutes (empty: list tracked times) - `([TIME]` - insert timetracking with the specified offset in minutes (empty: list tracked times)
- `)[TIME]` - stop timetracking with the specified offset in minutes - convenience helper to move to root (empty: stop now) - `)[TIME]` - stop timetracking with the specified offset in minutes - convenience helper to move to root (empty: stop now)
- `>[TEXT]` - complete active task and move up, with optional state description - `>[TEXT]` - complete active task and move up, with optional status description
- `<[TEXT]` - close active task and move up, with optional state description - `<[TEXT]` - close active task and move up, with optional status description
- `!TEXT` - set state for current task from text and move up - `!TEXT` - set status for current task from text and move up (empty to open)
- `,TEXT` - add text note (comment / description) - `,TEXT` - add text note (comment / description)
- TBI: `*[INT]` - set priority - can also be used in task, with any digit - TBI: `*[INT]` - set priority - can also be used in task creation, with any digit
- `@` - undoes last action (moving in place or upwards or waiting a minute confirms pending actions) - TBI: status history and creation with attribution
- `&` - undo last action (moving in place or upwards confirms pending actions)
- `wss://...` - switch or subscribe to relay (prefix with space to forcibly add a new one) - `wss://...` - switch or subscribe to relay (prefix with space to forcibly add a new one)
Property Filters: Property Filters:
@ -123,6 +124,8 @@ Property Filters:
- `+TAG` - add tag filter - `+TAG` - add tag filter
- `-TAG` - remove tag filters - `-TAG` - remove tag filters
- `?STATUS` - filter by status (type or description) - plain `?` to reset, `??` to show all - `?STATUS` - filter by status (type or description) - plain `?` to reset, `??` to show all
- `@AUTHOR` - filter by author (`@` for self, id prefix, name prefix)
- TBI: Filter by time
Status descriptions can be used for example for Kanban columns or review flows. Status descriptions can be used for example for Kanban columns or review flows.
An active tag or status filter will also set that attribute for newly created tasks. An active tag or status filter will also set that attribute for newly created tasks.
@ -148,6 +151,11 @@ An active tag or status filter will also set that attribute for newly created ta
For debugging: `props`, `alltags`, `descriptions` For debugging: `props`, `alltags`, `descriptions`
### Notes
- TBI = To Be Implemented
- `. TASK` - create and enter a new task even if the name matches an existing one
## Nostr reference ## Nostr reference
Mostr mainly uses the following NIPs: Mostr mainly uses the following NIPs:
@ -164,17 +172,26 @@ Considering to use Calendar: https://github.com/nostr-protocol/nips/blob/master/
## Plans ## Plans
- Remove state filter when moving up? - Local Database Cache, Negentropy Reconciliation
-> Offline Use!
- Scheduling
- Remove status filter when moving up?
- Task markdown support? - colored - Task markdown support? - colored
- Time tracking: Ability to postpone task and add planned timestamps (calendar entry) - Time tracking: Ability to postpone task and add planned timestamps (calendar entry)
- Parse Hashtag tags from task name - Parse Hashtag tags from task name
- Unified Filter object - Unified Filter object
-> include subtasks of matched tasks -> include subtasks of matched tasks
- Relay Switching
- Speedup: Offline caching & Expiry (no need to fetch potential years of history) - Speedup: Offline caching & Expiry (no need to fetch potential years of history)
+ Fetch most recent tasks first + Fetch most recent tasks first
+ Relay: compress tracked time for old tasks, filter closed tasks + Relay: compress tracked time for old tasks, filter closed tasks
+ Relay: filter out task state updates within few seconds, also on client side + Relay: filter out task status updates within few seconds, also on client side
### Command
- Open Command characters: `_^\=$%~'"`, `{}[]`
- Remove colon from task creation syntax
- reassign undo to `&` and use `@` for people
- maybe use `;` for sorting instead of `::`
### Conceptual ### Conceptual
@ -182,9 +199,10 @@ The following features are not ready to be implemented
because they need conceptualization. because they need conceptualization.
Suggestions welcome! Suggestions welcome!
- Special commands: help, exit, tutorial, change log level
- Duplicate task (subtasks? timetracking?)
- What if I want to postpone a procedure, i.e. make it pending, or move it across kanban, does this make sense? - What if I want to postpone a procedure, i.e. make it pending, or move it across kanban, does this make sense?
- Priorities - Dependencies (change from tags to properties so they can be added later? or maybe as a status?)
- Dependencies (change from tags to properties so they can be added later? or maybe as a state?)
- Templates - Templates
- Ownership - Ownership
- Combined formatting and recursion specifiers - Combined formatting and recursion specifiers
@ -194,11 +212,45 @@ Suggestions welcome!
### Interfaces ### Interfaces
- TUI: Clear terminal? Refresh on empty prompt after timeout? - TUI: Clear Terminal? Refresh on empty prompt after timeout?
- Kanban, GANTT, Calendar - Kanban, GANTT, Calendar
- Web Interface, Messenger integrations - Web Interface, Messenger integrations
## Notes ## Exemplary Workflows
- TBI = To Be Implemented - Freelancer
- `. TASK` - create and enter a new task even if the name matches an existing one - Family Chore management
- Inter-Disciplinary Project Team -> Company with multiple projects and multiple relays
+ Permissions via status or assignment (reassignment?)
+ Tasks can be blocked while having a status (e.g. kanban column)
+ A meeting can be worked on (tracked) before it starts
+ Schedule for multiple people
- Tracking Daily Routines / Habits
### Contexts
A context is a custom set of filters such as status, tags, assignee
so that the visible tasks are always relevant
and newly created tasks are less of a hassle to type out
since they will automatically take on that context.
By automating these contexts based on triggers, scripts or time,
relevant tasks can be surfaced automatically.
#### Example
In the morning, your groggy brain is good at divergent thinking,
and you like to do sports in the morning.
So for that time, mostr can show you tasks tagged for divergent thinking,
since you are easily distracted filter out those that require the internet,
as well as anything sportsy.
After you come back from sports and had breakfast,
for example detected through a period of inactivity on your device,
you are ready for work, so the different work projects are shown and you delve into one.
After 90 minutes you reach a natural low in your focus,
so mostr surfaces break activities -
such as a short walk, a small workout, some instrument practice
or simply grabbing a snack and drink.
After lunch you like to take an extended afternoon break,
so your call list pops up -
you can give a few people a call as you make a market run,
before going for siesta.

View File

@ -7,6 +7,7 @@ pub fn some_non_empty(str: &str) -> Option<String> {
if str.is_empty() { None } else { Some(str.to_string()) } if str.is_empty() { None } else { Some(str.to_string()) }
} }
// TODO as macro so that log comes from appropriate module
pub fn or_print<T, U: Display>(result: Result<T, U>) -> Option<T> { pub fn or_print<T, U: Display>(result: Result<T, U>) -> Option<T> {
match result { match result {
Ok(value) => Some(value), Ok(value) => Some(value),

View File

@ -400,7 +400,7 @@ async fn main() {
tasks.move_up(); tasks.move_up();
} }
Some('@') => { Some('@') | Some('&') => {
tasks.undo(); tasks.undo();
} }

View File

@ -28,6 +28,7 @@ pub(crate) struct Tasks {
tasks: TaskMap, tasks: TaskMap,
/// History of active tasks by PubKey /// History of active tasks by PubKey
history: HashMap<PublicKey, BTreeSet<Event>>, history: HashMap<PublicKey, BTreeSet<Event>>,
/// The task properties currently visible /// The task properties currently visible
properties: Vec<String>, properties: Vec<String>,
/// The task properties sorted by /// The task properties sorted by
@ -349,9 +350,10 @@ impl Tasks {
} }
let res: Vec<&Task> = self.resolve_tasks(self.view.iter()); let res: Vec<&Task> = self.resolve_tasks(self.view.iter());
if res.len() > 0 { if res.len() > 0 {
// Currently ignores filter when it matches nothing // Currently ignores filtered view when it matches nothing
return res; return res;
} }
// TODO use ChildrenIterator
self.resolve_tasks(self.children_of(self.position)).into_iter() self.resolve_tasks(self.children_of(self.position)).into_iter()
.filter(|t| { .filter(|t| {
// TODO apply filters in transit // TODO apply filters in transit
@ -705,7 +707,7 @@ impl Tasks {
} }
pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId { pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId {
info!("{} from {}", self.position.map_or(String::from("Stopping time-tracking"), |id| format!("Tracking \"{}\"", self.get_task_title(&id))), time.to_human_datetime()); // TODO omit seconds info!("{} from {}", self.position.map_or(String::from("Stopping time-tracking"), |id| format!("Tracking \"{}\"", self.get_task_title(&id))), time.to_human_datetime());
let pos = self.get_position(); let pos = self.get_position();
let tracking = build_tracking(pos); let tracking = build_tracking(pos);
// TODO this can lead to funny deletions // TODO this can lead to funny deletions
@ -723,6 +725,7 @@ impl Tasks {
self.submit(tracking.custom_created_at(time)) self.submit(tracking.custom_created_at(time))
} }
/// Sign and queue the event to the relay, returning its id
fn submit(&mut self, builder: EventBuilder) -> EventId { fn submit(&mut self, builder: EventBuilder) -> EventId {
let event = self.sender.submit(builder).unwrap(); let event = self.sender.submit(builder).unwrap();
let id = event.id; let id = event.id;
@ -843,9 +846,11 @@ pub trait PropertyCollection<T> {
fn add_or_remove(&mut self, value: T); fn add_or_remove(&mut self, value: T);
fn add_or_remove_at(&mut self, value: T, index: usize); fn add_or_remove_at(&mut self, value: T, index: usize);
} }
impl <T> PropertyCollection<T> for Vec<T> impl<T> PropertyCollection<T> for Vec<T>
where T: Display, T: Eq, T: Clone { where
fn remove_at(&mut self, index: usize) { T: Display + Eq + Clone,
{
fn remove_at(&mut self, index: usize) {
let col = self.remove(index); let col = self.remove(index);
info!("Removed property column \"{col}\""); info!("Removed property column \"{col}\"");
} }