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(wip): include stopwatch activity in Activity view, hidden behind devmode toggle #368

Merged
merged 1 commit into from
Sep 8, 2022
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
5 changes: 5 additions & 0 deletions src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface BaseQueryParams {
categories: Category[];
filter_categories: string[][];
bid_browsers?: string[];
bid_stopwatch?: string;
return_variable_suffix?: string;
}

Expand Down Expand Up @@ -129,6 +130,10 @@ export function canonicalEvents(params: DesktopQueryParams | AndroidQueryParams)
isDesktopParams(params) && params.filter_afk
? 'events = filter_period_intersect(events, not_afk);'
: '',
params.bid_stopwatch
? `stopwatch_events = query_bucket("${params.bid_stopwatch}");
events = period_union(events, stopwatch_events);`
: '',
// Categorize
params.categories ? `events = categorize(events, ${categories_str});` : '',
// Filter out selected categories
Expand Down
23 changes: 23 additions & 0 deletions src/stores/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface QueryOptions {
timeperiod?: TimePeriod;
filter_afk?: boolean;
include_audible?: boolean;
include_stopwatch?: boolean;
filter_categories?: string[][];
dont_query_inactive?: boolean;
force?: boolean;
Expand Down Expand Up @@ -102,6 +103,10 @@ interface State {
available: boolean;
};

stopwatch: {
available: boolean;
};

query_options?: QueryOptions;

// Can't this be handled in bucketStore?
Expand All @@ -112,6 +117,7 @@ interface State {
editor: string[];
browser: string[];
android: string[];
stopwatch: string[];
};
}

