Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: added category time to the timeline barchart
  • Loading branch information
ErikBjare committed Feb 22, 2021
1 parent f03e399 commit 86b8eab
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 102 deletions.
55 changes: 46 additions & 9 deletions src/components/SelectableVisualization.vue
Expand Up @@ -97,6 +97,7 @@ import { split_by_hour_into_data } from '~/util/transforms';
// TODO: Move this somewhere else
import { build_category_hierarchy } from '~/util/classes';
import { getColorFromCategory } from '~/util/color';
function pick_subname_as_name(c) {
c.name = c.subname;
Expand Down Expand Up @@ -229,15 +230,51 @@ export default {
}
},
datasets: function () {
// TODO: Move elsewhere
const data = split_by_hour_into_data(this.$store.state.activity.active.events);
return [
{
label: 'Total time',
backgroundColor: '#6699ff',
data,
},
];
const METHOD_CATEGORY = 'category';
const METHOD_ACTIVITY = 'activity';
const method = METHOD_CATEGORY;
if (method == METHOD_CATEGORY) {
const SEP = '>>>';
const data = this.$store.state.activity.category.by_hour;
if (data) {
const categories = new Set(
Object.values(data)
.map(result => {
return result.cat_events.map(e => e.data['$category'].join(SEP));
})
.flat()
);
const ds = [...categories].map(c_ => {
const c = this.$store.getters['categories/get_category'](c_.split(SEP));
if (c) {
return {
label: c.name.join(' > '),
backgroundColor: getColorFromCategory(c, this.$store.state.categories.classes),
data: Object.values(data).map(results => {
const cat = results.cat_events.find(e => _.isEqual(e.data['$category'], c.name));
if (cat) return Math.round((cat.duration / (60 * 60)) * 1000) / 1000;
else return null;
}),
};
} else {
console.log('missing c');
}
});
return ds;
} else {
return [];
}
} else if (method == METHOD_ACTIVITY) {
const data = split_by_hour_into_data(this.$store.state.activity.active.events);
return [
{
label: 'Total time',
backgroundColor: '#6699ff',
data,
},
];
}
return [];
},
date: function () {
let date = this.$store.state.activity.query_options.date;
Expand Down
10 changes: 10 additions & 0 deletions src/queries.ts
Expand Up @@ -256,6 +256,15 @@ export function editorActivityQuery(editorbuckets: string[]): string[] {
return q;
}

export function hourlyCategoryQuery(params: DesktopQueryParams) {
const q = `
${canonicalEvents(params)}
cat_events = sort_by_duration(merge_events_by_keys(events, ["$category"]));
RETURN = { "cat_events": cat_events };
`;
return querystr_to_array(q);
}

export function dailyActivityQuery(afkbucket: string): string[] {
afkbucket = escape_doublequote(afkbucket);
return [
Expand All @@ -276,6 +285,7 @@ export default {
fullDesktopQuery,
appQuery,
dailyActivityQuery,
hourlyCategoryQuery,
dailyActivityQueryAndroid,
editorActivityQuery,
};
143 changes: 52 additions & 91 deletions src/store/modules/activity.ts
Expand Up @@ -3,6 +3,7 @@ import { unitOfTime } from 'moment';
import * as _ from 'lodash';
import { map, filter, values, groupBy, sortBy, flow, reverse } from 'lodash/fp';

import { window_events } from '~/util/fakedata';
import queries from '~/queries';
import { getColorFromCategory } from '~/util/color';
import { loadClassesForQuery } from '~/util/classes';
Expand All @@ -13,8 +14,8 @@ interface TimePeriod {
length: [number, string];
}

function dateToTimeperiod(date: string): TimePeriod {
return { start: get_day_start_with_offset(date), length: [1, 'day'] };
function dateToTimeperiod(date: string, duration?: [number, string]): TimePeriod {
return { start: get_day_start_with_offset(date), length: duration || [1, 'day'] };
}

function timeperiodToStr(tp: TimePeriod): string {
Expand Down Expand Up @@ -62,6 +63,7 @@ const _state = {

category: {
available: false,
by_hour: [],
top: [],
},

Expand Down Expand Up @@ -104,6 +106,23 @@ function timeperiodsAroundTimeperiod(timeperiod: TimePeriod): TimePeriod[] {
return periods;
}

function timeperiodsHoursOfDay(timeperiod: TimePeriod): TimePeriod[] {
const periods = [];
const _length: [number, string] = [1, 'hour'];
for (let i = 0; i < 24; i++) {
const start = moment(timeperiod.start)
.add(i * _length[0], _length[1] as moment.unitOfTime.DurationConstructor)
.format();
periods.push({ start, length: _length });
}
// const periods = _.range(24).map(i => [TimePeriod(moment(i * 1 + dayOffset), [1, 'hour'])]);
return periods;
}

function timeperiodsStrsHoursOfDay(timeperiod: TimePeriod): string[] {
return timeperiodsHoursOfDay(timeperiod).map(timeperiodToStr);
}

function timeperiodStrsAroundTimeperiod(timeperiod: TimePeriod): string[] {
return timeperiodsAroundTimeperiod(timeperiod).map(timeperiodToStr);
}
Expand Down Expand Up @@ -142,6 +161,7 @@ const actions = {

if (state.window.available) {
await dispatch('query_desktop_full', query_options);
await dispatch('query_category_time_by_hour', query_options);
} else if (state.android.available) {
await dispatch('query_android', query_options);
} else {
Expand Down Expand Up @@ -263,6 +283,32 @@ const actions = {
commit('query_active_history_completed', { active_history });
},

async query_category_time_by_hour(
{ commit, state },
{ timeperiod, filterCategories, filterAFK }: QueryOptions
) {
// TODO: Only works for the 1 day timeperiod
// TODO: Needs to be adapted for Android
const periods = timeperiodsStrsHoursOfDay(timeperiod);
const classes = loadClassesForQuery();
const data = await this._vm.$aw.query(
periods,
// TODO: Clean up call, pass QueryParams in fullDesktopQuery as well
// TODO: Unify QueryOptions and QueryParams
queries.hourlyCategoryQuery({
bid_afk: state.buckets.afk[0],
bid_window: state.buckets.window[0],
bid_browsers: state.buckets.browser,
// bid_android: state.buckets.android,
classes: classes,
filter_afk: filterAFK,
filter_classes: filterCategories,
})
);
const category_time_by_hour = _.zipObject(periods, data);
commit('query_category_time_by_hour_completed', { category_time_by_hour });
},

async query_active_history_android({ commit, state }, { timeperiod }: QueryOptions) {
const periods = timeperiodStrsAroundTimeperiod(timeperiod).filter(tp_str => {
return !_.includes(state.active.history, tp_str);
Expand Down Expand Up @@ -317,95 +363,6 @@ const actions = {
// A function to load some demo data (for screenshots and stuff)
commit('start_loading', {});

const window_events = [
{
duration: 32.1 * 60,
data: {
app: 'Firefox',
title: 'ActivityWatch/activitywatch: Track how you spend your time - Mozilla Firefox',
url: 'https://github.com/ActivityWatch/activitywatch',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 14.6 * 60,
data: {
app: 'Firefox',
title: 'Inbox - Gmail - Mozilla Firefox',
url: 'https://mail.google.com',
$category: ['Comms', 'Email'],
},
},
{
duration: 0.2 * 60 * 60,
data: {
app: 'Firefox',
title: 'reddit: the front page of the internet - Mozilla Firefox',
url: 'https://reddit.com',
$category: ['Media', 'Social Media'],
},
},
{
duration: 0.2 * 60 * 60,
data: {
app: 'Firefox',
title: 'YouTube - Mozilla Firefox',
url: 'https://youtube.com',
$category: ['Media', 'Video'],
},
},
{
duration: 0.15 * 60 * 60,
data: {
app: 'Firefox',
title: 'Home / Twitter - Mozilla Firefox',
url: 'https://twitter.com',
$category: ['Media', 'Social Media'],
},
},
{
duration: 0.15 * 60 * 60,
data: {
app: 'Firefox',
title: 'Stack Overflow',
url: 'https://stackoverflow.com',
$category: ['Work', 'Programming'],
},
},
{
duration: 48.2 * 60,
data: {
app: 'Terminal',
title: 'vim ~/code/activitywatch/aw-server/aw-webui/src',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 12.6 * 60,
data: {
app: 'Terminal',
title: 'bash ~/code/activitywatch',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 58.1 * 60,
data: {
app: 'zoom',
title: 'Zoom Meeting',
$category: ['Comms', 'Video Conferencing'],
},
},
{
duration: 0.4 * 60 * 60,
data: { app: 'Minecraft', title: 'Minecraft', $category: ['Media', 'Games'] },
},
{
duration: 3.15 * 60,
data: { app: 'Spotify', title: 'Spotify', $category: ['Media', 'Music'] },
},
];

function groupSumEventsBy(events, key, f) {
return flow(
filter(f),
Expand Down Expand Up @@ -544,6 +501,10 @@ const mutations = {
};
},

query_category_time_by_hour_completed(state, { category_time_by_hour }) {
state.category.by_hour = category_time_by_hour;
},

buckets(state, data) {
state.buckets = data;
state.buckets.loaded = true;
Expand Down
88 changes: 88 additions & 0 deletions src/util/fakedata.js
@@ -0,0 +1,88 @@
export const window_events = [
{
duration: 32.1 * 60,
data: {
app: 'Firefox',
title: 'ActivityWatch/activitywatch: Track how you spend your time - Mozilla Firefox',
url: 'https://github.com/ActivityWatch/activitywatch',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 14.6 * 60,
data: {
app: 'Firefox',
title: 'Inbox - Gmail - Mozilla Firefox',
url: 'https://mail.google.com',
$category: ['Comms', 'Email'],
},
},
{
duration: 0.2 * 60 * 60,
data: {
app: 'Firefox',
title: 'reddit: the front page of the internet - Mozilla Firefox',
url: 'https://reddit.com',
$category: ['Media', 'Social Media'],
},
},
{
duration: 0.2 * 60 * 60,
data: {
app: 'Firefox',
title: 'YouTube - Mozilla Firefox',
url: 'https://youtube.com',
$category: ['Media', 'Video'],
},
},
{
duration: 0.15 * 60 * 60,
data: {
app: 'Firefox',
title: 'Home / Twitter - Mozilla Firefox',
url: 'https://twitter.com',
$category: ['Media', 'Social Media'],
},
},
{
duration: 0.15 * 60 * 60,
data: {
app: 'Firefox',
title: 'Stack Overflow',
url: 'https://stackoverflow.com',
$category: ['Work', 'Programming'],
},
},
{
duration: 48.2 * 60,
data: {
app: 'Terminal',
title: 'vim ~/code/activitywatch/aw-server/aw-webui/src',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 12.6 * 60,
data: {
app: 'Terminal',
title: 'bash ~/code/activitywatch',
$category: ['Work', 'Programming', 'ActivityWatch'],
},
},
{
duration: 58.1 * 60,
data: {
app: 'zoom',
title: 'Zoom Meeting',
$category: ['Comms', 'Video Conferencing'],
},
},
{
duration: 0.4 * 60 * 60,
data: { app: 'Minecraft', title: 'Minecraft', $category: ['Media', 'Games'] },
},
{
duration: 3.15 * 60,
data: { app: 'Spotify', title: 'Spotify', $category: ['Media', 'Music'] },
},
];
8 changes: 8 additions & 0 deletions src/util/time.js
Expand Up @@ -32,6 +32,14 @@ export function get_day_start_with_offset(dateParam) {
return dateMoment.hour(start_of_day_hours).minute(start_of_day_minutes).format();
}

// Return the startOfDay offset as a number of hours
export function get_hour_offset() {
const start_of_day = localStorage.startOfDay;
const start_of_day_hours = parseInt(start_of_day.split(':')[0]);
const start_of_day_minutes = parseInt(start_of_day.split(':')[1]);
return start_of_day_hours + start_of_day_minutes / 60;
}

export function get_day_end_with_offset(date) {
return moment(get_day_start_with_offset(date)).add(1, 'days').format();
}
Expand Down

0 comments on commit 86b8eab

Please sign in to comment.