mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-07-07 20:06:39 +02:00
Add configurable default range for reports
Query rule 'reports.<name>.range' for the specific default range of the report. Use rule 'reports.range' to configure an overall default range for all reports. Make internal reports 'summary', 'month', 'week', 'day', and 'gaps' use this feature. Closes #477 Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
This commit is contained in:
parent
d056719a36
commit
5265b26e86
8 changed files with 84 additions and 11 deletions
1
AUTHORS
1
AUTHORS
|
@ -104,3 +104,4 @@ Thanks to the following, who submitted detailed bug reports and excellent sugges
|
||||||
eq0cdk
|
eq0cdk
|
||||||
squirrellyDave
|
squirrellyDave
|
||||||
Edd Salkield
|
Edd Salkield
|
||||||
|
Oivvio Polite
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
- #470 Do not leak filter in IntervalFilterFirstOf
|
- #470 Do not leak filter in IntervalFilterFirstOf
|
||||||
(thanks to Shaun Ruffel)
|
(thanks to Shaun Ruffel)
|
||||||
- #474 Make display of ids and annotations in summary report configurable
|
- #474 Make display of ids and annotations in summary report configurable
|
||||||
|
- #477 Add configurable default range for reports
|
||||||
|
(thanks to Oivvio Polite)
|
||||||
- #478 Add support for XDG Base Directory specification on Unixes
|
- #478 Add support for XDG Base Directory specification on Unixes
|
||||||
(Thanks to Stanisław Wysocki)
|
(Thanks to Stanisław Wysocki)
|
||||||
- #491 Tracking an interval in the future while actively tracking time results in a database inconsistency
|
- #491 Tracking an interval in the future while actively tracking time results in a database inconsistency
|
||||||
|
|
|
@ -14,6 +14,7 @@ A chart summarizes the tracked and untracked time with colored blocks drawn on a
|
||||||
It accepts date ranges and tags for filtering.
|
It accepts date ranges and tags for filtering.
|
||||||
There are three types: *day*, *week*, and *month* with their respective commands.
|
There are three types: *day*, *week*, and *month* with their respective commands.
|
||||||
The **reports.**__<type>__**.range** configuration setting overrides the default date range.
|
The **reports.**__<type>__**.range** configuration setting overrides the default date range.
|
||||||
|
One can override the global default date range with the **reports.range** configuration.
|
||||||
For more details, and precise times, use the 'summary' report.
|
For more details, and precise times, use the 'summary' report.
|
||||||
|
|
||||||
*month*::
|
*month*::
|
||||||
|
|
|
@ -18,3 +18,14 @@ This does however assume there is a 'foo' extension installed.
|
||||||
|
|
||||||
The return code is the return code of the extension.
|
The return code is the return code of the extension.
|
||||||
If the extension produces no output and a non-zero rc, then 255 is returned.
|
If the extension produces no output and a non-zero rc, then 255 is returned.
|
||||||
|
|
||||||
|
== CONFIGURATION
|
||||||
|
|
||||||
|
**reports.range**::
|
||||||
|
Sets the default date range for all reports.
|
||||||
|
The value has to be a range hint, see timew-hints(7).
|
||||||
|
Defaults to `:all`
|
||||||
|
|
||||||
|
**reports.**__<name>__**.range**::
|
||||||
|
Set the date range for report _name_, where _name_ is the name of the report executable without its extension (i.e. a report executable 'foo.py' is referred to by 'foo').
|
||||||
|
The value has to be a range hint, see timew-hints(7).
|
||||||
|
|
|
@ -37,6 +37,11 @@ Determines whether the id column is shown in the summary.
|
||||||
Can be overridden by the ':ids' and ':no-ids' hint, respectively.
|
Can be overridden by the ':ids' and ':no-ids' hint, respectively.
|
||||||
Default value is 'no'
|
Default value is 'no'
|
||||||
|
|
||||||
|
**reports.summary.range**::
|
||||||
|
Set the date range for the summary report.
|
||||||
|
The value has to be a range hint, see timew-hints(7).
|
||||||
|
Default value is ':day'
|
||||||
|
|
||||||
**tags.**__<tag>__**.color**::
|
**tags.**__<tag>__**.color**::
|
||||||
Assigns a specific foreground and background color to a tag.
|
Assigns a specific foreground and background color to a tag.
|
||||||
Examples of valid colors include 'white', 'gray8', 'black on yellow', and 'rgb345'.
|
Examples of valid colors include 'white', 'gray8', 'black on yellow', and 'rgb345'.
|
||||||
|
|
|
@ -48,8 +48,11 @@ int CmdChartDay (
|
||||||
Rules& rules,
|
Rules& rules,
|
||||||
Database& database)
|
Database& database)
|
||||||
{
|
{
|
||||||
|
auto default_hint = rules.get ("reports.range", ":day");
|
||||||
|
auto report_hint = rules.get ("reports.day.range", default_hint);
|
||||||
|
|
||||||
Range default_range = {};
|
Range default_range = {};
|
||||||
expandIntervalHint (rules.get ("reports.day.range", ":day"), default_range);
|
expandIntervalHint (report_hint, default_range);
|
||||||
|
|
||||||
// Create a filter, and if empty, choose the current day.
|
// Create a filter, and if empty, choose the current day.
|
||||||
auto filter = cli.getFilter (default_range);
|
auto filter = cli.getFilter (default_range);
|
||||||
|
@ -63,8 +66,11 @@ int CmdChartWeek (
|
||||||
Rules& rules,
|
Rules& rules,
|
||||||
Database& database)
|
Database& database)
|
||||||
{
|
{
|
||||||
|
auto default_hint = rules.get ("reports.range", ":week");
|
||||||
|
auto report_hint = rules.get ("reports.week.range", default_hint);
|
||||||
|
|
||||||
Range default_range = {};
|
Range default_range = {};
|
||||||
expandIntervalHint (rules.get ("reports.week.range", ":week"), default_range);
|
expandIntervalHint (report_hint, default_range);
|
||||||
|
|
||||||
// Create a filter, and if empty, choose the current week.
|
// Create a filter, and if empty, choose the current week.
|
||||||
auto filter = cli.getFilter (default_range);
|
auto filter = cli.getFilter (default_range);
|
||||||
|
@ -78,8 +84,11 @@ int CmdChartMonth (
|
||||||
Rules& rules,
|
Rules& rules,
|
||||||
Database& database)
|
Database& database)
|
||||||
{
|
{
|
||||||
|
auto default_hint = rules.get ("reports.range", ":month");
|
||||||
|
auto report_hint = rules.get ("reports.month.range", default_hint);
|
||||||
|
|
||||||
Range default_range = {};
|
Range default_range = {};
|
||||||
expandIntervalHint (rules.get ("reports.month.range", ":month"), default_range);
|
expandIntervalHint (report_hint, default_range);
|
||||||
|
|
||||||
// Create a filter, and if empty, choose the current month.
|
// Create a filter, and if empty, choose the current month.
|
||||||
auto filter = cli.getFilter (default_range);
|
auto filter = cli.getFilter (default_range);
|
||||||
|
|
|
@ -77,6 +77,35 @@ static std::string findExtension (
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string basename (const std::string &script_path)
|
||||||
|
{
|
||||||
|
const auto lastSlash = script_path.find_last_of ('/');
|
||||||
|
|
||||||
|
if (lastSlash != std::string::npos)
|
||||||
|
{
|
||||||
|
return script_path.substr (lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return script_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dropExtension (const std::string& basename)
|
||||||
|
{
|
||||||
|
const auto lastDot = basename.find_last_of ('.');
|
||||||
|
|
||||||
|
if (lastDot != std::string::npos)
|
||||||
|
{
|
||||||
|
return basename.substr (0, lastDot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getScriptName (const std::string& script_path)
|
||||||
|
{
|
||||||
|
return dropExtension (basename (script_path));
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int CmdReport (
|
int CmdReport (
|
||||||
const CLI& cli,
|
const CLI& cli,
|
||||||
|
@ -84,22 +113,30 @@ int CmdReport (
|
||||||
Database& database,
|
Database& database,
|
||||||
const Extensions& extensions)
|
const Extensions& extensions)
|
||||||
{
|
{
|
||||||
std::string script;
|
std::string script_path;
|
||||||
for (auto& arg : cli._args)
|
for (auto& arg : cli._args)
|
||||||
{
|
{
|
||||||
if (arg.hasTag ("EXT"))
|
if (arg.hasTag ("EXT"))
|
||||||
{
|
{
|
||||||
script = findExtension (extensions, arg.attribute ("canonical"));
|
script_path = findExtension (extensions, arg.attribute ("canonical"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script.empty ())
|
if (script_path.empty ())
|
||||||
{
|
{
|
||||||
throw std::string ("Specify which report to run.");
|
throw std::string ("Specify which report to run.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compose Header info.
|
auto script_name = getScriptName (script_path);
|
||||||
auto filter = cli.getFilter ();
|
auto default_hint = rules.get ("reports.range", ":all");
|
||||||
|
auto report_hint = rules.get (format ("reports.{1}.range", script_name), default_hint);
|
||||||
|
|
||||||
|
Range default_range = {};
|
||||||
|
expandIntervalHint (report_hint, default_range);
|
||||||
|
|
||||||
|
// Create a filter, and if empty, choose the current week.
|
||||||
|
auto filter = cli.getFilter (default_range);
|
||||||
|
|
||||||
IntervalFilterAndGroup filtering ({
|
IntervalFilterAndGroup filtering ({
|
||||||
std::make_shared <IntervalFilterAllInRange> ( Range { filter.start, filter.end }),
|
std::make_shared <IntervalFilterAllInRange> ( Range { filter.start, filter.end }),
|
||||||
std::make_shared <IntervalFilterAllWithTags> (filter.tags ())
|
std::make_shared <IntervalFilterAllWithTags> (filter.tags ())
|
||||||
|
@ -107,6 +144,7 @@ int CmdReport (
|
||||||
|
|
||||||
auto tracked = getTracked (database, rules, filtering);
|
auto tracked = getTracked (database, rules, filtering);
|
||||||
|
|
||||||
|
// Compose Header info.
|
||||||
rules.set ("temp.report.start", filter.is_started () ? filter.start.toISO () : "");
|
rules.set ("temp.report.start", filter.is_started () ? filter.start.toISO () : "");
|
||||||
rules.set ("temp.report.end", filter.is_ended () ? filter.end.toISO () : "");
|
rules.set ("temp.report.end", filter.is_ended () ? filter.end.toISO () : "");
|
||||||
rules.set ("temp.report.tags", joinQuotedIfNeeded (",", filter.tags ()));
|
rules.set ("temp.report.tags", joinQuotedIfNeeded (",", filter.tags ()));
|
||||||
|
@ -123,10 +161,10 @@ int CmdReport (
|
||||||
|
|
||||||
// Run the extensions.
|
// Run the extensions.
|
||||||
std::vector <std::string> output;
|
std::vector <std::string> output;
|
||||||
int rc = extensions.callExtension (script, split (input, '\n'), output);
|
int rc = extensions.callExtension (script_path, split (input, '\n'), output);
|
||||||
if (rc != 0 && output.size () == 0)
|
if (rc != 0 && output.size () == 0)
|
||||||
{
|
{
|
||||||
throw format ("'{1}' returned {2} without producing output.", script, rc);
|
throw format ("'{1}' returned {2} without producing output.", script_path, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the output.
|
// Display the output.
|
||||||
|
|
|
@ -48,7 +48,13 @@ int CmdSummary (
|
||||||
const bool verbose = rules.getBoolean ("verbose");
|
const bool verbose = rules.getBoolean ("verbose");
|
||||||
|
|
||||||
// Create a filter, and if empty, choose 'today'.
|
// Create a filter, and if empty, choose 'today'.
|
||||||
auto filter = cli.getFilter (Range { Datetime ("today"), Datetime ("tomorrow") });
|
auto default_hint = rules.get ("reports.range", ":day");
|
||||||
|
auto report_hint = rules.get ("reports.summary.range", default_hint);
|
||||||
|
|
||||||
|
Range default_range = {};
|
||||||
|
expandIntervalHint (report_hint, default_range);
|
||||||
|
|
||||||
|
auto filter = cli.getFilter (default_range);
|
||||||
|
|
||||||
// Load the data.
|
// Load the data.
|
||||||
IntervalFilterAndGroup filtering ({
|
IntervalFilterAndGroup filtering ({
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue