Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: progress on audible-as-active #262

Merged
merged 3 commits into from
Feb 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@typescript-eslint/explicit-function-return-type": ["off"],
"@typescript-eslint/no-var-requires": ["off"],
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-use-before-define": "warn",
"@typescript-eslint/no-use-before-define": ["error", {"functions": false, "classes": false}],
"@typescript-eslint/no-unused-vars": ["warn", {"argsIgnorePattern": "^_"}],
"@typescript-eslint/no-this-alias": [
"warn",
Expand Down
67 changes: 39 additions & 28 deletions src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@ interface BaseQueryParams {
include_audible?: boolean;
classes: [string[], Rule][];
filter_classes: string[][];
bid_browsers?: string[];
}

interface DesktopQueryParams extends BaseQueryParams {
bid_window: string;
bid_afk: string;
filter_afk: boolean;
bid_browsers?: string[];
}

interface AndroidQueryParams extends BaseQueryParams {
bid_android: string;
bid_browsers?: string[];
}

function isDesktopParams(object: any): object is DesktopQueryParams {
Expand All @@ -54,30 +53,39 @@ export function canonicalEvents(params: DesktopQueryParams | AndroidQueryParams)
// Needs escaping for regex patterns like '\w' to work (JSON.stringify adds extra unecessary escaping)
const classes_str = JSON.stringify(params.classes).replace(/\\\\/g, '\\');
const cat_filter_str = JSON.stringify(params.filter_classes);
const bid_window = isDesktopParams(params) ? params.bid_window : params.bid_android;

return `
events = flood(query_bucket("${bid_window}"));
${
isDesktopParams(params)
? `not_afk = flood(query_bucket("${params.bid_afk}"));
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);`
: ''
}
${isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app"]);' : ''}
// For simplicity, we assume that bid_window and bid_android are exchangeable (note however it needs special treatment)
const bid_window = isDesktopParams(params) ? params.bid_window : params.bid_android;

${
isDesktopParams(params) && params.filter_afk
? 'events = filter_period_intersect(events, not_afk);'
: ''
}
${params.classes ? `events = categorize(events, ${classes_str});` : ''}
${
params.filter_classes
? `events = filter_keyvals(events, "$category", ${cat_filter_str});`
: ''
}
`;
return [
// Fetch window/app events
`events = flood(query_bucket("${bid_window}"));`,
// On Android, merge events to avoid overload of events
isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app"]);' : '',
// Fetch not-afk events
isDesktopParams(params)
? `not_afk = flood(query_bucket("${params.bid_afk}"));
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);`
: '',
// Fetch browser events
params.bid_browsers
? isDesktopParams(params) &&
browserEvents(params) +
// Include focused and audible browser events as indications of not-afk
(params.include_audible
? `audible_events = filter_keyvals(browser_events, "audible", [true]);
not_afk = period_union(not_afk, audible_events);`
: '')
: '',
// Filter out window events when the user was afk
isDesktopParams(params) && params.filter_afk
? 'events = filter_period_intersect(events, not_afk);'
: '',
// Categorize
params.classes ? `events = categorize(events, ${classes_str});` : '',
// Filter out selected categories
params.filter_classes ? `events = filter_keyvals(events, "$category", ${cat_filter_str});` : '',
].join('\n');
}

const default_limit = 100; // Hardcoded limit per group
Expand Down Expand Up @@ -171,7 +179,8 @@ function browserEvents(params: DesktopQueryParams): string {
window_${browserName} = filter_keyvals(events, "app", ${browser_appnames_str});
events_${browserName} = filter_period_intersect(events_${browserName}, window_${browserName});
events_${browserName} = split_url_events(events_${browserName});
browser_events = sort_by_timestamp(concat(browser_events, events_${browserName}));`;
browser_events = concat(browser_events, events_${browserName});
browser_events = sort_by_timestamp(browser_events);`;
});
return code;
}
Expand All @@ -182,7 +191,8 @@ export function fullDesktopQuery(
afkbucket: string,
filterAFK = true,
classes,
filterCategories: string[][]
filterCategories: string[][],
include_audible: boolean
): string[] {
// Escape `"`
browserbuckets = _.map(browserbuckets, escape_doublequote);
Expand All @@ -197,6 +207,7 @@ export function fullDesktopQuery(
classes: classes,
filter_classes: filterCategories,
filter_afk: filterAFK,
include_audible,
};

return querystr_to_array(
Expand All @@ -209,8 +220,8 @@ export function fullDesktopQuery(
app_events = limit_events(app_events, ${default_limit});
title_events = limit_events(title_events, ${default_limit});
duration = sum_durations(events);

${browserEvents(params)}
` + // Browser events are retrieved in canonicalQuery
`
browser_events = split_url_events(browser_events);
browser_urls = merge_events_by_keys(browser_events, ["url"]);
browser_urls = sort_by_duration(browser_urls);
Expand Down
6 changes: 4 additions & 2 deletions src/store/modules/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface QueryOptions {
date?: string;
timeperiod?: TimePeriod;
filterAFK?: boolean;
includeAudible?: boolean;
filterCategories?: string[][];
force?: boolean;
}
Expand Down Expand Up @@ -215,7 +216,7 @@ const actions = {

async query_desktop_full(
{ state, commit, rootState, rootGetters },
{ timeperiod, filterCategories, filterAFK }: QueryOptions
{ timeperiod, filterCategories, filterAFK, includeAudible }: QueryOptions
) {
const periods = [timeperiodToStr(timeperiod)];
const classes = loadClassesForQuery();
Expand All @@ -225,7 +226,8 @@ const actions = {
state.buckets.afk[0],
filterAFK,
classes,
filterCategories
filterCategories,
includeAudible
);
const data = await this._vm.$aw.query(periods, q);

Expand Down
21 changes: 17 additions & 4 deletions src/views/activity/Activity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ div
b-form-group(label="Show/filter category" label-cols="5" label-cols-lg="4")
b-form-select(v-model="filterCategory", :options="categories")

div.row
div.col-md-12
b-form-checkbox(v-model="filterAFK")
| Filter AFK
div.col-md-12
b-form-checkbox(v-model="includeAudible")
| Count audible browser tab as active

aw-devonly
b-btn(id="load-demo", @click="load_demo")
| Load demo data
Expand Down Expand Up @@ -143,6 +151,8 @@ export default {
return {
today: get_today(),
filterCategory: null,
includeAudible: true,
filterAFK: true,
new_view: {},
};
},
Expand All @@ -161,9 +171,11 @@ export default {
},
categories: function () {
const cats = this.$store.getters['categories/all_categories'];
const entries = cats.map(c => {
return { text: c.join(' > '), value: c };
});
const entries = cats
.map(c => {
return { text: c.join(' > '), value: c };
})
.sort((a, b) => a.text > b.text);
return [
{ text: 'All', value: null },
{ text: 'Uncategorized', value: ['Uncategorized'] },
Expand Down Expand Up @@ -262,7 +274,8 @@ export default {
timeperiod: this.timeperiod,
host: this.host,
force: force,
filterAFK: true,
filterAFK: this.filterAFK,
includeAudible: this.includeAudible,
filterCategories: this.filterCategories,
});
},
Expand Down