Add detail view and create/finish time for task - #27
Open
LiuYinCarl wants to merge 60 commits into
Open
LiuYinCarl wants to merge 60 commits into
LiuYinCarl wants to merge 60 commits into
Conversation
LiuYinCarl
commented
Jan 19, 2026
- Add Create time and Finsih time for tasks.
- Add Task Detail View which binding to 'v'.
Completed tasks are now hidden in the task list by default. Press `t` to toggle their visibility and immediately refresh the view. 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
- Remove unused `toml` dependency - Fix `get_indicator_done_tasks_color` 50% boundary overlap bug - Move `load_delete_confirm_items` from task.rs to ui.rs - Extract `format_timestamp`/`format_duration` to util.rs - Eliminate clone-write-reload anti-pattern in all CRUD operations - Extract `handle_modal_nav` helper for repeated modal keyboard logic - Remove dead `reload` and `_get_all` methods 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
- Add TASK_PRIORITY_NONE constant instead of magic 0 - Widen status and priority list modals to prevent text clipping - Update all priority 0 references to TASK_PRIORITY_NONE 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
- AddProject handler selected projects.len() (one past the end), so opening the tasks of a freshly created project panicked with an index out of bounds error; select len() - 1 and skip empty titles - Guard App::next/previous against empty lists (len() - 1 underflow) - Allow overriding the storage dir via BASILK_CONFIG_DIR so tests never touch the real config directory - Add unit tests for util, migration, json, project, task and app navigation, plus proptest-based property/fuzz tests
- Stopwatch (s) bound to the selected task accumulates into time_spent_secs; pomodoro (c) is a global countdown that rings the terminal bell at zero and persists nothing - Per-task estimated_hours (g in task details) with progress shown in the task list, details view, and timer modal - Event loop switches to poll-based ticking for live readouts; timers survive view switches and settle on stop, countdown zero, or quit - New c8f21 JSON migration for the timer fields
The timer modal now shows the readout as 5-row block-art digits instead
of a single text line, and a finished pomodoro rings the bell once and
stays visible ("time's up!") until dismissed with any key instead of
closing automatically.
Press b in the task view to toggle between the classic list and a board with Up Next / On Going / Done swimlanes. Left/right switch lanes, up/down move within a lane; all task keybindings (details, status, priority, timers, ...) work unchanged since the board is a rendering mode of ViewTasks, not a new ViewMode. The board always shows the Done lane and the focus follows a task across lanes when its status changes. Task lines are built by the shared Task::repr_spans helper so the list and board renderings cannot drift apart.
Split App::run's monolithic per-view key handling into dedicated handlers so the loop stays shallow, and break Json::check into focused paths for the current data file and legacy versioned files.
Press m in the project list to open global, project-independent notes. A note is a titled entry whose body is Markdown: Enter opens a full-page rendered preview (pulldown-cmark -> ratatui Text with a style stack), and e switches to a full-page tui-textarea editor (Esc saves and returns to the preview). Notes are stored in the same basilk_data.json wrapper behind #[serde(default)], so pre-notes files load unchanged; the e5a1c migration only bumps the version. Both write paths preserve the other half of the file. Also fix show_items classifying ViewHelp/InfoMigration: opening help over the projects or notes view with an empty project list fell into the tasks branch and panicked in Project::get_current (ratatui clears the list selection when rendering an empty list).
fanitriastowo
added a commit
to fanitriastowo/basilk
that referenced
this pull request
Aug 25, 2026
…, board, timers Pulls LiuYinCarl/basilk master (upstream GabAlpha/basilk PR GabAlpha#27, unmerged there) into this fork: task detail view with create/finish times, per-task notes, global Markdown notes, kanban board view, stopwatch and pomodoro timers, time estimates, hide-done toggle, help popup, and the first test suite in the repo. Data moves from per-version <version>.json files to a single basilk_data.json wrapper, migrated on first launch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xmQhyWJSB8Lak4GTto1Fp
Automates quality checks on every push and pull request so regressions are caught before review. 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
Resolves redundant returns, slice and string parameter types, and other lints so clippy can gate future changes with -D warnings. 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-pro
Raise line coverage from ~58% to 99.5% (only the real-terminal glue in main.rs stays uncovered, since it cannot run inside a unit test): - Refactor the event loop into run_with_source over an injectable KeySource so tests drive the full draw/dispatch/tick loop in-process with synthetic key events (Quit, Skip, migration info, Release filter). - Make Cli::parse pure and unit-testable; --version print/exit moved to main and verified end-to-end by tests/cli.rs via the real binary. - Cover every key handler, all 23 ViewModes, the board view, timer and hint readouts, delete/help/details/input modals, markdown edge cases (HTML, images, H3, hard breaks, trailing blank trim), JSON config-dir fallback and current-version check, and digit glyphs. - Fix a latent panic: opening help over a view with an empty list used to clear selected_project_index (use_state(ViewHelp) always returned the project state, and ratatui resets the state of an empty list), panicking in Project::get_current on the next redraw. ViewHelp now maps to the list state of the view it was opened from. - Enforce coverage in CI with cargo llvm-cov --fail-under-lines 95.
added 2 commits
August 26, 2026 00:13
checkout@v4/v3 and cache@v4 target Node 20, which GitHub now runs on a deprecated runtime (forced onto Node 24). checkout@v5 and cache@v5 use node24 natively with no usage changes.
- release.yml: any push to master touching src/, tests/, Cargo.toml or Cargo.lock bumps the patch version (commit subjects starting with [major]/[minor] bump that component instead), tags vX.Y.Z, builds release binaries for Linux, macOS (Intel + Apple Silicon) and Windows, and publishes them to a GitHub Release with auto-generated notes. A concurrency queue prevents racing bumps; the bump commit is pushed with GITHUB_TOKEN so it cannot re-trigger the workflow. - scripts/bump-version.sh: local manual bump (patch/minor/major) that updates Cargo.toml + Cargo.lock, commits and tags. - Document the versioning/release mechanism in README and AGENTS.md.
download-artifact merge-multiple flattened the three unix binaries, all named 'basilk', so only one survived. Stage each binary as basilk-<target> (and basilk-<target>.exe on Windows) before upload.
scaling of Task/Project::load_items, full-frame render at 2k tasks (list and board), Markdown rendering and JSON persistence, run via ./scripts/bench.sh. Measured on release build: ~0.3 ms/frame at 2k tasks (250 ms budget), ~2.5 ms for 10k-task load_items, 312 KB Markdown in ~3.5 ms, idle CPU 0.0%, startup ~6 ms.
The workflow no longer bumps versions or commits on its own. Releases are now triggered by pushing a vX.Y.Z tag (version updated manually via ./scripts/bump-version.sh). The pipeline verifies the tag matches the version in Cargo.toml, builds the 4 platform binaries from the tagged commit, and publishes the GitHub Release. workflow_dispatch re-publishes an existing tag.
A panic while the TUI is active used to strand the terminal in raw mode / alternate screen, making it look like the terminal no longer accepts input. init_terminal now installs a panic hook that restores the terminal before delegating to the default hook. Also add a regression test for opening help over an all-done (empty) task list and a deterministic random-key fuzz over the event loop.
A code commit without a version bump can never become a release (releases are tag-driven and the version lives in Cargo.toml), so require the bump at commit time: - .githooks/pre-commit blocks code commits (src/, tests/, Cargo manifests) that do not bump the version, reuse an existing tag, or leave Cargo.lock out of sync; .githooks/post-commit creates the vX.Y.Z tag automatically after a version-bump commit. Enable once per clone via scripts/install-hooks.sh. - The version-bump job in ci.yml is the server-side backstop: pushes and PRs that change code without bumping the version fail. - bump-version.sh now edits Cargo.toml + Cargo.lock in the working tree only (no commit/tag) to fit the hook-driven flow.
fs::write straight over basilk_data.json could leave a truncated file behind when interrupted, crashing the next startup on unparseable JSON. Write to a sibling basilk_data.json.tmp first and rename it over the target (same directory, so the rename stays on one filesystem), cleaning up the temp file on failure.
The legacy migration deleted the old versioned file right after writing the new one, before the recursive Json::check() verified it. Reorder to write -> verify -> remove, propagate write failures through the new write_internal Result so a failed migration keeps the legacy file, and treat the removal itself as best-effort cleanup.
read_notes swallowed every error and returned an empty list, and the write paths used it (and a panicking read) for their read-modify-write, so a corrupt data file was silently rewritten with an empty counterpart. Add a strict internal read (missing file -> None, parse failure -> Err), use it in Json::write/write_notes so they refuse to write, and make Json::read return Result so main can report a corrupt data file with its path before the terminal enters raw mode.
Every mutation deep-copied the whole project or note list for Json::write/write_notes. The write paths now take &[Project]/&[Note] and serialize through a borrowed DataWrapperRef, so no clone happens at the call sites or inside the persistence layer. Behavior is unchanged.
The static VERSION string was an implicit invariant maintained by call order: writes read it, but only check/read assigned it. The version now travels with the DataWrapper itself — the write paths take it from the strictly re-read on-disk wrapper, falling back to the latest known version when no file exists. This removes the MutexGuard threading and manual drops in the check paths while preserving the behavior of never downgrading a version written by a newer binary.
handle_modal_nav mapped Tab to previous and BackTab to next, the inverse of every list view. Swap them so Tab moves down and BackTab moves up, and update the modal nav test to assert both directions.
The task title is the stable identity of a task (selection restore, timer binding, add_time_spent all match the first task by title), so a duplicate title would silently act on the wrong task. Task::create and Task::rename now return bool and refuse a title already taken in the same project; the add/rename handlers keep the input view open on a rejection instead of silently succeeding.
Previously only --version was recognized and basilk --help launched the full-screen TUI. Cli::parse now maps --help/-h to a new CliAction::ShowHelp, main prints the USAGE text and exits like --version does, and tests/cli.rs asserts the end-to-end behavior.
The details modal computed the estimate percentage inline with f64 and two decimal places while the timer modal uses Task::estimate_progress (rounded integer, saturating arithmetic), so the same number was presented in two different formats. Both now go through estimate_progress.
Percentages 1..=24 fell through to the White fallback because the LightMagenta band started at 25. Extend it to 1..=50 so any started project is colored, and update the threshold test.
…ities on load Hand-edited JSON can carry statuses/priorities outside the known sets. The sort keys used position() and None sorts before Some(0), so unknown values jumped to the front of the list; they now map past the end of the known keys and sort last. load_items also normalizes Done tasks to priority NONE on every load, restoring the invariant the list/board index math relies on. board_sync now documents that a task with an unknown status keeps the current lane focus.
Note::create refused an empty title but Note::rename accepted one, and rename never stamped updated_at the way update_body does. rename now matches create (empty input is a silent no-op) and updates updated_at.
Replace the cloned vec, nine-field dummy Task fallback, and double clone with a plain Option map plus unwrap_or_default.
Count via iter().filter().count() instead of cloning the whole task vec, and drop the stray trailing comma in the done-count format.
The two options are compile-time constants, yet they were built once at startup and threaded through the event loop, handle_key, render, and render_modal, then cloned again every frame via to_vec(). Construct them where they are used: View::delete_confirm_items() feeds both show_delete_item_modal and the delete key handlers (which only need the option count for navigation). Removes Ui::load_delete_confirm_items and the delete_confirm_items parameter everywhere.
The second parameter is an absolute row count (Constraint::Length), not a percentage, so rename the pair to width_pct/height_rows. Clamp width_pct to 100: a larger value made 100 - width_pct underflow u16 and panic in debug builds.
Rename load_statues_items to load_statuses_items and use map_or for the timer's running-elapsed fallback.
- Call change_view as a method instead of App::change_view(self, ...) - Prefill inputs with Input::default().with_value(...) instead of cloning the previous input - Take &[ListItem] instead of &Vec<ListItem> in handle_key, handle_change_status_task, handle_change_priority_task, and handle_modal_nav
Task/Project/Note::get_current return immutable references, so they only need a shared borrow. All call sites compile unchanged (&mut reborrows as &); explicit &mut app arguments in tests were simplified to &app. No call site needed to keep a mutable borrow.
render_markdown and get_spaced_title both return owned values, so the note borrow can end before note_scroll is clamped. Reordering the statements that way drops the per-frame clone of the whole note body and title. Markdown is still re-parsed every frame, a known trade-off.
- markdown.rs: raw HTML is dropped entirely, not rendered as plain text; tables render as plain source only because the pulldown-cmark tables extension is off - view.rs: the Time Consumed line only requires created_at; without completed_at format_duration prints "Task not completed" - tests/cli.rs: the suite covers --version/--help print-and-exit only, not terminal setup - AGENTS.md: drop the nonexistent src/config.rs entry, rewrite the half-finished src/app.rs note (App lives in main.rs), and correct the key-handler testing note (handlers do change views via self.change_view; view_mode must be preset for use_state)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.