Skip to content

Commit 7ac8fa5

Browse files
authored
Merge pull request #32 from monofox/feature/custom_queries
Feature: custom queries
2 parents 0289300 + 9f402bd commit 7ac8fa5

23 files changed

+736
-173
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## Sun 04, May, 2025
2+
- [x] Remember shortcuts for project and tags in a cache file.
3+
Default cache path: $HOME/.cache/taskwarrior-web/mnemonics.cache
4+
5+
## Thu 01, May, 2025
6+
- [x] Improved CI pipeline in order to increase continues quality checks.
7+
- [x] Improved mobile view: proper scaling of the pages as well as headers are now really sticky, not fixed anymore. This ensures, that the header does not cover any tasks on small displays.
8+
9+
## Tue 29, April, 2025
10+
- [x] Rework of task modifications.
11+
- [x] Adding absolute dates in task details.
12+
- [x] Added possibility to delete tasks.
13+
- [x] For denotation its now possible to select specific annotations.
14+
115
## Fri 28, March, 2025
216
- [x] Font's can be customized
317
- [x] Removed packaged font

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ serde_path_to_error = "0.1.17"
2828
shell-words = "1.1.0"
2929
directories = "6.0.0"
3030
toml = "0.8.22"
31+
config = { version = "0.15.11", default-features = false, features = ["toml"] }
3132

3233
[dev-dependencies]
3334
tempfile = "3.19.1"

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ RUN echo "NoExtract = !usr/share/doc/timew/*" >> /etc/pacman.conf \
2626
&& pacman -S --noconfirm task timew cronie vi \
2727
&& pacman -S --noconfirm python-pip \
2828
&& useradd -m -d /app task && passwd -d task \
29-
&& chown -R task:task /app && chmod -R 775 /app \
3029
&& mkdir -p /app/bin \
3130
&& mkdir -p /app/taskdata \
3231
&& mkdir -p /app/.task/hooks \
3332
&& mkdir -p /app/.timewarrior/data/ \
33+
&& mkdir -p /app/.config/taskwarrior-web/ \
34+
&& chown -R task:task /app && chmod -R 775 /app \
3435
&& systemctl enable cronie.service \
3536
&& cp /usr/share/doc/timew/ext/on-modify.timewarrior /app/.task/hooks/on-modify.timewarrior \
3637
&& chmod +x /app/.task/hooks/on-modify.timewarrior \
@@ -67,6 +68,7 @@ EXPOSE 3000
6768
# Taskwarrior data volume
6869
VOLUME /app/taskdata/
6970
VOLUME /app/.timewarrior/
71+
VOLUME /app/.config/taskwarrior-web/
7072

7173
ENV TASKRC="/app/.taskrc"
7274
ENV TASKDATA="/app/taskdata"

README.md

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ That should do it.
5959

6060
The docker shares following directories as volumes to store data:
6161

62-
| Volume path | Purpose |
63-
| ----------------- | ---------------------------------------------- |
64-
| /app/taskdata | Stores task data (mostly taskchampion.sqlite3) |
65-
| /app/.timewarrior | Stores timewarrior data |
62+
| Volume path | Purpose |
63+
| ----------------- | ---------------------------------------------- |
64+
| /app/taskdata | Stores task data (mostly taskchampion.sqlite3) |
65+
| /app/.timewarrior | Stores timewarrior data |
66+
| /app/.config/taskwarrior-web | Stores taskwarrior-web configuration file |
6667

6768
It is recommend to specify the corresponding volume in order to persist the data.
6869

@@ -78,12 +79,12 @@ It is recommend to specify the corresponding volume in order to persist the data
7879

7980
In order to configure the environment variables and contexts for `timewarrior-web`, docker environments can be specified:
8081

