aw-webui icon indicating copy to clipboard operation
aw-webui copied to clipboard

Implemented tagging in stopwatch

Open nicolae-stroncea opened this issue 4 years ago • 11 comments

This is the updated PR for: https://github.com/ActivityWatch/aw-webui/pull/161

Created a new one cause the old commit history was too messy to fix and rebase.

From old PR:

User can write a list of tags for his stopwatch event that will be automatically stored inside the database. This functionality is useful for data-analysis, where you might want to view your stopwatch events by different tags: study, work, etc.

nicolae-stroncea avatar Jul 01 '20 16:07 nicolae-stroncea

Introduced couple of changes:

  • List of tags now stored as string of tags in database. e.g: event.data.tags = "this is tag 1,tag2,this-is-3"(no spaces between commas). This makes the logic much simpler since you don't have to convert between a list (the way it was previously) to a string every time when showing the user his tags, and makes the code cleaner since tags is only ever one type(string).
  • Now fully compatible with past events: You can click "Start New" on a past event and if past event:
    • Has tags, new event inherits the same tags, which is the desired behaviour
    • Doesn't have tags(old version), then new event still has the field for tags, where you can insert your tags
  • Unintended pleasant surprise: It is possible to give tags to events that were created in versions w/o the tags. Select to edit past event, check the running box to true, and click 'save'. Event will then be in the Running category. You will then be able to add tags to it, then untick the running box and click save (all other properties, including start time and end time will remain unchanged). Majority of people will not use this behaviour, but if somebody wants to they can. Making it any easier than this would likely require subclassing/editing EventEditor so that is shows the tags field even if it doesn't exist. Not sure if it's worth the effort or added complexity.

Currently, you can add tags to an event only by editing it(in the modal box), so many users may not be aware of the feature + it requires an extra click. It would be trivial to add an input field for tags next to the label one, so you can write both the Label and the tags when starting a new event. I can add that in, if you think that's a good idea.

Could look something like this:

image

Tested following cases (which I think covers all interactions):

  1. Creating new event from start and added ags/edited tags
  2. Creating event from previous event with tags(will have same tags)
  3. Creating event from prev event without tags.(can add tags to new event)
  4. Editing tags for finished event

nicolae-stroncea avatar Jul 03 '20 03:07 nicolae-stroncea

@ErikBjare I had some more time to think about this, and thought of another possible implementation:

  • Store tags in the key-value table, where event names are keys, and the tag list will be corresponding value.
  • When a user starts a new activity, instead of typing in the name, they can select the name from a dropdown, where the tags will be level 1 categories, and names will be children. As an example: "Work(tag) -> Code(name), Work -> Client meeting, Work -> team meeting

Advantages:

  • Tags are not stored with events, therefore not duplicated
  • All events which have the same name, automatically inherit the same tags, even if they were created before tags were implemented.

Disadvantages:

  • Can't think of any of the top of my mind. Might be more complex though, requiring new API routes to the key-value table. Would also only become available once aw-server-rust + sqlite become the default (not really a disadvantage, but would increase time till feature deployed)

I think functionality wise, it would be the same, and a similar dropdown could be implemented using current approach(by looping through all events, and building the dropdown)

nicolae-stroncea avatar Jul 17 '20 01:07 nicolae-stroncea

I'd rather implement a solid, simple, solution that solves 80% of the problem (like what's already in the PR) than try to engineer a perfect solution that takes 10x as long to implement and maintain.

I agree there needs to be a way to make this work well with categories, but I don't think creating a tags key-value table is the right way. Tags should be stored with events imo, otherwise they are lost on bucket export (they could be stored in bucket.data instead of the global key-value store, once we've moved to aw-server-rust where that is supported).

requiring new API routes to the key-value table

There is already an API for this in aw-server-rust, so that isn't really an issue.

When a user starts a new activity, instead of typing in the name, they can select the name from a dropdown

