Skip to content

Commit

Permalink
refactor: moved category/pattern select & Search/Report query options…
Browse files Browse the repository at this point in the history
… into components
  • Loading branch information
ErikBjare committed Apr 27, 2022
1 parent e709c48 commit ba70a4f
Show file tree
Hide file tree
Showing 10 changed files with 351 additions and 161 deletions.
63 changes: 63 additions & 0 deletions src/components/QueryOptions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template lang="pug">
div
b-form-group(label="Hostname" label-cols=2)
b-form-select(v-model="queryOptionsData.hostname")
option(v-for="hostname in hostnameChoices")
| {{hostname}}
b-form-group(label="Start" label-cols=2)
b-form-datepicker(v-model="queryOptionsData.start")
b-form-group(label="Stop" label-cols=2)
b-form-datepicker(v-model="queryOptionsData.stop")
b-form-group(label="Toggles" label-cols=2)
b-form-checkbox(type="checkbox" v-model="queryOptionsData.filter_afk" label="Filter AFK" description="")
label Exclude time away from computer
</template>

<script lang="ts">
import Vue from 'vue';
import moment from 'moment';
export default Vue.extend({
name: 'QueryOptions',
props: {
queryOptions: {
type: Object,
},
},
data() {
return {
queryOptionsData: {
hostname: '',
start: moment().subtract(1, 'day').format('YYYY-MM-DD'),
stop: moment().add(1, 'day').format('YYYY-MM-DD'),
filter_afk: true,
},
};
},
computed: {
hostnameChoices() {
return this.$store.getters['buckets/hosts'];
},
},
watch: {
queryOptionsData: {
handler(value) {
this.$emit('input', value);
},
deep: true,
},
},
async mounted() {
await this.$store.dispatch('buckets/ensureBuckets');
this.queryOptionsData = {
...this.queryOptionsData,
hostname: this.hostnameChoices[0],
...this.queryOptions,
};
this.$emit('input', this.queryOptionsData);
},
});
</script>
55 changes: 55 additions & 0 deletions src/components/SelectCategories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template lang="pug">
// Based on https://bootstrap-vue.org/docs/components/form-tags#using-custom-form-components
b-form-tags#tags-component-select(
v-model="value"
add-on-change
no-outer-focus
)
template(v-slot="{ tags, inputAttrs, inputHandlers, disabled, removeTag }")
b-form-select(
v-bind="inputAttrs"
v-on="inputHandlers"
:disabled="disabled || options.length === 0"
:options="options"
)
template(#first)
// This is required to prevent bugs with Safari
option(disabled value="") Choose a tag...
ul.list-inline.d-inline-block.my-2(v-if="tags.length > 0")
li.list-inline-item(v-for="tag in tags" :key="tag")
b-form-tag(
@remove="removeTag(tag)"
:title="tag"
:disabled="disabled"
variant="info"
)
| {{ tag }}
</template>

<script lang="typescript">
import Vue from 'vue';
const SEP = " > ";
export default Vue.extend({
data() {
return {
value: [],
};
},
computed: {
options() {
const classes = this.$store.state.categories.classes;
return classes.map(category => category.name.join(SEP));
}
},
watch: {
value(val) {
const category_names = val.map(v => v.split(SEP))
this.$emit('input', category_names);
},
},
});
</script>
83 changes: 83 additions & 0 deletions src/components/SelectCategoriesOrPattern.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<template lang="pug">
div
// Let the user either choose a mode to use for filtering events.
// Either let the user choose which of the existing categories to include, or use a custom regex.
b-form-group
b-form-select(v-model="mode")
option(value="custom") Custom regex
option(value="categories") Use existing categories

// select which categories, by having a form select and a "plus" button to include them
b-input-group
aw-select-categories(v-if="mode == 'categories'", v-model="filterCategoriesData")
b-input(v-if="mode == 'custom'" v-model="pattern" v-on:keyup.enter="generate()" placeholder="Regex pattern to search for")
b-input-group-append
slot(name="input-group-append")
</template>

<script lang="ts">
import Vue from 'vue';
const SEP = ' > ';
export default Vue.extend({
name: 'SelectCategoriesOrPattern',
props: {
filterCategories: {
type: Array,
default: () => [],
},
},
data() {
return {
mode: 'categories',
pattern: '',
filterCategoriesData: [],
};
},
computed: {
categories: function () {
return this.$store.state.categories.classes;
},
categoriesWithRules() {
if (this.mode === 'categories') {
// Get the category and all subcategories
return this.categories
.filter(cat => {
const name = cat.name.join(SEP);
for (const filterCat of this.filterCategoriesData) {
if (name.includes(filterCat.join(SEP))) {
return true;
}
}
return false;
})
.filter(cat => cat.rule.type === 'regex')
.map(cat => [cat.name, cat.rule]);
} else if (this.mode === 'custom') {
return [[['searched'], { type: 'regex', regex: this.pattern }]];
} else {
console.error('Unknown mode:', this.mode);
return [];
}
},
},
watch: {
filterCategories() {
this.filterCategoriesData = [...this.filterCategoriesData, ...this.filterCategories];
},
filterCategoriesData() {
this.$emit('input', this.categoriesWithRules);
console.log(this.categoriesWithRules);
},
pattern() {
this.$emit('input', this.categoriesWithRules);
console.log(this.categoriesWithRules);
},
},
async mounted() {
await this.$store.dispatch('categories/load');
},
});
</script>
5 changes: 5 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ Vue.component('aw-selectable-vis', () => import('./components/SelectableVisualiz
Vue.component('aw-selectable-eventview', () => import('./components/SelectableEventView.vue'));
Vue.component('new-release-notification', () => import('./components/NewReleaseNotification.vue'));
Vue.component('user-satisfaction-poll', () => import('./components/UserSatisfactionPoll.vue'));
Vue.component('aw-query-options', () => import('./components/QueryOptions.vue'));
Vue.component('aw-select-categories', () => import('./components/SelectCategories.vue'));
Vue.component('aw-select-categories-or-pattern', () =>
import('./components/SelectCategoriesOrPattern.vue')
);

// Visualization components
Vue.component('aw-summary', () => import('./visualizations/Summary.vue'));
Expand Down
11 changes: 6 additions & 5 deletions src/store/modules/activity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import moment from 'moment';
import * as _ from 'lodash';
import { map, filter, values, groupBy, sortBy, flow, reverse } from 'lodash/fp';
import { IEvent } from '~/util/interfaces';

import { window_events } from '~/util/fakedata';
import queries from '~/queries';
Expand Down Expand Up @@ -326,12 +327,12 @@ const actions = {
}

// Only query periods with known data from AFK bucket
if (dontQueryInactive) {
if (dontQueryInactive && state.active.events.length > 0) {
const start = new Date(period.split('/')[0]);
const end = new Date(period.split('/')[1]);

// Retrieve active time in period
const period_activity = state.active.events.find(e => {
const period_activity = state.active.events.find((e: IEvent) => {
return start < new Date(e.timestamp) && new Date(e.timestamp) < end;
});

Expand Down Expand Up @@ -375,11 +376,11 @@ const actions = {
periods,
queries.activityQueryAndroid(state.buckets.android[0])
);
let active_history = _.zipObject(periods, data);
active_history = _.mapValues(active_history, (duration, key) => {
const active_history = _.zipObject(periods, data);
const active_history_events = _.mapValues(active_history, (duration: number, key): [IEvent] => {
return [{ timestamp: key.split('/')[0], duration, data: { status: 'not-afk' } }];
});
commit('query_active_history_completed', { active_history });
commit('query_active_history_completed', { active_history: active_history_events });
},

async query_active_history_empty({ commit }) {
Expand Down
2 changes: 0 additions & 2 deletions src/store/modules/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,12 @@ const mutations = {

let i = 0;
state.classes = classes.map(c => Object.assign(c, { id: i++ }));
console.log('Loaded classes:', state.classes);
state.classes_unsaved_changes = false;
},
import(state, classes) {
let i = 0;
// overwrite id even if already set
state.classes = classes.map(c => Object.assign(c, { id: i++ }));
console.log('Loaded classes:', state.classes);
state.classes_unsaved_changes = true;
},
updateClass(state, new_class) {
Expand Down
4 changes: 2 additions & 2 deletions src/util/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ export function getTitleAttr(bucket: Bucket, e: IEvent) {
}
} else if (bucket.type == 'afkstatus') {
return e.data.status;
} else if (bucket.type.startsWith('app.editor')) {
} else if (bucket.type?.startsWith('app.editor')) {
return _.last(e.data.file.split('/'));
} else if (bucket.type.startsWith('general.stopwatch')) {
} else if (bucket.type?.startsWith('general.stopwatch')) {
return e.data.label;
} else {
return e.data.title;
Expand Down
Loading

1 comment on commit ba70a4f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are screenshots of this commit:

Screenshots using aw-server v0.11.0 (click to expand)

Screenshots using aw-server-rust v0.11.0 (click to expand)

CML watermark

Please sign in to comment.