81-
| Docker environment | Shell environment | Purpose
82-
| -------------------------------- | ----------------------- | ---------------------------------------------------------|
82+
| Docker environment | Shell environment | Purpose |
83+
| -------------------------------- | ----------------------- | -------------------------------------------------------- |
8384
| TASK_WEB_TWK_SERVER_PORT | TWK_SERVER_PORT | Specifies the server port (see "Ports") |
8485
| TASK_WEB_DISPLAY_TIME_OF_THE_DAY | DISPLAY_TIME_OF_THE_DAY | Displays a time of the day widget in case of value `1` |
8586
| TASK_WEB_TWK_USE_FONT | TWK_USE_FONT | Font to be used. If not, browsers default fonts are used |
86-
| TASK_WEB_TWK_THEME | TWK_THEME | Defines the theme to be used (see "Themes") |
87+
| TASK_WEB_TWK_THEME | TWK_THEME | Defines the theme to be used (see "Themes") |
8788

8889
## Hooks
8990

@@ -114,17 +115,13 @@ That should be it! Now you have the server running at `localhost:3000` accessibl
114115

115116
### Troubleshooting
116117

117-
if you are receiving the following error in step 5
118-
118+
By default the log level is set to `INFO`. If a more detailed log is required, the application can be run with DEBUG or even TRACE messages.
119+
For debug messages, just set the environment "RUST_LOG" to "DEBUG":
119120
```shell
120-
121-
thread 'main' panicked at build.rs:7:19:
122-
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }
123-
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
124-
121+
env RUST_LOG="DEBUG" cargo run
125122
```
126123

127-
It's because, `tailwindcss-cli` is missing
124+
If a fine granular configuration is desired - the application log itself is captured with the name `taskwarrior_web`.
128125

129126
## Customizing
130127

@@ -219,17 +216,63 @@ Keyboard shortcut is `u`
219216
This will bring up undo confirmation dialog
220217
![Undo](./screenshots/undo.png)
221218

219+
## Custom queries
220+
221+
Task organization is a pretty personal thing. And depending on the project or individual base, custom workflows and reportings are required.
222+
Create a configuration file under Linux in `$HOME/.config/taskwarrior-web/config.toml` or under Windows in `%APPDATA%\taskwarrior-web\config.toml` and add custom queries.
223+
224+
A configuration file can look like:
225+
226+
```toml
227+
[custom_queries]
228+
229+
[custom_queries.completed_last_week]
230+
query = "end.after:today-1wk and status:completed"
231+
description = "completed last 7days"
232+
233+
[custom_queries.due_today]
234+
query = "due:today"
235+
description = "to be done today"
236+
fixed_key = "ni" # this will override randomly generated key
237+
```
238+
239+
Following options for each query definition is available:
240+
| property | mandatory | meaning |
241+
| ----------- | --------- | ---------------------------------------------------------------------- |
242+
| query | X | specifies the query to be executed on `taskwarrior`. |
243+
| description | X | description to be shown in the Web-UI for recognizing the right query. |
244+
| fixed_key | | Can be specified as two characters which will hardcode the shortcut. |
245+
246+
The query can be selected via keyboard shortcuts or via click on the right buttons.
247+
In order to select custom queries with the keyboard, first type in `q` as key for queries.
248+
A list is shown with available custom queries:
249+
![Custom query selections](./screenshots/custom_queries_selection.png)
250+
251+
On each custom query, either a pre-defined shortcut key is shown or an automatic and cached shortcut is shown.
252+
The right one is typed and automatically the custom query is set:
253+
254+
![Custom query list](./screenshots/custom_queries_list.png)
255+
256+
As soon as one of the other reports like `next`, `pending` or others are selected, the custom query is unset and `taskwarrior-web` standard reports are shown.
257+
258+
Beside of a configuration file, it is possible to configure via environment variables as well:
259+
```shell
260+
env TWK_custom_queries__one_query__fixed_key=ni TWK_custom_queries__one_query__query="end.after:today-1wk and status:completed" TWK_custom_queries__one_query__description="completed last 7days" cargo run
261+
```
262+
263+
The same way it is possible to configure the docker container accordingly.
264+
222265
## Switch theme
223266