I like this idea (it's how Toggl works), but we could just simply check the most recent tags and list them.

Maybe @johan-bjareholt could give his 2¢?

ErikBjare avatar Jul 17 '20 09:07 ErikBjare

Tags definitely should be saved in events, I think the question should rather be if we want to store favorite tags or something like that.

Whether they should be connected to actual categories or not I'm not sure. Need to think about that a little more. If we do that maybe we could save metadata about a tag in the key/value store (like that the tag "meeting" can be classified as the category "Work -> Meeting -> Physical Meeting" or something?). Then we can add a query transform that simply does that mapping. Because we probably want the same settings for all tags of the same name so the only other option would be to replace all existing events which is probably not a good idea?

When a user starts a new activity, instead of typing in the name, they can select the name from a dropdown

I like this idea (it's how Toggl works), but we could just simply check the most recent tags and list them.

I think both could be useful, we might suggest both the most recent tags as well as be able to pin/favorite a tag (the former not needing key-value and the latter requiring it).

Both are valuable features in different ways, most recent gives a quick and automatic way to recommend a tag while the favorite/pin would be manual but reliable. I guess it's a matter of taste whether we should use the first, second or both.

johan-bjareholt avatar Jul 17 '20 19:07 johan-bjareholt

@ErikBjare @johan-bjareholt here's how I'm thinking a dropdown might work: dropdown will show events in alphabetical order, with top being "Add new Event". When you select an event, it will also selects the most recent tags for the specific event.

Because users now have to fill out an extra field, to minimize user effort and time spent choosing, we should ideally have some mechanism which automatically adds the right tags for the event that you choose, minimizing errors. This is especially important if you use the stopwatch feature often. I think picking most recent tags for that event is a good heuristic for that.

Doesn't have to be a dropdown just something which automatically tags events for you.

EDIT: Another option would be to have a new view: Choose from Past Events, above History, where we show a list of unique event names you've created so far, with a heuristic for their tags (most recent tags/most popular tags/etc). This view would be pretty similar to the History view except for no duplicates and different sort mechanism. Currently History view is great for replaying past events if you have only a couple, and don't use the stopwatch often. I use the stopwatch multiple times daily, and searching for an event that I did last week can lead to a lot of scrolling sometimes.

nicolae-stroncea avatar Jul 18 '20 14:07 nicolae-stroncea

This is on a slight side note, but should this be removed: This is an early experiment, an important missing feature is the ability to set start/end times manually.? It looks like it is already implemented. I can add it in one of the commits

nicolae-stroncea avatar Jul 18 '20 16:07 nicolae-stroncea

I played around with it and added a dropdown. I also moved the Start button on the new line, to better accomodate narrow width devices.

image

When you select an item from the dropdown, it will automatically fill in the tags with most recent tags for that event.

image

If you change the tags from the default, it will create this event with the new tags, but won't change any past events, which is the intended behaviour.

Mobile view:

image

nicolae-stroncea avatar Jul 19 '20 02:07 nicolae-stroncea

This is on a slight side note, but should this be removed: This is an early experiment, an important missing feature is the ability to set start/end times manually.? It looks like it is already implemented. I can add it in one of the commits

Yes this can be removed.

There's still a few things which I'm kind of confused about. For example, if a single task can have multiple tags will it in the future be possible to have multiple categories on a single event? That will not work as it's only possible to have a single category on a single event today. If we made it possible to have multiple categories on a single event that would also become confusing because then the sum of all categories could be more than the total amount of events.

Sorry for being a bit picky, but I'm a bit afraid of doing the data structure of this wrong because if we do and want to change it in the future we need to write some kind of migration which will be a lot of work. It's less work to get it right from the start.

The UI looks really good, but I don't think it's clear to the user how to specify multiple tags.

EDIT: It would work though if only the task (but not the tags) can be assigned to a category.

johan-bjareholt avatar Jul 19 '20 18:07 johan-bjareholt

@johan-bjareholt assigning the task (instead of the tags) to a category makes sense. Would that information be stored similar to how the categories in the settings will be stored?

nicolae-stroncea avatar Jul 19 '20 18:07 nicolae-stroncea

@johan-bjareholt assigning the task (instead of the tags) to a category makes sense. Would that information be stored similar to how the categories in the settings will be stored?

I don't know how that would be stored, it will be very hard to get working nicely because it would create dependencies between the bucket and the categories (and the categories can be removed at any time, so the category might break). I think we should postpone that idea.

I also realized something else from earlier:

  • List of tags now stored as string of tags in database. e.g: event.data.tags = "this is tag 1,tag2,this-is-3"(no spaces between commas). This makes the logic much simpler since you don't have to convert between a list (the way it was previously) to a string every time when showing the user his tags, and makes the code cleaner since tags is only ever one type(string).

While the implementation is simpler, the data format is less portable. If we want to for example want to do summaries of these tags later in the query language for the web-ui (or any 3rd party visualizer for that matter) we would have to parse this tag specific format instead of just using lists which are a part of the JSON format already. By parsing the tags at the input level means that you only need to parse it at one place, parsing it after the input level means that every other consumer needs to parse that data which can likely become more than just one.

johan-bjareholt avatar Jul 19 '20 20:07 johan-bjareholt

Re categorization: I assumed we'd deal with the stopwatch events like any other events. Let them be categorized by rules like everything else. Categories should not be stored with/assigned to events.

By parsing the tags at the input level means that you only need to parse it at one place, parsing it after the input level means that every other consumer needs to parse that data which can likely become more than just one.

I agree with this. I don't like the idea of storing lists as a comma-separated string.

ErikBjare avatar Jul 20 '20 07:07 ErikBjare