mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 17:34:04 +01:00
i3 focus block: red on miss, suitcase
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWZUTC9Zzdzsx7VW7dm
This commit is contained in:
parent
7581a904cd
commit
47b4510ac6
@ -0,0 +1,31 @@
|
||||
{
|
||||
"intent": "The i3 focus block turns red when an interview milestone is missed and shows a suitcase while a trip question is open; no new text.",
|
||||
"scope": [
|
||||
"linux_configuration/i3blocks/focus_project.sh",
|
||||
"linux_configuration/tests/test_i3blocks_focus_project.sh",
|
||||
"Non-goal: the block still renders only daily-limits' cached focus field"
|
||||
],
|
||||
"changes": [
|
||||
"jq render picks #FF5555 when focus.missed is true, over green and yellow",
|
||||
"jq render appends the FontAwesome suitcase (U+F0F2) when a trip_ask:* milestone is pending or missed; malformed milestones are ignored"
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "bash linux_configuration/tests/test_i3blocks_focus_project.sh",
|
||||
"result": "pass",
|
||||
"evidence": "red first (missed block stayed yellow), then all checks passed incl. red, suitcase, no-suitcase and malformed milestone cases"
|
||||
},
|
||||
{
|
||||
"command": "shellcheck linux_configuration/i3blocks/focus_project.sh linux_configuration/tests/test_i3blocks_focus_project.sh",
|
||||
"result": "pass",
|
||||
"evidence": "no findings"
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"Suitcase glyph needs the bar's FontAwesome font (installed: Font Awesome 7 Free Solid)"
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit; the live ~/.config/i3blocks/focus_project.sh is a symlink to the repo file",
|
||||
"Check the block renders yellow/green again"
|
||||
]
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
{
|
||||
"intent": "Merged-but-open issues (Merge only tags the opener, kado-no-akari #21) get their own 'Awaiting opener' column in ~/src/issue-dashboard and an 'awaiting' count in status.json; the i3bar issue_dashboard block shows it as '⏳ N' instead of counting it as to do.",
|
||||
"scope": [
|
||||
"linux_configuration/i3blocks/issue_dashboard.sh - read the optional 'awaiting' field and show '· ⏳ N' between '✓' and '✗' when N > 0",
|
||||
"linux_configuration/tests/test_i3blocks_issue_dashboard.sh - awaiting text, hidden at zero, ordering, colour, old-format file without the key",
|
||||
"Non-goal: the dashboard change itself (local repo ~/src/issue-dashboard, commit 0e6077c); the running dashboard server was not restarted."
|
||||
],
|
||||
"changes": [
|
||||
"awaiting is optional: a status.json from a server older than the column has no key and still renders '📋 N · ⚙ N · ✓ N', never grey.",
|
||||
"awaiting never changes the colour (it waits on the opener, not kuhy) and stays out of the short text; zero is hidden like '✗'.",
|
||||
"Still zero forks on the hot path: one more regex field read and an arithmetic test."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "bash linux_configuration/tests/test_i3blocks_issue_dashboard.sh",
|
||||
"result": "pass",
|
||||
"evidence": "awaiting / hidden-at-zero / ordering with ✗ / colour / old-format / stale / missing / broken / empty / click asserted; strace still shows one execve and no clone/fork."
|
||||
},
|
||||
{
|
||||
"command": "bash linux_configuration/tests/test_i3blocks_efficiency.sh",
|
||||
"result": "pass",
|
||||
"evidence": "All i3blocks efficiency regression tests passed."
|
||||
},
|
||||
{
|
||||
"command": "ISSUE_DASHBOARD_STATUS=<status.json from a scratch issue-dashboard server on a fixture source> issue_dashboard.sh",
|
||||
"result": "pass",
|
||||
"evidence": "'📋 1 · ⚙ 0 · ✓ 1 · ⏳ 2 · ✗ 1' #FF5555 from {todo 1, ready 1, awaiting 2, failed 1}; the live old-format status.json still renders '📋 14 · ⚙ 0 · ✓ 0' #FFFFFF."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"'⏳' shows only once kuhy restarts the dashboard server; until then the old server keeps writing merged-open issues into todo."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert this commit; the block reads the old fields only.",
|
||||
"Confirm the bar still renders '📋 N · ⚙ N · ✓ N'."
|
||||
]
|
||||
}
|
||||
@ -18,6 +18,9 @@
|
||||
# gaming_budget block already says "⏱?" for the same cache, and old minutes
|
||||
# must never be shown.
|
||||
#
|
||||
# Interview projects: focus.missed (any milestone missed or unknown) turns the
|
||||
# block red, over green and yellow; no text is added.
|
||||
#
|
||||
# Clicks (the block says what to do, so a click goes where the work is):
|
||||
# left `python3 -m focus_project.open`: the tutor focus screen (starts the
|
||||
# focus timer if it is not running) and the project's work URL
|
||||
@ -34,6 +37,10 @@ readonly STALE_AFTER_SECONDS=180
|
||||
# Dracula-ish palette, matching gaming_budget.sh.
|
||||
readonly YELLOW='#F1FA8C'
|
||||
readonly GREEN='#50FA7B'
|
||||
readonly RED='#FF5555'
|
||||
# FontAwesome suitcase (the bar's icon font): an interview project's trip
|
||||
# question (milestone trip_ask:*) is still open, pending or missed.
|
||||
readonly SUITCASE=$'\uf0f2'
|
||||
|
||||
emit() {
|
||||
# full_text, short_text, color: the three lines i3blocks reads.
|
||||
@ -60,14 +67,21 @@ hide() {
|
||||
# can never add lines to the block's output.
|
||||
render_focus() {
|
||||
local rendered
|
||||
rendered=$(jq -r --arg green "$GREEN" --arg yellow "$YELLOW" '
|
||||
rendered=$(jq -r --arg green "$GREEN" --arg yellow "$YELLOW" \
|
||||
--arg red "$RED" --arg suitcase "$SUITCASE" '
|
||||
(.generated_at | if type == "number" then floor else "none" end),
|
||||
(.focus | if type == "object" and (.project | type) == "string" then
|
||||
(.minutes // 0 | floor) as $m
|
||||
| (.daily_minutes // 0 | floor) as $d
|
||||
| ((.name // .project) | tostring | gsub("[\u0001-\u001f\u007f]"; " ")) as $name
|
||||
| "🎯 \($name) \($m)/\($d)", "🎯 \($m)/\($d)",
|
||||
(if $d > 0 and $m >= $d then $green else $yellow end)
|
||||
| (if any((.milestones | if type == "array" then .[] else empty end);
|
||||
type == "object" and ((.id | type) == "string")
|
||||
and (.id | startswith("trip_ask:"))
|
||||
and (.state == "pending" or .state == "missed"))
|
||||
then " " + $suitcase else "" end) as $trip
|
||||
| "🎯 \($name) \($m)/\($d)\($trip)", "🎯 \($m)/\($d)\($trip)",
|
||||
(if .missed == true then $red
|
||||
elif $d > 0 and $m >= $d then $green else $yellow end)
|
||||
else "", "", $yellow end)' "$LIMITS_CACHE" 2>/dev/null) || return 1
|
||||
printf '%s\n' "$rendered" >"$RENDER_CACHE"
|
||||
}
|
||||
|
||||
@ -63,6 +63,51 @@ out=$(run_block)
|
||||
assert_eq '🎯 HackerRank prep 120/120' "$(line 1 "$out")" 'target reached text'
|
||||
assert_eq '#50FA7B' "$(line 3 "$out")" 'green at daily_minutes'
|
||||
|
||||
printf 'Checking interview milestones (red when missed, suitcase when a trip question is open)...\n'
|
||||
RED='#FF5555'
|
||||
SUITCASE=$'\uf0f2'
|
||||
# focus_ms MISSED MINUTES MILESTONE_JSON_ARRAY
|
||||
focus_ms() {
|
||||
jq -nc --argjson x "$1" --argjson m "$2" --argjson ms "$3" \
|
||||
'{project:"p",name:"Interview",minutes:$m,daily_minutes:30,missed:$x,milestones:$ms}'
|
||||
}
|
||||
ms_json() { # ID STATE
|
||||
jq -nc --arg i "$1" --arg s "$2" '[{id:$i,due:"2026-11-12T23:59:00",state:$s}]'
|
||||
}
|
||||
write_cache "$NOW" "$(focus_ms true 5 "$(ms_json rules missed)")"
|
||||
out=$(run_block)
|
||||
assert_eq "$RED" "$(line 3 "$out")" 'a missed milestone turns the block red'
|
||||
assert_eq '🎯 Interview 5/30' "$(line 1 "$out")" 'red adds no text'
|
||||
write_cache "$NOW" "$(focus_ms true 30 "$(ms_json rules missed)")"
|
||||
assert_eq "$RED" "$(line 3 "$(run_block)")" 'red beats green once the daily target is reached'
|
||||
write_cache "$NOW" "$(focus_ms false 30 "$(ms_json rules "done")")"
|
||||
assert_eq '#50FA7B' "$(line 3 "$(run_block)")" 'all milestones done: not red'
|
||||
write_cache "$NOW" "$(focus_ms false 5 "$(ms_json rules pending)")"
|
||||
assert_eq '#F1FA8C' "$(line 3 "$(run_block)")" 'only pending milestones: not red'
|
||||
write_cache "$NOW" "$(focus_json 'No milestones' 5 120)"
|
||||
assert_eq '#F1FA8C' "$(line 3 "$(run_block)")" 'a project without milestones is not red'
|
||||
write_cache "$NOW" '{"project":null,"minutes":0,"daily_minutes":0,"missed":true}'
|
||||
assert_eq '' "$(line 1 "$(run_block)")" 'missed without a project stays hidden'
|
||||
|
||||
write_cache "$NOW" "$(focus_ms false 5 "$(ms_json trip_ask:2026-11-14 pending)")"
|
||||
out=$(run_block)
|
||||
assert_eq "🎯 Interview 5/30 $SUITCASE" "$(line 1 "$out")" 'pending trip question shows the suitcase'
|
||||
assert_eq "🎯 5/30 $SUITCASE" "$(line 2 "$out")" 'suitcase in the short text too'
|
||||
assert_eq '#F1FA8C' "$(line 3 "$out")" 'a pending trip question alone is not red'
|
||||
write_cache "$NOW" "$(focus_ms true 5 "$(ms_json trip_ask:2026-11-14 missed)")"
|
||||
out=$(run_block)
|
||||
assert_eq "🎯 Interview 5/30 $SUITCASE" "$(line 1 "$out")" 'missed trip question shows the suitcase'
|
||||
assert_eq "$RED" "$(line 3 "$out")" 'missed trip question is red'
|
||||
for state in "done" late_done; do
|
||||
write_cache "$NOW" "$(focus_ms false 5 "$(ms_json trip_ask:2026-11-14 "$state")")"
|
||||
assert_eq '🎯 Interview 5/30' "$(line 1 "$(run_block)")" "$state trip question shows no suitcase"
|
||||
done
|
||||
write_cache "$NOW" "$(focus_ms false 5 "$(ms_json phone:2026-11-14 pending)")"
|
||||
assert_eq '🎯 Interview 5/30' "$(line 1 "$(run_block)")" 'other open milestones show no suitcase'
|
||||
|
||||
write_cache "$NOW" "$(focus_ms false 5 '["junk",{"id":7},null]')"
|
||||
assert_eq '🎯 Interview 5/30' "$(line 1 "$(run_block)")" 'malformed milestones are ignored, not fatal'
|
||||
|
||||
printf 'Checking the hidden states...\n'
|
||||
write_cache "$NOW" '{"project":null,"minutes":0,"daily_minutes":0}'
|
||||
out=$(run_block)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user