224267
It is possible to switch the theme, which is saved in local storage too.
225268

226269
For this following three symbols are used (left of the command bar):
227270

228-
| Symbol | Purpose |
229-
|--------|---------------------------------------|
230-
| | Auto Mode or forced mode from server |
231-
| | Dark mode |
232-
| 🌣 | Light mode |
271+
| Symbol | Purpose |
272+
| ------ | ------------------------------------ |
273+
| | Auto Mode or forced mode from server |
274+
| | Dark mode |
275+
| 🌣 | Light mode |
233276

234277
# WIP warning
235278

@@ -243,11 +286,11 @@ there will be errors, as no checks, and there may not be any error messages in c
243286
- [x] Hiding empty columns
244287
- [ ] Temporary highlight last modified row, if visible
245288
- [x] Make the mnemonics same for tags on refresh
246-
- [ ] Modification
247-
- [ ] Deleting
289+
- [x] Modification
290+
- [x] Deleting
248291
- [ ] Following Context
249292
- [ ] Error handling
250-
- [ ] Retaining input in case of error
293+
- [x] Retaining input in case of error
251294
- [ ] Finetune error handling
252295
- [ ] Add more tests
253296
- [ ] Convert to desktop app using Tauri

config.sample.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[custom_queries]
2+
3+
[custom_queries.one_query]
4+
description = "report of something"
5+
6+
[custom_queries.two_query]
7+
description = "report of another thing"
8+
fixed_key = "n" # this will override randomly generated key

docker/start.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ if [[ ! -f "$TASKRC" ]]; then
1717
fi
1818

1919
cd $HOME/bin
20-
exec ./taskwarrior-web
20+
exec ./taskwarrior-web &
21+
pid=$!
22+
trap 'kill -SIGTERM $pid; wait $pid' SIGTERM
23+
wait $pidh

frontend/src/main.ts

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function focusTextInput(event: KeyboardEvent | MouseEvent) {
2323
event.preventDefault()
2424
ss.focus();
2525
} else {
26-
document.getElementById('cmd-inp').focus();
26+
document.getElementById('cmd-inp')?.focus();
2727
}
2828
}
2929