Expand Down Expand Up @@ -161,6 +167,10 @@ export const useActivityStore = defineStore('activity', {
available: false,
},

stopwatch: {
available: false,
},

query_options: null,

buckets: {
Expand All @@ -170,6 +180,7 @@ export const useActivityStore = defineStore('activity', {
editor: [],
browser: [],
android: [],
stopwatch: [],
},
}),

Expand Down Expand Up @@ -317,6 +328,7 @@ export const useActivityStore = defineStore('activity', {
filter_categories,
filter_afk,
include_audible,
include_stopwatch,
}: QueryOptions) {
const periods = [timeperiodToStr(timeperiod)];
const categories = useCategoryStore().classes_for_query;
Expand All @@ -325,6 +337,10 @@ export const useActivityStore = defineStore('activity', {
bid_window: this.buckets.window[0],
bid_afk: this.buckets.afk[0],
bid_browsers: this.buckets.browser,
bid_stopwatch:
include_stopwatch && this.buckets.stopwatch.length > 0
? this.buckets.stopwatch[0]
: undefined,
filter_afk,
categories,
filter_categories,
Expand Down Expand Up @@ -364,6 +380,7 @@ export const useActivityStore = defineStore('activity', {
timeperiod,
filter_categories,
filter_afk,
include_stopwatch,
dontQueryInactive,
}: QueryOptions & { dontQueryInactive: boolean }) {
// TODO: Needs to be adapted for Android
Expand Down Expand Up @@ -429,6 +446,10 @@ export const useActivityStore = defineStore('activity', {
bid_afk: this.buckets.afk[0],
bid_window: this.buckets.window[0],
bid_browsers: this.buckets.browser,
bid_stopwatch:
include_stopwatch && this.buckets.stopwatch.length > 0
? this.buckets.stopwatch[0]
: undefined,
// bid_android: this.buckets.android,
categories,
filter_categories,
Expand Down Expand Up @@ -475,6 +496,7 @@ export const useActivityStore = defineStore('activity', {
this.editor.available = this.buckets.editor.length > 0;
this.android.available = this.buckets.android.length > 0;
this.category.available = this.window.available || this.android.available;
this.stopwatch.available = this.buckets.stopwatch.length > 0;
},

async get_buckets(this: State, { host }) {
Expand All @@ -485,6 +507,7 @@ export const useActivityStore = defineStore('activity', {
this.buckets.android = bucketsStore.bucketsAndroid(host);
this.buckets.browser = bucketsStore.bucketsBrowser(host);
this.buckets.editor = bucketsStore.bucketsEditor(host);
this.buckets.stopwatch = bucketsStore.bucketsStopwatch(host);

console.log('Available buckets: ', this.buckets);
this.buckets.loaded = true;
Expand Down
66 changes: 35 additions & 31 deletions src/stores/buckets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function select_buckets(
return _.map(
_.filter(
buckets,
bucket => (!type || bucket['type'] === type) && (!host || bucket['hostname'] == host)
bucket => (!type || bucket.type === type) && (!host || bucket.hostname == host)
),
bucket => bucket['id']
);
Expand All @@ -29,12 +29,12 @@ export const useBucketsStore = defineStore('buckets', {
getters: {
hosts(this: State): string[] {
// TODO: Include consideration of device_id UUID
return _.uniq(_.map(this.buckets, bucket => bucket['hostname']));
return _.uniq(_.map(this.buckets, bucket => bucket.hostname));
},
// Uses device_id instead of hostname
devices(this: State): string[] {
// TODO: Include consideration of device_id UUID
return _.uniq(_.map(this.buckets, bucket => bucket['device_id']));
return _.uniq(_.map(this.buckets, bucket => bucket.device_id));
},

available(): (hostname: string) => {
Expand All @@ -43,6 +43,7 @@ export const useBucketsStore = defineStore('buckets', {
editor: boolean;
android: boolean;
category: boolean;
stopwatch: boolean;
} {
// Returns a map of which kinds of buckets are available
//
Expand All @@ -60,51 +61,54 @@ export const useBucketsStore = defineStore('buckets', {
editor: this.bucketsEditor(hostname).length > 0,
android: androidAvail,
category: windowAvail || androidAvail,
stopwatch: this.bucketsStopwatch(hostname).length > 0,
};
};
},

// These should be considered low-level, and should be used sparingly.
bucketsAFK(this: State): (host: string) => string[] {
return host => select_buckets(this.buckets, { host, type: 'afkstatus' });
bucketsByType(
this: State
): (host: string, type: string, fallback_unknown_host?: boolean) => string[] {
return (host, type, fallback_unknown_host) => {
let buckets = select_buckets(this.buckets, { host, type });
if (fallback_unknown_host && buckets.length == 0) {
buckets = select_buckets(this.buckets, { host: 'unknown', type });
//console.log('fallback: ', buckets);
}
return buckets;
};
},
bucketsWindow(this: State): (host: string) => string[] {

// Convenience getters for bucketsByType
bucketsAFK(): (host: string) => string[] {
return host => this.bucketsByType(host, 'afkstatus');
},
bucketsWindow(): (host: string) => string[] {
return host =>
_.filter(
select_buckets(this.buckets, { host, type: 'currentwindow' }),
id => !id.startsWith('aw-watcher-android')
this.bucketsByType(host, 'currentwindow').filter(
(id: string) => !id.startsWith('aw-watcher-android')
);
},
bucketsAndroid(this: State): (host: string) => string[] {
bucketsAndroid(): (host: string) => string[] {
return host =>
_.filter(select_buckets(this.buckets, { host, type: 'currentwindow' }), id =>
this.bucketsByType(host, 'currentwindow').filter((id: string) =>
id.startsWith('aw-watcher-android')
);
},
bucketsEditor(this: State): (host: string) => string[] {
bucketsEditor(): (host: string) => string[] {
// fallback to a bucket with 'unknown' host, if one exists.
// TODO: This needs a fix so we can get rid of this workaround.
const type = 'app.editor.activity';
return (host: string) => {
const buckets = select_buckets(this.buckets, { host, type });
return buckets.length == 0
? select_buckets(this.buckets, { host: 'unknown', type })
: buckets;
};
return host => this.bucketsByType(host, 'app.editor.activity', true);
},
bucketsBrowser(this: State): (host: string) => string[] {
bucketsBrowser(): (host: string) => string[] {
// fallback to a bucket with 'unknown' host, if one exists.
// TODO: This needs a fix so we can get rid of this workaround.
const type = 'web.tab.current';
return (host: string) => {
const buckets = select_buckets(this.buckets, { host, type });
if (buckets.length > 0) {
return buckets;
} else {
console.log('fallback: ', select_buckets(this.buckets, { host: 'unknown', type }));
return select_buckets(this.buckets, { host: 'unknown', type });
}
};
return host => this.bucketsByType(host, 'web.tab.current', true);
},
bucketsStopwatch(): (host: string) => string[] {
// fallback to a bucket with 'unknown' host, if one exists.
// TODO: This needs a fix so we can get rid of this workaround.
return (host: string) => this.bucketsByType(host, 'general.stopwatch', true);
},

getBucket(this: State): (id: string) => IBucket {
Expand Down
1 change: 1 addition & 0 deletions src/util/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IEvent {
export interface IBucket {
id: string;
hostname: string;
device_id: string;
type: string;
data: Record<string, any>;
}
9 changes: 9 additions & 0 deletions src/views/activity/Activity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ div
icon#includeAudibleHelp(name="question-circle" style="opacity: 0.4")
b-tooltip(target="includeAudibleHelp" v-b-tooltip.hover title="If the active window is an audible browser tab, count as active. Requires a browser watcher.")

b-form-checkbox(v-if="devmode" v-model="include_stopwatch" size="sm")
// WIP: https://github.com/ActivityWatch/aw-webui/pull/368
| Include manually logged events (stopwatch)
br
| #[b Note:] WIP, breaks aw-server-rust badly. Only shown in devmode.

div.col-md-6.mt-2.mt-md-0
b-form-group(label="Show category" label-cols="5" label-cols-lg="4" style="font-size: 0.88em")
b-form-select(v-model="filter_category", :options="categoryStore.category_select(true)" size="sm")
Expand Down Expand Up @@ -189,12 +195,14 @@ export default {
showOptions: false,

include_audible: true,
include_stopwatch: false,
filter_afk: true,
new_view: {},
};
},
computed: {
...mapState(useViewsStore, ['views']),
...mapState(useSettingsStore, ['devmode']),

// number of filters currently set (different from defaults)
filters_set() {
Expand Down Expand Up @@ -396,6 +404,7 @@ export default {
force: force,
filter_afk: this.filter_afk,
include_audible: this.include_audible,
include_stopwatch: this.include_stopwatch,
filter_categories: this.filter_categories,
};
await this.activityStore.ensure_loaded(queryOptions);
Expand Down