feat: add status

- real .klyban.csv
- real .klyban.conf
This commit is contained in:
Johann Dreo 2023-07-28 12:08:36 +02:00
commit 68915c9d2f
3 changed files with 76 additions and 32 deletions

15
.klyban.conf Normal file
View file

@ -0,0 +1,15 @@
[options]
status_key = STATUS
id_key = ID
title_key = TITLE
details_key = DETAILS
tags_key = TAGS
deadline_key = DEADLINE
show_keys = ID,TITLE,DETAILS,DEADLINE,TAGS
[options.add]
details = ""
tags = ""
deadline = ""
status = TODO

View file

@ -1,9 +1,5 @@
"ID","STATUS","TITLE","DETAILS","TAGS","DEADLINE" "ID","STATUS","TITLE","DETAILS","TAGS","DEADLINE","TOUCHED"
1,"DOING","print card","pretty print fixed-width cards given a content","klyban","" 0,"TODO","Use click-option-group","To help sort options in categories in help.","","","2023-07-28T12:04:02.615501"
2,"TODO","print table","pretty print set of cards on each column","klyban","" 1,"TODO","Use click-aliases","To allow for aliases (TBC: user-defined in config file?)","","","2023-07-28T12:05:04.229519"
3,"TODO","nested prints","print cards within cards","klyban","" 2,"TODO","edit existing","When calling edit, populate defaults with existing data.","","","2023-07-28T12:07:08.177802"
4,"TODO","a test","","","" 3,"TODO","sanity checks","Check data consistency in load_data and save_data.","","","2023-07-28T12:08:10.272349"
5,"TODO","another test","","",""
6,"TODO","another test","","",""
7,"TODO","anothering test","","",""
8,"TODO","anothering test","","",""

1 ID STATUS TITLE DETAILS TAGS DEADLINE TOUCHED
2 1 0 DOING TODO print card Use click-option-group pretty print fixed-width cards given a content To help sort options in categories in help. klyban 2023-07-28T12:04:02.615501
3 2 1 TODO print table Use click-aliases pretty print set of cards on each column To allow for aliases (TBC: user-defined in config file?) klyban 2023-07-28T12:05:04.229519
4 3 2 TODO nested prints edit existing print cards within cards When calling edit, populate defaults with existing data. klyban 2023-07-28T12:07:08.177802
5 4 3 TODO a test sanity checks Check data consistency in load_data and save_data. 2023-07-28T12:08:10.272349
5 TODO another test
6 TODO another test
7 TODO anothering test
8 TODO anothering test

View file