@@ -34,11 +34,11 @@ window.handleTaskAnnotations = (event: KeyboardEvent | MouseEvent) => {
3434
}
3535
event.preventDefault();
3636
let annoSelector = document.getElementById('anno-inp');
37-
document.querySelector('#anno-inp').classList.toggle('hidden');
37+
document.querySelector('#anno-inp')?.classList.toggle('hidden');
3838
Array.from(document.querySelectorAll('.is-a-annotation')).forEach((value) => {
3939
value.classList.toggle('hidden');
4040
});
41-
if (annoSelector.checkVisibility()) {
41+
if (annoSelector?.checkVisibility()) {
4242
annoSelector.focus();
4343
}
4444
return false;
@@ -59,45 +59,66 @@ window.handleTaskAnnotationTrigger = (event: KeyboardEvent | MouseEvent) => {
5959

6060
hotkeys('esc', function (event, handler) {
6161
// Prevent the default refresh event under WINDOWS system
62-
if(event.target != document.getElementById('tag-inp')) {
62+
if(event.target != document.getElementById('tag-inp') &&
63+
event.target != document.getElementById('query-inp')) {
6364
console.log("not processing")
6465
return
6566
}
66-
event.preventDefault()
67-
let tag_selector = document.getElementById('cmd-inp')
68-
document.querySelector('#tags_map_drawer').classList.toggle('hidden')
69-
if (tag_selector.checkVisibility()) {
67+
event.preventDefault();
68+
let tag_selector = document.getElementById('cmd-inp');
69+
if (event.target == document.getElementById('tag-inp')) {
70+
document.querySelector('#tags_map_drawer')?.classList.toggle('hidden');
71+
} else if (event.target == document.getElementById('query-inp')) {
72+
document.querySelector('#querys_map_drawer')?.classList.toggle('hidden');
73+
}
74+
if (tag_selector?.checkVisibility()) {
7075
tag_selector.focus();
7176
}
7277
return false;
7378
});
7479

80+
hotkeys('ctrl+shift+K', function (event, handler) {
81+
// Prevent the default refresh event under WINDOWS system
82+
event.preventDefault();
83+
focusTextInput(event);
84+
return false;
85+
});
86+
7587
hotkeys('t', function (event, handler) {
7688
// Prevent the default refresh event under WINDOWS system
7789
if(event.target != document.getElementById('cmd-inp')) {
78-
console.log("not processing")
90+
console.debug("not processing")
7991
return
8092
}
8193
event.preventDefault()
82-
window['toggleTagPanel']();
83-
94+
window['togglePanel']('tag');
8495
});
8596

86-
hotkeys('ctrl+shift+K', function (event, handler) {
97+
hotkeys('q', function (event, handler) {
8798
// Prevent the default refresh event under WINDOWS system
88-
event.preventDefault();
89-
focusTextInput(event);
90-
return false;
99+
if(event.target != document.getElementById('cmd-inp')) {
100+
console.debug("not processing")
101+
return
102+
}
103+
event.preventDefault()
104+
window['togglePanel']('query');
91105
});
92106

93-
window['toggleTagPanel'] = () => {
94-
let tagSelector = document.getElementById('tag-inp')
95-
document.querySelector('#tags_map_drawer').classList.toggle('hidden')
96-
if (tagSelector.checkVisibility()) {
107+
window['togglePanel'] = (panelType: string) => {
108+
let tagSelector = document.getElementById(panelType + '-inp')
109+
document.querySelector('#' + panelType + 's_map_drawer')?.classList.toggle('hidden')
110+
if (tagSelector?.checkVisibility()) {
97111
tagSelector.focus();
98112
}
99113
return false;
100-
}
114+
};
115+
116+
window['processPanelShortcut'] = (event: KeyboardEvent, panelType: string) {
117+
const shortcut = event.target?.value;
118+
if (shortcut.length >= 2) {
119+
document.getElementById(panelType + "s_" + shortcut)?.click()
120+
};
121+
};
101122

102123
document.addEventListener('click', function (event) {
103124
let element = document.getElementsByTagName('html')[0];
@@ -154,6 +175,7 @@ document.addEventListener("DOMContentLoaded", function () {
154175
.padStart(2, "0");
155176
}, 1000
156177
)
178+
157179
let day_progress = setInterval(
158180
() => {
159181
const dd = document.getElementById('time_of_the_day');

frontend/templates/left_action_bar.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<div class="pl-2 pr-2 py-1.5 rounded-sm text-xs flex bg-base-100 gap-2 items-center flex-wrap">
22

33
<div class="join" id="tag_search_bar">
4-
<button class="btn btn-neutral btn-xs join-item" id="tag-selection-toggle" onclick="window['toggleTagPanel']()">
4+
<button class="btn btn-neutral btn-xs join-item" id="tag-selection-toggle" onclick="window['togglePanel']('tag')">
55
<span><span class="shortcut_key opacity-50">t</span>ags</span>
66
</button>
7+
<button class="btn btn-neutral btn-xs join-item" id="query-selection-toggle" onclick="window['togglePanel']('query')">
8+
<span><span class="shortcut_key opacity-50">q</span>ueries</span>
9+
</button>
710
<span class="btn btn-neutral btn-xs join-item" id="task_action_bar">
811
<button hx-get="task_action_bar" hx-target="#task_action_bar" hx-swap="outerHTML"
912
hx-trigger="click,keyup[key=='s'] from:#cmd-inp">ta<span class="shortcut_key opacity-50">s</span>k</button>

0 commit comments

Comments
 (0)