diff --git a/src/components/Header.vue b/src/components/Header.vue
index da12744f..f182dbaf 100644
--- a/src/components/Header.vue
+++ b/src/components/Header.vue
@@ -77,28 +77,24 @@ import 'vue-awesome/icons/desktop';
import _ from 'lodash';
-// Set this to true to test Android behavior when on a desktop
-const testingAndroid = false;
-
export default {
name: 'Header',
data() {
return {
activityViews: [],
- isAndroidApp:
- testingAndroid ||
- (navigator.userAgent.includes('Android') && navigator.userAgent.includes('wv')), // Checks for Android and WebView
};
},
mounted: async function() {
const buckets = await this.$aw.getBuckets();
const types_by_host = {};
+
+ // TODO: Change to use same bucket detection logic as get_buckets/set_available in store/modules/activity.ts
_.each(buckets, v => {
types_by_host[v.hostname] = types_by_host[v.hostname] || {};
// The '&& true;' is just to typecoerce into booleans
types_by_host[v.hostname].afk |= v.type == 'afkstatus';
types_by_host[v.hostname].window |= v.type == 'currentwindow';
- types_by_host[v.hostname].android |= v.type == 'currentwindow' && this.isAndroidApp; // Use other bucket type ID in the future
+ types_by_host[v.hostname].android |= v.type == 'currentwindow' && v.id.includes('android'); // Use other bucket type ID in the future
});
//console.log(types_by_host);
@@ -112,12 +108,12 @@ export default {
icon: 'desktop',
});
}
- if (testingAndroid || types.android) {
+ if (types.android) {
this.activityViews.push({
name: `${hostname} (Android)`,
hostname: hostname,
type: 'android',
- pathUrl: '/activity/android',
+ pathUrl: `/activity/${hostname}`,
icon: 'mobile',
});
}
diff --git a/src/components/SelectableVisualization.vue b/src/components/SelectableVisualization.vue
index 182d5e4e..9ea8e056 100644
--- a/src/components/SelectableVisualization.vue
+++ b/src/components/SelectableVisualization.vue
@@ -1,23 +1,30 @@
div
- h5 {{ type_title }}
+ h5 {{ visualizations[type].title }}
+ div
+ b-dropdown.vis-style-dropdown-btn(size="sm" variant="outline-secondary")
+ template(v-slot:button-content)
+ icon(name="cog")
+ b-dropdown-item(v-for="t in types" :key="t" variant="outline-secondary" @click="$emit('onTypeChange', id, t)" v-bind:disabled="!visualizations[t].available")
+ | {{ visualizations[t].title }}
+
div(v-if="type == 'top_apps'")
- aw-summary(:fields="top_apps",
+ aw-summary(:fields="$store.state.activity.window.top_apps",
:namefunc="e => e.data.app",
:colorfunc="e => e.data.app",
with_limit)
div(v-if="type == 'top_titles'")
- aw-summary(:fields="top_titles",
+ aw-summary(:fields="$store.state.activity.window.top_titles",
:namefunc="e => e.data.title",
:colorfunc="e => e.data.app",
with_limit)
div(v-if="type == 'top_domains'")
- aw-summary(:fields="top_domains",
+ aw-summary(:fields="$store.state.activity.browser.top_domains",
:namefunc="e => e.data.$domain",
:colorfunc="e => e.data.$domain",
with_limit)
div(v-if="type == 'top_urls'")
- aw-summary(:fields="top_urls",
+ aw-summary(:fields="$store.state.activity.browser.top_urls",
:namefunc="e => e.data.url",
:colorfunc="e => e.data.$domain",
with_limit)
@@ -37,29 +44,26 @@ div
:colorfunc="e => e.data.language",
with_limit)
div(v-if="type == 'top_categories'")
- aw-summary(:fields="top_categories",
+ aw-summary(:fields="$store.state.activity.category.top",
:namefunc="e => e.data['$category'].join(' > ')",
:colorfunc="e => e.data['$category'].join(' > ')",
with_limit)
div(v-if="type == 'category_tree'")
- aw-categorytree(:events="top_categories")
+ aw-categorytree(:events="$store.state.activity.category.top")
div(v-if="type == 'category_sunburst'")
aw-sunburst-categories(:data="top_categories_hierarchy", style="height: 20em")
- b-dropdown.vis-style-dropdown-btn(size="sm" variant="outline-secondary")
- template(v-slot:button-content)
- icon(name="cog")
- b-dropdown-item(v-for="t in types" :key="t" variant="outline-secondary" @click="$emit('onTypeChange', id, t)" v-bind:disabled="!get_type_available(t)")
- | {{ get_type_title(t) }}
-
@@ -109,24 +113,56 @@ export default {
};
},
computed: {
- top_apps: function() {
- return this.$store.state.activity.window.top_apps;
- },
- top_titles: function() {
- return this.$store.state.activity.window.top_titles;
- },
- top_domains: function() {
- return this.$store.state.activity.browser.top_domains;
- },
- top_urls: function() {
- return this.$store.state.activity.browser.top_urls;
- },
- top_categories: function() {
- return this.$store.state.activity.category.top;
+ visualizations: function() {
+ return {
+ top_apps: {
+ title: 'Top Applications',
+ available:
+ this.$store.state.activity.window.available ||
+ this.$store.state.activity.android.available,
+ },
+ top_titles: {
+ title: 'Top Window Titles',
+ available: this.$store.state.activity.window.available,
+ },
+ top_domains: {
+ title: 'Top Browser Domains',
+ available: this.$store.state.activity.browser.available,
+ },
+ top_urls: {
+ title: 'Top Browser URLs',
+ available: this.$store.state.activity.browser.available,
+ },
+ top_editor_files: {
+ title: 'Top Editor Files',
+ available: this.$store.state.activity.editor.available,
+ },
+ top_editor_languages: {
+ title: 'Top Editor Languages',
+ available: this.$store.state.activity.editor.available,
+ },
+ top_editor_projects: {
+ title: 'Top Editor Projects',
+ available: this.$store.state.activity.editor.available,
+ },
+ top_categories: {
+ title: 'Top Categories',
+ available: this.$store.state.activity.category.available,
+ },
+ category_tree: {
+ title: 'Category Tree',
+ available: this.$store.state.activity.category.available,
+ },
+ category_sunburst: {
+ title: 'Category Sunburst',
+ available: this.$store.state.activity.category.available,
+ },
+ };
},
top_categories_hierarchy: function() {
- if (this.top_categories) {
- const categories = this.top_categories.map(c => {
+ const top_categories = this.$store.state.activity.category.top;
+ if (top_categories) {
+ const categories = top_categories.map(c => {
return { name: c.data.$category, size: c.duration };
});
@@ -138,59 +174,6 @@ export default {
return null;
}
},
- type_title: function() {
- return this.get_type_title(this.type);
- },
- },
- methods: {
- get_type_available: function(type) {
- if (type === 'top_apps' || type === 'top_titles') {
- return this.$store.state.activity.window.available;
- } else if (type === 'top_domains' || type === 'top_urls') {
- return this.$store.state.activity.browser.available;
- } else if (
- type === 'top_editor_files' ||
- type === 'top_editor_languages' ||
- type === 'top_editor_projects'
- ) {
- return this.$store.state.activity.editor.available;
- } else if (
- type === 'top_categories' ||
- type === 'category_tree' ||
- type === 'category_sunburst'
- ) {
- return this.$store.state.activity.category.available;
- } else {
- console.error('Unknown type available: ', type);
- return false;
- }
- },
- get_type_title: function(type) {
- if (type === 'top_apps') {
- return 'Top Applications';
- } else if (type === 'top_titles') {
- return 'Top Window Titles';
- } else if (type === 'top_domains') {
- return 'Top Browser Domains';
- } else if (type === 'top_urls') {
- return 'Top Browser URLs';
- } else if (type === 'top_editor_files') {
- return 'Top Editor Files';
- } else if (type === 'top_editor_languages') {
- return 'Top Editor Languages';
- } else if (type === 'top_editor_projects') {
- return 'Top Editor Projects';
- } else if (type === 'top_categories') {
- return 'Top Categories';
- } else if (type === 'category_tree') {
- return 'Category Tree';
- } else if (type === 'category_sunburst') {
- return 'Category Sunburst';
- } else {
- console.error('Unknown type: ', type);
- return 'Unknown';
- }
- },
},
};
diff --git a/src/main.js b/src/main.js
index 49c13a38..197459b5 100644
--- a/src/main.js
+++ b/src/main.js
@@ -23,6 +23,11 @@ import 'typeface-varela-round';
// Loads all the filters
import './util/filters.js';
+// Create an instance of AWClient as this.$aw
+import awclient from './util/awclient.js';
+console.log(awclient);
+Vue.prototype.$aw = awclient;
+
// Sets up the routing and the base app (using vue-router)
import router from './route.js';
@@ -54,10 +59,6 @@ Vue.component('aw-timeline-barchart', () => import('./visualizations/TimelineBar
// A mixin to make async method errors propagate
Vue.mixin(require('~/mixins/asyncErrorCaptured.js'));
-// Create an instance of AWClient as this.$aw
-import awclient from './util/awclient.js';
-Vue.prototype.$aw = awclient;
-
// Set the PRODUCTION constant
Vue.prototype.PRODUCTION = PRODUCTION;
diff --git a/src/queries.ts b/src/queries.ts
index 20c319f7..add41564 100644
--- a/src/queries.ts
+++ b/src/queries.ts
@@ -9,18 +9,26 @@ function querystr_to_array(querystr: string): string[] {
.map(l => l + ';');
}
-interface QueryParams {
- bid_window: string;
- bid_afk: string;
- bid_browsers?: string[];
+interface BaseQueryParams {
filter_afk: boolean;
include_audible?: boolean;
classes: Record;
}
+interface DesktopQueryParams extends BaseQueryParams {
+ bid_window: string;
+ bid_afk: string;
+ bid_browsers?: string[];
+}
+
+interface AndroidQueryParams extends BaseQueryParams {
+ bid_android: string;
+ bid_browsers?: string[];
+}
+
// Constructs a query that returns a fully-detailed list of events from the merging of several sources (window, afk, web).
// Puts it's results in `not_afk` and `events`.
-function canonicalEvents(params: QueryParams): string {
+function canonicalEvents(params: DesktopQueryParams): string {
return `
events = flood(query_bucket("${params.bid_window}"));
not_afk = flood(query_bucket("${params.bid_afk}"));
@@ -29,18 +37,18 @@ function canonicalEvents(params: QueryParams): string {
`;
}
+const default_limit = 100; // Hardcoded limit per group
+
export function windowQuery(
windowbucket,
afkbucket,
- appcount,
- titlecount,
filterAFK,
classes,
filterCategories: string[][]
): string[] {
windowbucket = windowbucket.replace('"', '\\"');
afkbucket = afkbucket.replace('"', '\\"');
- const params: QueryParams = {
+ const params: DesktopQueryParams = {
bid_window: windowbucket,
bid_afk: afkbucket,
classes: classes,
@@ -60,22 +68,34 @@ export function windowQuery(
cat_events = sort_by_duration(merge_events_by_keys(events, ["$category"]));
events = sort_by_timestamp(events);
- app_events = limit_events(app_events, ${appcount});
- title_events = limit_events(title_events, ${titlecount});
+ app_events = limit_events(app_events, ${default_limit});
+ title_events = limit_events(title_events, ${default_limit});
duration = sum_durations(events);
RETURN = {"app_events": app_events, "title_events": title_events, "cat_events": cat_events, "duration": duration, "active_events": not_afk};`;
return querystr_to_array(code);
}
-export function appQuery(appbucket: string, limit = 5): string[] {
+export function appQuery(appbucket: string, classes, filterAFK): string[] {
appbucket = appbucket.replace('"', '\\"');
+ const params: AndroidQueryParams = {
+ bid_android: appbucket,
+ classes: classes,
+ filter_afk: filterAFK,
+ };
const code = `
- events = query_bucket("${appbucket}");
- events = merge_events_by_keys(events, ["app"]);
- events = sort_by_duration(events);
- events = limit_events(events, ${limit});
- total_duration = sum_durations(events);
- RETURN = {"events": events, "total_duration": total_duration};
+ events = query_bucket("${params.bid_android}");
+ events = merge_events_by_keys(events, ["app"]);
+ events = categorize(events, ${JSON.stringify(params.classes)});
+
+ title_events = sort_by_duration(merge_events_by_keys(events, ["app", "classname"]));
+ app_events = sort_by_duration(merge_events_by_keys(title_events, ["app"]));
+ cat_events = sort_by_duration(merge_events_by_keys(events, ["$category"]));
+
+ events = sort_by_timestamp(events);
+ app_events = limit_events(app_events, ${default_limit});
+ title_events = limit_events(title_events, ${default_limit});
+ duration = sum_durations(events);
+ RETURN = {"app_events": app_events, "title_events": title_events, "cat_events": cat_events, "duration": duration, "active_events": app_events};
`;
return querystr_to_array(code);
}
@@ -122,7 +142,7 @@ function browsersWithBuckets(browserbuckets: string[]): [string, string][] {
}
// Returns a list of active browser events (where the browser was the active window) from all browser buckets
-function browserEvents(params: QueryParams): string {
+function browserEvents(params: DesktopQueryParams): string {
// If multiple browser buckets were found
// AFK filtered later in the process
let code = `
@@ -151,7 +171,6 @@ export function browserSummaryQuery(
browserbuckets: string[],
windowbucket: string,
afkbucket: string,
- limit = 5,
filterAFK = true
): string[] {
// Escape `"`
@@ -160,7 +179,7 @@ export function browserSummaryQuery(
afkbucket = afkbucket.replace('"', '\\"');
// TODO: Get classes
- const params: QueryParams = {
+ const params: DesktopQueryParams = {
bid_window: windowbucket,
bid_afk: afkbucket,
bid_browsers: browserbuckets,
@@ -172,17 +191,17 @@ export function browserSummaryQuery(
`${browserEvents(params)}
urls = merge_events_by_keys(events, ["url"]);
urls = sort_by_duration(urls);
- urls = limit_events(urls, ${limit});
+ urls = limit_events(urls, ${default_limit});
domains = split_url_events(events);
domains = merge_events_by_keys(domains, ["$domain"]);
domains = sort_by_duration(domains);
- domains = limit_events(domains, ${limit});
+ domains = limit_events(domains, ${default_limit});
duration = sum_durations(events);
RETURN = {"domains": domains, "urls": urls, "duration": duration};`
);
}
-export function editorActivityQuery(editorbuckets: string[], limit): string[] {
+export function editorActivityQuery(editorbuckets: string[]): string[] {
let q = ['events = [];'];
for (let editorbucket of editorbuckets) {
editorbucket = editorbucket.replace('"', '\\"');
@@ -190,11 +209,11 @@ export function editorActivityQuery(editorbuckets: string[], limit): string[] {
}
q = q.concat([
'files = sort_by_duration(merge_events_by_keys(events, ["file", "language"]));',
- 'files = limit_events(files, ' + limit + ');',
+ `files = limit_events(files, ${default_limit});`,
'languages = sort_by_duration(merge_events_by_keys(events, ["language"]));',
- 'languages = limit_events(languages, ' + limit + ');',
+ `languages = limit_events(languages, ${default_limit});`,
'projects = sort_by_duration(merge_events_by_keys(events, ["project"]));',
- 'projects = limit_events(projects, ' + limit + ');',
+ `projects = limit_events(projects, ${default_limit});`,
'duration = sum_durations(events);',
'RETURN = {"files": files, "languages": languages, "projects": projects, "duration": duration};',
]);
diff --git a/src/route.js b/src/route.js
index 559fef7f..4bbf888b 100644
--- a/src/route.js
+++ b/src/route.js
@@ -9,7 +9,6 @@ const ActivitySummary = () => import('./views/activity/ActivitySummary.vue');
const ActivityWindow = () => import('./views/activity/ActivityWindow.vue');
const ActivityBrowser = () => import('./views/activity/ActivityBrowser.vue');
const ActivityEditor = () => import('./views/activity/ActivityEditor.vue');
-const ActivityAndroid = () => import('./views/activity/ActivityAndroid.vue');
const Buckets = () => import('./views/Buckets.vue');
const Bucket = () => import('./views/Bucket.vue');
@@ -25,8 +24,6 @@ Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
- // Must be before general activity view such that it matches first
- { path: '/activity/android/:host/:date?', component: ActivityAndroid, props: true },
{
path: '/activity/:host/:periodLength?/:date?',
component: Activity,
diff --git a/src/store/modules/activity.ts b/src/store/modules/activity.ts
index 2c4af994..13330177 100644
--- a/src/store/modules/activity.ts
+++ b/src/store/modules/activity.ts
@@ -6,8 +6,6 @@ import queries from '~/queries';
import { loadClassesForQuery } from '~/util/classes';
import { get_day_start_with_offset } from '~/util/time';
-const default_limit = 100;
-
interface TimePeriod {
start: string;
length: [number, string];
@@ -69,15 +67,21 @@ const _state = {
history: {},
},
+ android: {
+ available: false,
+ },
+
query_options: {
browser_buckets: 'all',
editor_buckets: 'all',
},
+
buckets: {
- afk_buckets: [],
- window_buckets: [],
- editor_buckets: [],
- browser_buckets: [],
+ afk: [],
+ window: [],
+ editor: [],
+ browser: [],
+ android: [],
},
};
@@ -130,8 +134,12 @@ const actions = {
if (state.window.available) {
await dispatch('query_window', query_options);
+ } else if (state.android.available) {
+ await dispatch('query_android', query_options);
} else {
- console.log('Cannot call query_window as we are missing either an afk or window bucket');
+ console.log(
+ 'Cannot query windows as we are missing either an afk/window bucket pair or an android bucket'
+ );
await dispatch('query_window_empty', query_options);
}
@@ -146,6 +154,8 @@ const actions = {
if (state.active.available) {
await dispatch('query_active_history', query_options);
+ } else if (state.android.available) {
+ await dispatch('query_active_history_android', query_options);
} else {
console.log('Cannot call query_active_history as we do not have an afk bucket');
await dispatch('query_active_history_empty', query_options);
@@ -166,18 +176,26 @@ const actions = {
async query_window({ state, commit }, { timeperiod, filterAFK, filterCategories }: QueryOptions) {
const periods = [timeperiodToStr(timeperiod)];
+ const start = moment();
const classes = loadClassesForQuery();
const q = queries.windowQuery(
- state.buckets.window_buckets[0],
- state.buckets.afk_buckets[0],
- default_limit, // this.top_apps_count,
- default_limit, // this.top_windowtitles_count,
+ state.buckets.window[0],
+ state.buckets.afk[0],
filterAFK,
classes,
filterCategories
);
const data = await this._vm.$aw.query(periods, q);
commit('query_window_completed', data[0]);
+ console.info(`Completed window query in ${moment().diff(start)}ms`);
+ },
+
+ async query_android({ state, commit }, { timeperiod, filterCategories }: QueryOptions) {
+ const periods = [timeperiodToStr(timeperiod)];
+ const classes = loadClassesForQuery();
+ const q = queries.appQuery(state.buckets.android[0], classes, filterCategories);
+ const data = await this._vm.$aw.query(periods, q).catch(this.errorHandler);
+ commit('query_window_completed', data[0]);
},
async query_window_empty({ commit }) {
@@ -194,10 +212,9 @@ const actions = {
async query_browser({ state, commit }, { timeperiod, filterAFK }: QueryOptions) {
const periods = [timeperiodToStr(timeperiod)];
const q = queries.browserSummaryQuery(
- state.buckets.browser_buckets,
- state.buckets.window_buckets[0],
- state.buckets.afk_buckets[0],
- default_limit, // this.top_web_count
+ state.buckets.browser,
+ state.buckets.window[0],
+ state.buckets.afk[0],
filterAFK
);
const data = await this._vm.$aw.query(periods, q);
@@ -215,7 +232,7 @@ const actions = {
async query_editor({ state, commit }, { timeperiod }) {
const periods = [timeperiodToStr(timeperiod)];
- const q = queries.editorActivityQuery(state.buckets.editor_buckets, 100);
+ const q = queries.editorActivityQuery(state.buckets.editor);
const data = await this._vm.$aw.query(periods, q);
commit('query_editor_completed', data[0]);
},
@@ -233,12 +250,30 @@ const actions = {
const periods = timeperiodStrsAroundTimeperiod(timeperiod).filter(tp_str => {
return !_.includes(state.active.history, tp_str);
});
- const bucket_id_afk = state.buckets.afk_buckets[0];
- const data = await this._vm.$aw.query(periods, queries.dailyActivityQuery(bucket_id_afk));
+ const data = await this._vm.$aw.query(
+ periods,
+ queries.dailyActivityQuery(state.buckets.afk[0])
+ );
const active_history = _.zipObject(
periods,
_.map(data, pair => _.filter(pair, e => e.data.status == 'not-afk'))
);
+ console.log(active_history);
+ commit('query_active_history_completed', { active_history });
+ },
+
+ async query_active_history_android({ commit, state }, { timeperiod }: QueryOptions) {
+ const periods = timeperiodStrsAroundTimeperiod(timeperiod).filter(tp_str => {
+ return !_.includes(state.active.history, tp_str);
+ });
+ const data = await this._vm.$aw.query(
+ periods,
+ queries.dailyActivityQueryAndroid(state.buckets.android[0])
+ );
+ let active_history = _.zipObject(periods, data);
+ active_history = _.mapValues(active_history, (duration, key) => {
+ return [{ timestamp: key.split('/')[0], duration, data: { status: 'not-afk' } }];
+ });
commit('query_active_history_completed', { active_history });
},
@@ -248,28 +283,30 @@ const actions = {
},
async set_available({ commit, state }) {
- const window_available =
- state.buckets.afk_buckets.length > 0 && state.buckets.window_buckets.length > 0;
+ const window_available = state.buckets.afk.length > 0 && state.buckets.window.length > 0;
const browser_available =
- state.buckets.afk_buckets.length > 0 &&
- state.buckets.window_buckets.length > 0 &&
- state.buckets.browser_buckets.length > 0;
- const active_available = state.buckets.afk_buckets.length > 0;
- const editor_available = state.buckets.editor_buckets.length > 0;
+ state.buckets.afk.length > 0 &&
+ state.buckets.window.length > 0 &&
+ state.buckets.browser.length > 0;
+ const active_available = state.buckets.afk.length > 0;
+ const editor_available = state.buckets.editor.length > 0;
+ const android_available = state.buckets.android.length > 0;
commit('set_available', {
window_available: window_available,
browser_available: browser_available,
active_available: active_available,
editor_available: editor_available,
+ android_available: android_available,
});
},
async get_buckets({ commit, rootGetters }, { host }) {
const buckets = {
- afk_buckets: rootGetters['buckets/afkBucketsByHost'](host),
- window_buckets: rootGetters['buckets/windowBucketsByHost'](host),
- browser_buckets: rootGetters['buckets/browserBuckets'],
- editor_buckets: rootGetters['buckets/editorBuckets'],
+ afk: rootGetters['buckets/afkBucketsByHost'](host),
+ window: rootGetters['buckets/windowBucketsByHost'](host),
+ android: rootGetters['buckets/androidBucketsByHost'](host),
+ browser: rootGetters['buckets/browserBuckets'],
+ editor: rootGetters['buckets/editorBuckets'],
};
console.log('Available buckets: ', buckets);
commit('buckets', buckets);
@@ -458,7 +495,12 @@ const mutations = {
state.active.duration = null;
state.active.events = null;
- state.active.history = {};
+ // Ensures that active history isn't being fully reloaded on every date change
+ // (see caching done in query_active_history and query_active_history_android)
+ // FIXME: Better detection of when to actually clear (such as on force reload, hostname change)
+ if (Object.keys(state.active.history).length === 0) {
+ state.active.history = {};
+ }
},
set_available(state, data) {
@@ -466,7 +508,8 @@ const mutations = {
state.browser.available = data['browser_available'];
state.active.available = data['active_available'];
state.editor.available = data['editor_available'];
- state.category.available = data['window_available'];
+ state.category.available = data['window_available'] || data['android_available'];
+ state.android.available = data['android_available'];
},
query_window_completed(state, data) {
diff --git a/src/store/modules/buckets.js b/src/store/modules/buckets.js
index bc85563a..99e430e1 100644
--- a/src/store/modules/buckets.js
+++ b/src/store/modules/buckets.js
@@ -3,33 +3,41 @@ const state = {
buckets: [],
};
+// TODO: Remove the bucket['id'].includes(testing) check (only needed because I had an old bucket laying around)
function get_buckets_by_type(buckets, type) {
return _.map(
- _.filter(buckets, bucket => bucket['type'] === type),
+ _.filter(buckets, bucket => bucket['type'] === type && !bucket['id'].includes('testing')),
bucket => bucket['id']
);
}
+// TODO: Remove the bucket['id'].includes(testing) check (only needed because I had an old bucket laying around)
function get_buckets_by_host_and_type(buckets, host, type) {
return _.map(
- _.filter(buckets, bucket => bucket['type'] === type && bucket['hostname'] == host),
+ _.filter(
+ buckets,
+ bucket =>
+ bucket['type'] === type && bucket['hostname'] == host && !bucket['id'].includes('testing')
+ ),
bucket => bucket['id']
);
}
// getters
const getters = {
- afkBuckets(state) {
- return get_buckets_by_type(state.buckets, 'afkstatus');
- },
afkBucketsByHost: state => host => {
return get_buckets_by_host_and_type(state.buckets, host, 'afkstatus');
},
- windowBuckets(state) {
- return get_buckets_by_type(state.buckets, 'currentwindow');
- },
windowBucketsByHost: state => host => {
- return get_buckets_by_host_and_type(state.buckets, host, 'currentwindow');
+ return _.filter(
+ get_buckets_by_host_and_type(state.buckets, host, 'currentwindow'),
+ id => !id.startsWith('aw-watcher-android')
+ );
+ },
+ androidBucketsByHost: state => host => {
+ return _.filter(get_buckets_by_host_and_type(state.buckets, host, 'currentwindow'), id =>
+ id.startsWith('aw-watcher-android')
+ );
},
editorBuckets(state) {
return get_buckets_by_type(state.buckets, 'app.editor.activity');
diff --git a/src/views/activity/Activity.vue b/src/views/activity/Activity.vue
index beb15f05..3af66d12 100644
--- a/src/views/activity/Activity.vue
+++ b/src/views/activity/Activity.vue
@@ -25,7 +25,7 @@ div
@change="(periodLength) => setDate(date, periodLength)")
div.p-1(v-if="periodLength === 'day'")
input.form-control(id="date" type="date" :value="date" :max="today"
- @change="setDate($event.target.value)")
+ @change="setDate($event.target.value, periodLength)")
div.p-1.ml-auto
b-button-group
diff --git a/src/views/activity/ActivityAndroid.vue b/src/views/activity/ActivityAndroid.vue
deleted file mode 100644
index fa896500..00000000
--- a/src/views/activity/ActivityAndroid.vue
+++ /dev/null
@@ -1,165 +0,0 @@
-
-div
- h2 Activity for {{ dateShort }}
-
- p
- | Device type: Android
- br
- | Host: {{ host }}
- br
- | Active time: {{ total_duration | friendlyduration }}
-
- div.d-flex
- div.p-1
- b-button-group
- b-button(:to="'/activity/android/' + host + '/' + previousDay()", variant="outline-dark")
- icon(name="arrow-left")
- span.d-none.d-lg-inline
- | Previous day
- b-button(:to="'/activity/android/' + host + '/' + nextDay()", :disabled="nextDay() > today", variant="outline-dark")
- span.d-none.d-lg-inline
- | Next day
- icon(name="arrow-right")
- div.p-1
- input.form-control(id="date" type="date" :value="dateShort" :max="today" @change="setDate($event.target.value)")
-
- div.p-1.ml-auto
- b-button-group
- b-button(@click="refresh()", variant="outline-dark")
- icon(name="sync")
- span.d-none.d-lg-inline
- | Refresh
-
- aw-periodusage(:periodusage_arr="daily_activity", :host="host")
-
- br
-
- div.row
- div.col-md-4
- h5 Top Applications
- aw-summary(:fields="top_apps", :namefunc="top_apps_namefunc", :colorfunc="top_apps_colorfunc")
- b-button(size="sm", variant="outline-secondary", :disabled="top_apps.length < top_apps_count", @click="top_apps_count += 5; queryApps()")
- icon(name="angle-double-down")
- | Show more
-
-
-
-
-
-
-