@ -38,10 +38,14 @@ def load_data(context):
context.obj['deadline_key'], context.obj['deadline_key'],
context.obj['touched_key'], context.obj['touched_key'],
]) ])
df = df.set_index(context.obj['id_key'])
save_data(context, df) save_data(context, df)
# set index on TID. else:
# set index on ID.
df = df.astype({context.obj['id_key']:int}).set_index(context.obj['id_key']) df = df.astype({context.obj['id_key']:int}).set_index(context.obj['id_key'])
finally:
if context.obj['debug']: if context.obj['debug']:
print("Loaded:") print("Loaded:")
print(df) print(df)
@ -54,7 +58,7 @@ def save_data(context, df):
print(df) print(df)
# FIXME double check that there are actually data. # FIXME double check that there are actually data.
# Bring back TID as a regular column. # Bring back ID as a regular column.
df = df.reset_index() df = df.reset_index()
# Automagically manages standard input if input=="-", thanks to allow_dash=True. # Automagically manages standard input if input=="-", thanks to allow_dash=True.
@ -87,7 +91,7 @@ def configure(context, param, filename):
callback = configure, callback = configure,
is_eager = True, is_eager = True,
expose_value = False, expose_value = False,
help = 'Read option defaults from the specified configuration file', help = 'Read option defaults from the specified configuration file.',
show_default = True, show_default = True,
) )
@click.option('-i', '--input' , help="CSV data file.", default='.klyban.csv', type=click.Path(writable=True, readable=True, allow_dash=True), show_default=True) @click.option('-i', '--input' , help="CSV data file.", default='.klyban.csv', type=click.Path(writable=True, readable=True, allow_dash=True), show_default=True)
@ -176,6 +180,9 @@ def show(context):
def add(context, title, status, details, tags, deadline): def add(context, title, status, details, tags, deadline):
"""Add a new task.""" """Add a new task."""
df = load_data(context) df = load_data(context)
if df.index.empty:
next_id = 0
else:
next_id = df.index.max() + 1 next_id = df.index.max() + 1
df.loc[next_id] = pd.Series({ df.loc[next_id] = pd.Series({
context.obj['status_key']: status, context.obj['status_key']: status,
@ -246,17 +253,49 @@ def delete(context, tid):
context.invoke(show) context.invoke(show)
def change_status(context, tid, new_status):
"""Edit the status of a task."""
df = load_data(context)
row = df.loc[tid]
if row.empty:
error("ID_NOT_FOUND", "{} = {} not found in `{}`".format(context.obj['id_key'], tid, context.obj['input']))
if new_status not in context.obj['status_list']:
error("UNKNOWN_STATUS", "Unknown status `{}`".format(new_status))
else:
df.loc[tid, context.obj['status_key']] = new_status
df.loc[tid, context.obj['touched_key']] = datetime.datetime.now().isoformat()
save_data(context, df)
@cli.command() @cli.command()
@click.argument('TID', required=True, type=int) @click.argument('TID', required=True, type=int, is_eager=True, callback=check_id)
@click.argument('STATUS', required=True, type=str)
@click.pass_context
def status(context, tid, status):
"""Explicitely change the status of a task.
Use status names configured with --status-list."""
change_status(context, tid, status)
context.invoke(show)
@cli.command()
@click.argument('TID', required=True, type=int, is_eager=True, callback=check_id)
@click.pass_context @click.pass_context
def promote(context, tid): def promote(context, tid):
"""Upgrade the status of task `TID` to the next one. """Upgrade the status of a task to the next one.
Use status names configured with --status-list.""" Use status names configured with --status-list."""
df = load_data(context) df = load_data(context)
row = df.loc[ df[context.obj['id_key']] == tid ] row = df.loc[tid]
if row.empty: if row.empty:
error("ID_NOT_FOUND", "{} = {} not found in `{}`".format(context.obj['id_key'], tid, context.obj['input'])) error("ID_NOT_FOUND", "{} = {} not found in `{}`".format(context.obj['id_key'], tid, context.obj['input']))
@ -269,25 +308,22 @@ def promote(context, tid):
if i >= len(context.obj['status_list'])-1: if i >= len(context.obj['status_list'])-1:
error("UNKNOWN_STATUS", "Cannot promote task {}, already at the last status.".format(tid)) error("UNKNOWN_STATUS", "Cannot promote task {}, already at the last status.".format(tid))
else: else:
df.loc[df[context.obj['id_key']] == tid, context.obj['status_key']] = context.obj['status_list'][i+1] change_status(context, tid, context.obj['status_list'][i+1])
df.loc[df[context.obj['id_key']] == tid, context.obj['touched_key']] = datetime.datetime.now().isoformat()
save_data(context, df)
context.invoke(show) context.invoke(show)
@cli.command() @cli.command()
@click.argument('TID', required=True, type=int) @click.argument('TID', required=True, type=int, is_eager=True, callback=check_id)
@click.pass_context @click.pass_context
def demote(context, tid): def demote(context, tid):
"""Downgrade the status of task `TID` to the previous one. """Downgrade the status of a task to the previous one.
Use status names configured with --status-list.""" Use status names configured with --status-list."""
df = load_data(context) df = load_data(context)
row = df.loc[ df[context.obj['id_key']] == tid ] row = df.loc[tid]
if row.empty: if row.empty:
error("ID_NOT_FOUND", "{} = {} not found in `{}`".format(context.obj['id_key'], tid, context.obj['input'])) error("ID_NOT_FOUND", "{} = {} not found in `{}`".format(context.obj['id_key'], tid, context.obj['input']))
@ -300,10 +336,7 @@ def demote(context, tid):
if i == 0: if i == 0:
error("UNKNOWN_STATUS", "Cannot demote task {}, already at the first status.".format(tid)) error("UNKNOWN_STATUS", "Cannot demote task {}, already at the first status.".format(tid))
else: else:
df.loc[df[context.obj['id_key']] == tid, context.obj['status_key']] = context.obj['status_list'][i-1] change_status(context, tid, context.obj['status_list'][i-1])
df.loc[df[context.obj['id_key']] == tid, context.obj['touched_key']] = datetime.datetime.now().isoformat()
save_data(context, df)
context.invoke(show) context.invoke(show)