diff --git a/.eslintrc.json b/.eslintrc.json
index 871a0b38..b6e04f6e 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -13,6 +13,8 @@
"rules": {
"prettier/prettier": "off",
"vue/require-default-prop": "off",
+ "vue/prop-name-casing": "off",
+ "vue/name-property-casing": "off",
"@typescript-eslint/camelcase": ["off"],
"@typescript-eslint/explicit-function-return-type": ["off"],
"@typescript-eslint/no-var-requires": ["off"],
diff --git a/package.json b/package.json
index 1779090a..3bc58938 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"test": "jest --rootDir=src",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
- "lint": "vue-cli-service lint --no-fix-warnings",
+ "lint": "vue-cli-service lint",
"lint_old": "eslint --ignore-path=.gitignore --ext .vue,.js,.ts ."
},
"devDependencies": {
diff --git a/src/components/ErrorBoundary.vue b/src/components/ErrorBoundary.vue
index 0f9d51a0..3a0ea20c 100644
--- a/src/components/ErrorBoundary.vue
+++ b/src/components/ErrorBoundary.vue
@@ -16,7 +16,7 @@ export default {
errorCaptured (err, vm, info) {
//console.error("Error captured!");
//console.error(err, vm, info);
- let msg = (err.name && err.message) ? (err.name + ": " + err.message) : err;
+ const msg = (err.name && err.message) ? (err.name + ": " + err.message) : err;
this.errors.push({
msg: msg,
time: new Date().toISOString(),
diff --git a/src/components/Header.vue b/src/components/Header.vue
index 3458649b..8f2a3e31 100644
--- a/src/components/Header.vue
+++ b/src/components/Header.vue
@@ -100,7 +100,7 @@ import 'vue-awesome/icons/desktop';
import _ from 'lodash';
// Set this to true to test Android behavior when on a desktop
-let testingAndroid = false;
+const testingAndroid = false;
export default {
name: 'Header',
@@ -112,8 +112,8 @@ export default {
};
},
mounted: async function() {
- let buckets = await this.$aw.getBuckets();
- let types_by_host = {};
+ const buckets = await this.$aw.getBuckets();
+ const types_by_host = {};
_.each(buckets, (v) => {
types_by_host[v.hostname] = types_by_host[v.hostname] || {};
// The '&& true;' is just to typecoerce into booleans
diff --git a/src/components/SummaryView.vue b/src/components/SummaryView.vue
index bccd1e1c..f6292c55 100644
--- a/src/components/SummaryView.vue
+++ b/src/components/SummaryView.vue
@@ -43,8 +43,8 @@ export default {
methods: {
query: async function() {
- var periods = [this.period];
- var q = query.summaryQuery(this.windowBucketId, this.afkBucketId, this.limit);
+ const periods = [this.period];
+ const q = query.summaryQuery(this.windowBucketId, this.afkBucketId, this.limit);
let data = await this.$aw.query(periods, q);
console.log(data);
data = data[0];
diff --git a/src/mixins/asyncErrorCaptured.js b/src/mixins/asyncErrorCaptured.js
index 3de97e25..e95db223 100644
--- a/src/mixins/asyncErrorCaptured.js
+++ b/src/mixins/asyncErrorCaptured.js
@@ -8,20 +8,20 @@
function handleError(error, vm, info) {
let cur = vm;
while ((cur = cur.$parent)) {
- var hooks = cur.$options.errorCaptured || [];
- for (let hook of hooks) if (hook.call(cur, error, vm, info) === false) break;
+ const hooks = cur.$options.errorCaptured || [];
+ for (const hook of hooks) if (hook.call(cur, error, vm, info) === false) break;
}
}
export default {
beforeCreate: function() {
- var _self = this;
- var methods = this.$options.methods || {};
+ const _self = this;
+ const methods = this.$options.methods || {};
for (var key in methods) {
var original = methods[key];
methods[key] = function() {
try {
- var result = original.apply(this, arguments);
+ const result = original.apply(this, arguments);
// let's analyse what is returned from the method
if (result && typeof result.then === 'function' && typeof result.catch === 'function') {
// this looks like a Promise. let's handle it's errors:
diff --git a/src/queries.js b/src/queries.js
index fbbc3bfc..0aca70c3 100644
--- a/src/queries.js
+++ b/src/queries.js
@@ -12,7 +12,7 @@ function querystr_to_array(querystr) {
export function summaryQuery(windowbucket, afkbucket, count) {
windowbucket = windowbucket.replace('"', '\\"');
afkbucket = afkbucket.replace('"', '\\"');
- let code = `events = flood(query_bucket("${windowbucket}"));
+ const code = `events = flood(query_bucket("${windowbucket}"));
not_afk = flood(query_bucket("${afkbucket}"));
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);
events = filter_period_intersect(events, not_afk);
@@ -29,7 +29,7 @@ export function summaryQuery(windowbucket, afkbucket, count) {
export function windowQuery(windowbucket, afkbucket, appcount, titlecount, filterAFK, classes) {
windowbucket = windowbucket.replace('"', '\\"');
afkbucket = afkbucket.replace('"', '\\"');
- let code =
+ const code =
`events = flood(query_bucket("${windowbucket}"));
not_afk = flood(query_bucket("${afkbucket}"));
not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);` +
@@ -51,7 +51,7 @@ export function windowQuery(windowbucket, afkbucket, appcount, titlecount, filte
export function appQuery(appbucket, limit) {
appbucket = appbucket.replace('"', '\\"');
limit = limit || 5;
- let code =
+ const code =
`events = query_bucket("${appbucket}");` +
`events = merge_events_by_keys(events, ["app"]);
events = sort_by_duration(events);
@@ -104,12 +104,12 @@ export function browserSummaryQuery(browserbuckets, windowbucket, afkbucket, lim
: '');
_.each(Object.keys(appnames), browserName => {
- let bucketId = _.filter(browserbuckets, buckets => buckets.indexOf(browserName) !== -1)[0];
+ const bucketId = _.filter(browserbuckets, buckets => buckets.indexOf(browserName) !== -1)[0];
if (bucketId === undefined) {
// Skip browser if specific bucket not available
return;
}
- let appnames_str = JSON.stringify(appnames[browserName]);
+ const appnames_str = JSON.stringify(appnames[browserName]);
code +=
`events_${browserName} = flood(query_bucket("${bucketId}"));
window_${browserName} = filter_keyvals(window, "app", ${appnames_str});` +
diff --git a/src/route.js b/src/route.js
index f418d6cf..79be36bc 100644
--- a/src/route.js
+++ b/src/route.js
@@ -23,7 +23,7 @@ const Dev = () => import('./views/Dev.vue');
Vue.use(VueRouter);
-var router = new VueRouter({
+const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{
diff --git a/src/util/awclient.js b/src/util/awclient.js
index 53edd121..c33637a7 100644
--- a/src/util/awclient.js
+++ b/src/util/awclient.js
@@ -5,12 +5,12 @@ let baseURL = "";
// If running with `npm node dev`, use testing server as origin.
// Works since CORS is enabled by default when running `aw-server --testing`.
if(!PRODUCTION) {
- let protocol = "http";
- let hostname = "127.0.0.1";
- let port = "5666";
+ const protocol = "http";
+ const hostname = "127.0.0.1";
+ const port = "5666";
baseURL = protocol + "://" + hostname + ":" + port;
}
-let awc = new AWClient("aw-webui", {testing: !PRODUCTION, baseURL});
+const awc = new AWClient("aw-webui", {testing: !PRODUCTION, baseURL});
export default awc;
diff --git a/src/util/classes.ts b/src/util/classes.ts
index 0953cf08..8aa5fe0a 100644
--- a/src/util/classes.ts
+++ b/src/util/classes.ts
@@ -1,9 +1,9 @@
-let _ = require('lodash');
+const _ = require('lodash');
const level_sep = ">";
interface Category {
- id?: number,
+ id?: number;
name: string[];
name_pretty?: string;
subname?: string;
@@ -16,7 +16,7 @@ interface Category {
children?: Category[];
}
-export let defaultCategories: Category[] = [
+export const defaultCategories: Category[] = [
{ name: ['Work'], rule: { type: 'regex', pattern: 'Google Docs' } },
{
name: ['Work', 'Programming'],
@@ -35,7 +35,7 @@ export let defaultCategories: Category[] = [
export function build_category_hierarchy(classes: Category[]): Category[] {
function annotate(c: Category) {
- let ch = c.name;
+ const ch = c.name;
c.name_pretty = ch.join(level_sep);
c.subname = ch.slice(-1)[0];
c.parent = ch.length > 1 ? ch.slice(0, -1) : null;
@@ -43,19 +43,19 @@ export function build_category_hierarchy(classes: Category[]): Category[] {
return c;
}
- let new_classes = classes.slice().map(c => annotate(c));
+ const new_classes = classes.slice().map(c => annotate(c));
// Insert dangling/undefined parents
- let all_full_names = new Set(new_classes.map(c => c.name.join(level_sep)));
+ const all_full_names = new Set(new_classes.map(c => c.name.join(level_sep)));
function createMissingParents(children) {
children
.map(c => c.parent)
.filter(p => !!p)
.map(p => {
- let name = p.join(level_sep);
+ const name = p.join(level_sep);
if (p && !all_full_names.has(name)) {
- let new_parent = annotate({ name: p, rule: { type: null, pattern: '' } });
+ const new_parent = annotate({ name: p, rule: { type: null, pattern: '' } });
classes.push(new_parent);
all_full_names.add(name);
// New parent might not be top-level, so we need to recurse
@@ -84,7 +84,7 @@ export function build_category_hierarchy(classes: Category[]): Category[] {
export function flatten_category_hierarchy(hier: Category[]): Category[] {
return _.flattenDeep(
hier.map(h => {
- let level = [h, flatten_category_hierarchy(h.children)];
+ const level = [h, flatten_category_hierarchy(h.children)];
h.children = [];
return level;
})
@@ -102,7 +102,7 @@ export function saveClasses(classes: Category[]) {
}
export function loadClasses(): Category[] {
- let classes_json = localStorage.classes;
+ const classes_json = localStorage.classes;
if(classes_json && classes_json.length >= 1) {
return JSON.parse(classes_json);
} else {
diff --git a/src/util/color.js b/src/util/color.js
index 2cfddc22..37f26451 100644
--- a/src/util/color.js
+++ b/src/util/color.js
@@ -8,12 +8,12 @@ const d3 = require("d3");
// See here for examples:
// https://bl.ocks.org/pstuffa/3393ff2711a53975040077b7453781a9
-let scale = d3.scaleOrdinal(['#90CAF9', '#FFE082', '#EF9A9A', '#A5D6A7']);
+const scale = d3.scaleOrdinal(['#90CAF9', '#FFE082', '#EF9A9A', '#A5D6A7']);
// Needed to prewarm the color table
scale.domain([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
-let customColors = {
+const customColors = {
"afk": "#EEE",
"not-afk": "#7F6",
"hibernating": "#DD6",
@@ -46,8 +46,8 @@ function hashcode(str){
if (str.length === 0) {
return hash;
}
- for (var i = 0; i < str.length; i++) {
- var character = str.charCodeAt(i);
+ for (let i = 0; i < str.length; i++) {
+ const character = str.charCodeAt(i);
hash = ((hash<<5)-hash)+character;
hash = hash & hash; // Convert to 32bit integer
}
diff --git a/src/util/time.js b/src/util/time.js
index 0573805f..e1b825d2 100644
--- a/src/util/time.js
+++ b/src/util/time.js
@@ -2,10 +2,10 @@ import moment from 'moment';
export function seconds_to_duration(seconds) {
// Returns a human-readable duration string
- var hrs = Math.floor(seconds / 60 / 60);
- var min = Math.floor((seconds / 60) % 60);
- var sec = Math.floor(seconds % 60);
- let l = [];
+ const hrs = Math.floor(seconds / 60 / 60);
+ const min = Math.floor((seconds / 60) % 60);
+ const sec = Math.floor(seconds % 60);
+ const l = [];
if (hrs != 0) l.push(hrs + 'h');
if (min != 0) l.push(min + 'm');
if (sec != 0 || l.length == 0) l.push(sec + 's');
@@ -13,9 +13,9 @@ export function seconds_to_duration(seconds) {
}
export function friendlydate(timestamp) {
- let now = moment();
- let m = moment.parseZone(timestamp);
- let sinceNow = moment.duration(m.diff(now));
+ const now = moment();
+ const m = moment.parseZone(timestamp);
+ const sinceNow = moment.duration(m.diff(now));
if (-sinceNow.asSeconds() <= 60) {
return `${Math.round(-sinceNow.asSeconds())}s ago`;
} else if (-sinceNow.asSeconds() <= 60 * 60 * 24) {
@@ -25,10 +25,10 @@ export function friendlydate(timestamp) {
}
export function get_day_start_with_offset(dateParam) {
- var dateMoment = dateParam ? moment(dateParam) : moment().startOf('day');
- var start_of_day = localStorage.startOfDay;
- var start_of_day_hours = parseInt(start_of_day.split(':')[0]);
- var start_of_day_minutes = parseInt(start_of_day.split(':')[1]);
+ const dateMoment = dateParam ? moment(dateParam) : moment().startOf('day');
+ 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 dateMoment
.hour(start_of_day_hours)
.minute(start_of_day_minutes)
@@ -47,7 +47,7 @@ export function get_day_period(date) {
export function get_day_start(datestr) {
// Get start time of date
- var datestart = moment(datestr);
+ const datestart = moment(datestr);
datestart.set('hour', 0);
datestart.set('minute', 0);
datestart.set('second', 0);
diff --git a/src/util/tooltip.js b/src/util/tooltip.js
index bcc98f76..9d2d65fa 100644
--- a/src/util/tooltip.js
+++ b/src/util/tooltip.js
@@ -3,7 +3,7 @@ import { seconds_to_duration } from './time.js';
import DOMPurify from 'dompurify';
import _ from 'lodash';
-let sanitize = DOMPurify.sanitize;
+const sanitize = DOMPurify.sanitize;
export function buildTooltip(bucket, e) {
// WARNING: XSS risk, make sure to sanitize properly
diff --git a/src/views/Bucket.vue b/src/views/Bucket.vue
index 19b25251..95b27693 100644
--- a/src/views/Bucket.vue
+++ b/src/views/Bucket.vue
@@ -47,7 +47,7 @@ export default {
},
computed: {
buckets() {
- let bucket = this.bucket;
+ const bucket = this.bucket;
bucket.events = this.events;
return [bucket];
}
@@ -57,6 +57,12 @@ export default {
this.getEvents(this.id);
}
},
+ mounted: function() {
+ this.id = this.$route.params.id;
+ this.getBucketInfo(this.id);
+ this.getEvents(this.id);
+ this.getEventCount(this.id);
+ },
methods: {
getBucketInfo: async function(bucket_id) {
this.bucket = await this.$aw.getBucketInfo(bucket_id);
@@ -75,11 +81,5 @@ export default {
this.eventcount = (await this.$aw.countEvents(bucket_id)).data;
},
},
- mounted: function() {
- this.id = this.$route.params.id;
- this.getBucketInfo(this.id);
- this.getEvents(this.id);
- this.getEventCount(this.id);
- },
}
diff --git a/src/views/Buckets.vue b/src/views/Buckets.vue
index 5e88ad83..6ffcb001 100644
--- a/src/views/Buckets.vue
+++ b/src/views/Buckets.vue
@@ -97,14 +97,14 @@ import _ from 'lodash';
export default {
name: "Buckets",
- mounted: function() {
- this.getBuckets();
- },
data: () => {
return {
buckets: [],
}
},
+ mounted: function() {
+ this.getBuckets();
+ },
methods: {
getBuckets: async function() {
this.buckets = _.orderBy(await this.$aw.getBuckets(), [(b) => b.id], ["asc"]);
diff --git a/src/views/Log.vue b/src/views/Log.vue
index 13da630b..0a36f807 100644
--- a/src/views/Log.vue
+++ b/src/views/Log.vue
@@ -43,14 +43,14 @@ div
diff --git a/src/visualizations/Summary.vue b/src/visualizations/Summary.vue
index 06fe8a4b..292a329d 100644
--- a/src/visualizations/Summary.vue
+++ b/src/visualizations/Summary.vue
@@ -37,11 +37,6 @@ export default {
data: function() {
return { limit_: this.limit }
},
- mounted: function() {
- let el = this.$el.children[0];
- summary.create(el);
- this.update();
- },
watch: {
fields: function() {
this.update();
@@ -50,9 +45,14 @@ export default {
this.update();
},
},
+ mounted: function() {
+ const el = this.$el.children[0];
+ summary.create(el);
+ this.update();
+ },
methods: {
update: function() {
- let el = this.$el.children[0];
+ const el = this.$el.children[0];
if(this.fields !== null) {
summary.updateSummedEvents(el, this.fields.slice(0, this.limit_), this.namefunc, this.colorfunc)
} else {
diff --git a/src/visualizations/SunburstClock.vue b/src/visualizations/SunburstClock.vue
index 6f163881..67d6345e 100644
--- a/src/visualizations/SunburstClock.vue
+++ b/src/visualizations/SunburstClock.vue
@@ -112,12 +112,6 @@ import _ from 'lodash';
export default {
name: "aw-sunburst-clock",
props: ['date', 'afkBucketId', 'windowBucketId'],
- mounted: function() {
- sunburst.create(this.$el);
- this.starttime = moment(this.date);
- this.endtime = moment(this.date).add(1, 'days');
- this.visualize();
- },
data: () => {
return {
@@ -134,6 +128,12 @@ export default {
this.visualize();
}
},
+ mounted: function() {
+ sunburst.create(this.$el);
+ this.starttime = moment(this.date);
+ this.endtime = moment(this.date).add(1, 'days');
+ this.visualize();
+ },
methods: {
todaysEvents: function(bucket_id) {
@@ -148,21 +148,21 @@ export default {
parents = _.sortBy(parents, "timestamp", "desc");
children = _.sortBy(children, "timestamp", "desc");
- var i_child = 0;
- for(var i_parent = 0; i_parent < parents.length; i_parent++) {
- let p = parents[i_parent];
- let p_start = moment(p.timestamp);
- let p_end = p_start.clone().add(p.duration, "seconds");
+ let i_child = 0;
+ for(let i_parent = 0; i_parent < parents.length; i_parent++) {
+ const p = parents[i_parent];
+ const p_start = moment(p.timestamp);
+ const p_end = p_start.clone().add(p.duration, "seconds");
p.children = [];
while(i_child < children.length) {
- var e = children[i_child];
- var e_start = moment(e.timestamp);
- var e_end = e_start.clone().add(e.duration, "seconds");
+ const e = children[i_child];
+ const e_start = moment(e.timestamp);
+ const e_end = e_start.clone().add(e.duration, "seconds");
- let before_parent = e_end.isBefore(p_start);
- let within_parent = e_start.isAfter(p_start) && e_end.isBefore(p_end);
- let after_parent = e_start.isAfter(p_end);
+ const before_parent = e_end.isBefore(p_start);
+ const within_parent = e_start.isAfter(p_start) && e_end.isBefore(p_end);
+ const after_parent = e_start.isAfter(p_end);
// TODO: This isn't correct, yet
if(before_parent) {
@@ -188,9 +188,9 @@ export default {
// Build the root node
//console.log(parents);
- let m_start = moment(_.first(parents).timestamp)
- let m_end = moment(_.tail(parents).timestamp)
- let duration = (m_end - m_start) / 1000;
+ const m_start = moment(_.first(parents).timestamp)
+ const m_end = moment(_.tail(parents).timestamp)
+ const duration = (m_end - m_start) / 1000;
return {
"timestamp": _.first(parents).timestamp,
// TODO: If we want a 12/24h clock, this has to change
diff --git a/src/visualizations/TimelineInspect.vue b/src/visualizations/TimelineInspect.vue
index 4bd3ba36..0925fcd0 100644
--- a/src/visualizations/TimelineInspect.vue
+++ b/src/visualizations/TimelineInspect.vue
@@ -18,10 +18,6 @@ import timeline from './timeline.js';
export default {
name: "aw-timeline",
props: ['chunks', 'show_afk', 'chunkfunc', 'eventfunc'],
- mounted: function() {
- timeline.create(this.$el);
- this.update();
- },
watch: {
chunks: function() {
this.update();
@@ -30,6 +26,10 @@ export default {
this.update();
}
},
+ mounted: function() {
+ timeline.create(this.$el);
+ this.update();
+ },
methods: {
update: function() {
if(this.chunks === null) {
diff --git a/src/visualizations/TimelineSimple.vue b/src/visualizations/TimelineSimple.vue
index 41e983d2..06899b10 100644
--- a/src/visualizations/TimelineSimple.vue
+++ b/src/visualizations/TimelineSimple.vue
@@ -18,13 +18,13 @@ import timeline_simple from './timeline-simple.js';
export default {
name: "aw-timeline",
props: ['type', 'event_type', 'events'],
- mounted: function() {
- timeline_simple.create(this.$el);
- },
watch: {
"events": function() {
timeline_simple.update(this.$el, this.events, this.event_type)
}
+ },
+ mounted: function() {
+ timeline_simple.create(this.$el);
}
}
diff --git a/src/visualizations/VisTimeline.vue b/src/visualizations/VisTimeline.vue
index 3727033c..d4a477dc 100644
--- a/src/visualizations/VisTimeline.vue
+++ b/src/visualizations/VisTimeline.vue
@@ -51,11 +51,33 @@ export default {
}
};
},
- mounted() {
- this.$nextTick(() => {
- let el = this.$el.querySelector('#visualization');
- this.timeline = new Timeline(el, [], [], this.options);
- });
+ computed: {
+ chartData() {
+ const data = [];
+ _.each(this.buckets, (bucket, bidx) => {
+ if(bucket.events === undefined) {
+ return;
+ }
+ let events = bucket.events;
+ // Filter out events shorter than 1 second (notably including 0-duration events)
+ // TODO: Use flooding instead, preferably with some additional method of removing/simplifying short events for even greater performance
+ if(this.filterShortEvents) {
+ events = _.filter(events, (e) => e.duration > 1);
+ }
+ events = _.sortBy(events, (e) => e.timestamp);
+ _.each(events, (e) => {
+ data.push([
+ bidx,
+ getTitleAttr(bucket, e),
+ buildTooltip(bucket, e),
+ new Date(e.timestamp),
+ new Date(moment(e.timestamp).add(e.duration, 'seconds')),
+ getColorFromString(getTitleAttr(bucket, e)),
+ ]);
+ })
+ })
+ return data;
+ },
},
watch: {
buckets() {
@@ -66,12 +88,12 @@ export default {
}
// Build groups
- let groups = _.map(this.buckets, (bucket, bidx) => {
+ const groups = _.map(this.buckets, (bucket, bidx) => {
return {id: bidx, content: this.showRowLabels ? '': bucket.id};
});
// Build items
- let items = _.map(this.chartData, (row, i) => {
+ const items = _.map(this.chartData, (row, i) => {
return {
id: i,
group: row[0],
@@ -85,7 +107,7 @@ export default {
if(groups.length > 0 && items.length > 0) {
if(this.queriedInterval && this.showQueriedInterval) {
- let duration = this.queriedInterval[1].diff(this.queriedInterval[0], "seconds");
+ const duration = this.queriedInterval[1].diff(this.queriedInterval[0], "seconds");
groups.push({id: groups.length, content: "queried interval"});
items.push({
id: items.length + 1,
@@ -102,8 +124,8 @@ export default {
});
}
- let start = (this.queriedInterval && this.queriedInterval[0]) || _.min(_.map(items, (item) => item.start));
- let end = (this.queriedInterval && this.queriedInterval[1]) || _.max(_.map(items, (item) => item.end));
+ const start = (this.queriedInterval && this.queriedInterval[0]) || _.min(_.map(items, (item) => item.start));
+ const end = (this.queriedInterval && this.queriedInterval[1]) || _.max(_.map(items, (item) => item.end));
this.options.min = start;
this.options.max = end;
this.timeline.setOptions(this.options);
@@ -112,33 +134,11 @@ export default {
}
}
},
- computed: {
- chartData() {
- let data = [];
- _.each(this.buckets, (bucket, bidx) => {
- if(bucket.events === undefined) {
- return;
- }
- let events = bucket.events;
- // Filter out events shorter than 1 second (notably including 0-duration events)
- // TODO: Use flooding instead, preferably with some additional method of removing/simplifying short events for even greater performance
- if(this.filterShortEvents) {
- events = _.filter(events, (e) => e.duration > 1);
- }
- events = _.sortBy(events, (e) => e.timestamp);
- _.each(events, (e) => {
- data.push([
- bidx,
- getTitleAttr(bucket, e),
- buildTooltip(bucket, e),
- new Date(e.timestamp),
- new Date(moment(e.timestamp).add(e.duration, 'seconds')),
- getColorFromString(getTitleAttr(bucket, e)),
- ]);
- })
- })
- return data;
- },
+ mounted() {
+ this.$nextTick(() => {
+ const el = this.$el.querySelector('#visualization');
+ this.timeline = new Timeline(el, [], [], this.options);
+ });
},
}
diff --git a/src/visualizations/periodusage.js b/src/visualizations/periodusage.js
index 3a278e2d..c08cdd67 100644
--- a/src/visualizations/periodusage.js
+++ b/src/visualizations/periodusage.js
@@ -14,7 +14,7 @@ function create(svg_elem) {
function set_status(svg_elem, msg) {
// Select svg canvas
svg_elem.innerHTML = '';
- let svg = d3.select(svg_elem);
+ const svg = d3.select(svg_elem);
svg
.append('text')
@@ -26,12 +26,12 @@ function set_status(svg_elem, msg) {
.attr('fill', 'black');
}
-var diagramcolor = '#aaa';
-var diagramcolor_selected = '#fc5';
-var diagramcolor_focused = '#adf';
+const diagramcolor = '#aaa';
+const diagramcolor_selected = '#fc5';
+const diagramcolor_focused = '#adf';
function update(svg_elem, usage_arr, link_prefix) {
- let dateformat = 'YYYY-MM-DD';
+ const dateformat = 'YYYY-MM-DD';
// No apps, sets status to "No data"
if (usage_arr.length <= 0) {
@@ -42,33 +42,33 @@ function update(svg_elem, usage_arr, link_prefix) {
var svg = d3.select(svg_elem);
function get_usage_time(day_events) {
- var day_event = _.head(_.filter(day_events, e => e.data.status == 'not-afk'));
+ const day_event = _.head(_.filter(day_events, e => e.data.status == 'not-afk'));
return day_event != undefined ? day_event.duration : 0;
}
- var usage_times = usage_arr.map(day_events => get_usage_time(day_events));
- var longest_usage = Math.max.apply(null, usage_times);
+ const usage_times = usage_arr.map(day_events => get_usage_time(day_events));
+ let longest_usage = Math.max.apply(null, usage_times);
// Avoid division by zero
if (longest_usage <= 0) {
longest_usage = 0.00000000001;
}
- var padding = 0.3 * (100 / (usage_arr.length - 1));
- var width = 100 / usage_arr.length - padding;
- var center_elem = Math.floor(usage_arr.length / 2);
+ const padding = 0.3 * (100 / (usage_arr.length - 1));
+ const width = 100 / usage_arr.length - padding;
+ const center_elem = Math.floor(usage_arr.length / 2);
_.each(usage_arr, (events, i) => {
- var usage_time = get_usage_time(events);
- var height = 85 * (usage_time / longest_usage);
- var date = '';
+ const usage_time = get_usage_time(events);
+ const height = 85 * (usage_time / longest_usage);
+ let date = '';
if (events.length > 0) {
// slice off so it's only the day
date = moment(usage_arr[i][0].timestamp).format(dateformat);
}
- var color = i == center_elem ? diagramcolor_selected : diagramcolor;
- var offset = 50;
+ const color = i == center_elem ? diagramcolor_selected : diagramcolor;
+ const offset = 50;
- let x = i * padding + i * width + 0.25 * width;
+ const x = i * padding + i * width + 0.25 * width;
if (moment(date).isSame(moment(), 'day')) {
svg
@@ -87,7 +87,7 @@ function update(svg_elem, usage_arr, link_prefix) {
.text('Today');
}
- let rect = svg
+ const rect = svg
.append('rect')
.attr('x', x + '%')
.attr('y', 101 - height + '%') // Draw rect bottom-up
@@ -107,14 +107,14 @@ function update(svg_elem, usage_arr, link_prefix) {
rect.style('fill', diagramcolor_focused);
})
.on('mouseout', (d, j, n) => {
- var a = n[j];
+ const a = n[j];
rect.style('fill', a.getAttribute('color'));
})
.on('click', function(d, j, n) {
- var me = n[j];
- var date = d3.select(me).attr('date');
- var link_prefix = d3.select(me).attr('data');
- var url = `/#${link_prefix}/${date}`;
+ const me = n[j];
+ const date = d3.select(me).attr('date');
+ const link_prefix = d3.select(me).attr('data');
+ const url = `/#${link_prefix}/${date}`;
/* Not the vue-way, but works */
window.location.assign(url);
/* Hardcoding click behavior also isn't optimal I guess */
diff --git a/src/visualizations/summary.js b/src/visualizations/summary.js
index 59af96d4..a71ff3ef 100644
--- a/src/visualizations/summary.js
+++ b/src/visualizations/summary.js
@@ -13,7 +13,7 @@ function create(container) {
container.innerHTML = '';
// Create svg canvas
- let svg = d3.select(container).append('svg');
+ const svg = d3.select(container).append('svg');
svg
.attr('width', '100%')
.attr('height', '100px')
@@ -22,8 +22,8 @@ function create(container) {
function set_status(container, msg) {
// Select svg canvas
- let svg_elem = container.querySelector('.appsummary');
- let svg = d3.select(svg_elem);
+ const svg_elem = container.querySelector('.appsummary');
+ const svg = d3.select(svg_elem);
svg_elem.innerHTML = '';
svg
@@ -37,7 +37,7 @@ function set_status(container, msg) {
}
function updateSummedEvents(container, summedEvents, titleKeyFunc, colorKeyFunc) {
- let apps = _.map(summedEvents, e => {
+ const apps = _.map(summedEvents, e => {
return { name: titleKeyFunc(e), duration: e.duration, colorKey: colorKeyFunc(e) };
});
update(container, apps);
@@ -50,34 +50,34 @@ function update(container, apps) {
return container;
}
- let svg_elem = container.querySelector('.appsummary');
+ const svg_elem = container.querySelector('.appsummary');
svg_elem.innerHTML = '';
- let svg = d3.select(svg_elem);
+ const svg = d3.select(svg_elem);
// Remove apps without a duration from list
apps = apps.filter(function(app) {
return app.duration !== undefined;
});
- var curr_y = 0;
- var longest_duration = apps[0].duration;
+ let curr_y = 0;
+ const longest_duration = apps[0].duration;
_.each(apps, function(app, i) {
// TODO: Expand on click and list titles
// Variables
- var width = (app.duration / longest_duration) * 100 + '%';
- let barHeight = 50;
- let textSize = 15;
- var baseappcolor = getColorFromString(app.colorKey || app.name);
- var appcolor = Color(baseappcolor)
+ const width = (app.duration / longest_duration) * 100 + '%';
+ const barHeight = 50;
+ const textSize = 15;
+ const baseappcolor = getColorFromString(app.colorKey || app.name);
+ const appcolor = Color(baseappcolor)
.lighten(0.1)
.hex();
- var hovercolor = Color(baseappcolor)
+ const hovercolor = Color(baseappcolor)
.darken(0.1)
.hex();
// The group representing an application in the barchart
- let eg = svg.append('g');
+ const eg = svg.append('g');
eg.attr('id', 'summary_app_' + i)
.on('mouseover', function() {
eg.select('rect').style('fill', hovercolor);
diff --git a/src/visualizations/sunburst-clock.js b/src/visualizations/sunburst-clock.js
index 0599e586..99ad9923 100644
--- a/src/visualizations/sunburst-clock.js
+++ b/src/visualizations/sunburst-clock.js
@@ -21,20 +21,20 @@ import { seconds_to_duration } from '../util/time.js';
const color = require('../util/color.js');
// Dimensions of sunburst.
-var width = 750;
-var height = 600;
-var radius = Math.min(width, height) / 2;
+const width = 750;
+const height = 600;
+const radius = Math.min(width, height) / 2;
-var legendData = {
+const legendData = {
afk: color.getColorFromString('afk'),
'not-afk': color.getColorFromString('not-afk'),
hibernating: color.getColorFromString('hibernating'),
};
-var rootEl; // The root DOM node of the graph as a d3 object
-var vis; // The root SVG node of the graph as a d3 object
-var partition;
-var arc;
+let rootEl; // The root DOM node of the graph as a d3 object
+let vis; // The root SVG node of the graph as a d3 object
+let partition;
+let arc;
function create(el) {
// Clear the svg in case we are redrawing
@@ -70,8 +70,8 @@ function create(el) {
}
function drawClockTick(a) {
- let xn = Math.cos(a);
- let yn = Math.sin(a);
+ const xn = Math.cos(a);
+ const yn = Math.sin(a);
vis
.append('line')
@@ -84,11 +84,11 @@ function drawClockTick(a) {
}
function drawClock(h, m, text) {
- let a = 2 * Math.PI * (h / 24 + m / 24 / 60) - (1 / 2) * Math.PI;
+ const a = 2 * Math.PI * (h / 24 + m / 24 / 60) - (1 / 2) * Math.PI;
drawClockTick(a);
- let xn = Math.cos(a);
- let yn = Math.sin(a);
+ const xn = Math.cos(a);
+ const yn = Math.sin(a);
vis
.append('text')
@@ -116,13 +116,13 @@ function update(el, json) {
.style('opacity', 0);
// Turn the data into a d3 hierarchy and calculate the sums.
- var root = d3.hierarchy(json);
- var nodes = partition(root);
+ let root = d3.hierarchy(json);
+ let nodes = partition(root);
- let mode_clock = true;
+ const mode_clock = true;
if (mode_clock) {
// TODO: Make this a checkbox in the UI
- let show_whole_day = true;
+ const show_whole_day = true;
let root_start = moment(json.timestamp);
let root_end = moment(json.timestamp).add(json.duration, 'seconds');
@@ -136,19 +136,19 @@ function update(el, json) {
drawClock(18, 0);
// TODO: Draw only if showing today
- let now = moment();
+ const now = moment();
drawClock(now.hour(), now.minute(), 'Now');
}
nodes = nodes
.each(function(d) {
- let loc_start_sec = moment(d.data.timestamp).diff(root_start, 'seconds', true);
- let loc_end_sec = moment(d.data.timestamp)
+ const loc_start_sec = moment(d.data.timestamp).diff(root_start, 'seconds', true);
+ const loc_end_sec = moment(d.data.timestamp)
.add(d.data.duration, 'seconds')
.diff(root_start, 'seconds', true);
- let loc_start = Math.max(0, loc_start_sec / ((root_end - root_start) / 1000));
- let loc_end = Math.min(1, loc_end_sec / ((root_end - root_start) / 1000));
+ const loc_start = Math.max(0, loc_start_sec / ((root_end - root_start) / 1000));
+ const loc_end = Math.min(1, loc_end_sec / ((root_end - root_start) / 1000));
d.x0 = 2 * Math.PI * loc_start;
d.x1 = 2 * Math.PI * loc_end;
@@ -167,7 +167,7 @@ function update(el, json) {
// If show_whole_day:
// 0.0044 rad = 1min
// 0.0011 rad = 15s
- let threshold = 0.001;
+ const threshold = 0.001;
return d.x1 - d.x0 > threshold;
});
@@ -199,13 +199,13 @@ function mouseclick(d) {
}
function showInfo(d) {
- let hoverEl = d3.select('.explanation > .hover');
+ const hoverEl = d3.select('.explanation > .hover');
- let m = moment(d.data.timestamp);
+ const m = moment(d.data.timestamp);
hoverEl.select('.date').text(m.format('YYYY-MM-DD'));
hoverEl.select('.time').text(m.format('HH:mm:ss'));
- let durationString = seconds_to_duration(d.data.duration);
+ const durationString = seconds_to_duration(d.data.duration);
hoverEl.select('.duration').text(durationString);
hoverEl.select('.title').text(d.data.data.app || d.data.data.status);
@@ -220,7 +220,7 @@ function showInfo(d) {
function mouseover(d) {
showInfo(d);
- var sequenceArray = d.ancestors().reverse();
+ const sequenceArray = d.ancestors().reverse();
sequenceArray.shift(); // remove root node from the array
// Fade all the segments.
@@ -257,7 +257,7 @@ function mouseleave() {
function initializeBreadcrumbTrail() {
// Add the svg area.
- var trail = d3
+ const trail = d3
.select('.sequence')
.append('svg:svg')
.attr('width', width)
@@ -272,20 +272,20 @@ function initializeBreadcrumbTrail() {
function drawLegend() {
// Dimensions of legend item: width, height, spacing, radius of rounded rect.
- var li = {
+ const li = {
w: 75,
h: 30,
s: 3,
r: 3,
};
- var legend = d3
+ const legend = d3
.select('.legend')
.append('svg:svg')
.attr('width', li.w)
.attr('height', d3.keys(legendData).length * (li.h + li.s));
- var g = legend
+ const g = legend
.selectAll('g')
.data(d3.entries(legendData))
.enter()
diff --git a/src/visualizations/timeline-simple.js b/src/visualizations/timeline-simple.js
index 51b00adf..e569d204 100644
--- a/src/visualizations/timeline-simple.js
+++ b/src/visualizations/timeline-simple.js
@@ -7,7 +7,7 @@ const moment = require("moment");
import {getTitleAttr, getColorFromString} from "../util/color.js";
-var time = require("../util/time.js");
+const time = require("../util/time.js");
function create(svg_el) {
// Clear element
@@ -20,7 +20,7 @@ function create(svg_el) {
}
function set_status(svg_el, text){
- let timeline = d3.select(svg_el);
+ const timeline = d3.select(svg_el);
timeline.selectAll("*").remove();
timeline.append("text")
@@ -33,7 +33,7 @@ function set_status(svg_el, text){
}
function update(svg_el, events, event_type) {
- let timeline = d3.select(svg_el);
+ const timeline = d3.select(svg_el);
timeline.selectAll("*").remove();
if (events.length <= 0){
@@ -43,40 +43,40 @@ function update(svg_el, events, event_type) {
events = _.clone(events);
_.reverse(events);
- let e_first = _.first(events);
- let e_last = _.last(events);
- let m_first = moment(e_first.timestamp);
- let m_last = moment(e_last.timestamp);
- let total_duration = (m_last - m_first) / 1000 + e_last.duration;
+ const e_first = _.first(events);
+ const e_last = _.last(events);
+ const m_first = moment(e_first.timestamp);
+ const m_last = moment(e_last.timestamp);
+ const total_duration = (m_last - m_first) / 1000 + e_last.duration;
console.log("First: " + m_first.format());
console.log("Last: " + m_last.format());
console.log("Duration: " + total_duration);
// Iterate over each event and create interval boxes
_.each(events, function(e, i) {
- let id = "timeline_event_" + i;
- let timestamp = moment(e.timestamp);
+ const id = "timeline_event_" + i;
+ const timestamp = moment(e.timestamp);
- let color_base = getColorFromString(getTitleAttr({type: event_type}, e));
- let color_hover = Color(color_base).darken(0.4).hex();
+ const color_base = getColorFromString(getTitleAttr({type: event_type}, e));
+ const color_hover = Color(color_base).darken(0.4).hex();
- let x = (timestamp - m_first) / 1000 / total_duration;
- let width = 100 * e.duration / total_duration;
+ const x = (timestamp - m_first) / 1000 / total_duration;
+ const width = 100 * e.duration / total_duration;
- let eg = timeline.append("g")
+ const eg = timeline.append("g")
.attr("id", id)
.attr("transform", "translate(" + 100 * x + "," + 0 + ")");
- let rect = eg.append("rect")
+ const rect = eg.append("rect")
.attr("width", width)
.attr("height", 4)
.style("fill", color_base)
.on("mouseover", function(d, j, n){
- let elem = n[j];
+ const elem = n[j];
elem.style.fill = color_hover;
})
.on("mouseout", function(d, j, n){
- let elem = n[j];
+ const elem = n[j];
elem.style.fill = color_base;
});
diff --git a/src/visualizations/timeline.js b/src/visualizations/timeline.js
index 699a6b6b..a1652272 100644
--- a/src/visualizations/timeline.js
+++ b/src/visualizations/timeline.js
@@ -14,8 +14,8 @@ import { getColorFromString } from '../util/color.js';
import { seconds_to_duration } from '../util/time.js';
function show_info(container, elem_id) {
- var title_event_box = container.querySelector('#' + elem_id);
- var titleinfo = container.querySelector('.titleinfo-container');
+ const title_event_box = container.querySelector('#' + elem_id);
+ const titleinfo = container.querySelector('.titleinfo-container');
titleinfo.innerHTML = title_event_box.innerHTML;
titleinfo.style.height = title_event_box.getAttribute('height');
}
@@ -38,7 +38,7 @@ function create(container) {
.attr('display', 'none');
// Container for titleinfo that has a fixed size and a overflow scroll
- let titleinfo_container = document.createElement('div');
+ const titleinfo_container = document.createElement('div');
titleinfo_container.style.width = '100%';
titleinfo_container.style.height = '200px';
titleinfo_container.style.overflowY = 'scroll';
@@ -52,11 +52,11 @@ function create(container) {
}
function set_status(container, text) {
- let timeline_elem = container.querySelector('.apptimeline');
- let titleinfo_list_elem = container.querySelector('.titleinfo-list');
- let titleinfo_container_elem = container.querySelector('.titleinfo-container');
+ const timeline_elem = container.querySelector('.apptimeline');
+ const titleinfo_list_elem = container.querySelector('.titleinfo-list');
+ const titleinfo_container_elem = container.querySelector('.titleinfo-container');
- let timeline = d3.select(timeline_elem);
+ const timeline = d3.select(timeline_elem);
timeline_elem.innerHTML = '';
titleinfo_list_elem.innerHTML = '';
titleinfo_container_elem.innerHTML = '';
@@ -72,8 +72,8 @@ function set_status(container, text) {
}
function update(container, events, showAFK, chunkfunc, eventfunc) {
- let timeline = d3.select(container.querySelector('.apptimeline')).html(null);
- let titleinfo_list = d3.select(container.querySelector('.titleinfo-list')).html(null);
+ const timeline = d3.select(container.querySelector('.apptimeline')).html(null);
+ const titleinfo_list = d3.select(container.querySelector('.titleinfo-list')).html(null);
d3.select(container.querySelector('.titleinfo-container')).html(null);
if (events.length <= 0) {
@@ -81,14 +81,14 @@ function update(container, events, showAFK, chunkfunc, eventfunc) {
return;
}
- var firstEvent = events[0];
- var lastEvent = events[events.length - 1];
+ const firstEvent = events[0];
+ const lastEvent = events[events.length - 1];
- var timeStart = moment(firstEvent.timestamp);
- var timeEnd = moment(lastEvent.timestamp).add(lastEvent.duration, 'seconds');
- let totalDuration = _.sumBy(events, 'duration');
+ const timeStart = moment(firstEvent.timestamp);
+ const timeEnd = moment(lastEvent.timestamp).add(lastEvent.duration, 'seconds');
+ const totalDuration = _.sumBy(events, 'duration');
- var secSinceStart = timeEnd.diff(timeStart, 'seconds', true);
+ const secSinceStart = timeEnd.diff(timeStart, 'seconds', true);
// Iterate over each app timeperiod
let curr_x = 0;
@@ -97,7 +97,7 @@ function update(container, events, showAFK, chunkfunc, eventfunc) {
let eventX, eventWidth;
if (showAFK) {
- let eventBegin = moment(e.timestamp);
+ const eventBegin = moment(e.timestamp);
eventX = eventBegin.diff(timeStart, 'seconds', true) / secSinceStart;
eventX = eventX * 100 + '%';
eventWidth = (e.duration / secSinceStart) * 100 + '%';
@@ -106,14 +106,14 @@ function update(container, events, showAFK, chunkfunc, eventfunc) {
eventWidth = (e.duration / totalDuration) * 100;
}
- var appcolor = getColorFromString(chunkfunc(e));
- var hovercolor = Color(appcolor)
+ const appcolor = getColorFromString(chunkfunc(e));
+ const hovercolor = Color(appcolor)
.darken(0.4)
.hex();
- let eg = timeline.append('g').attr('id', 'timeline_event_' + i);
+ const eg = timeline.append('g').attr('id', 'timeline_event_' + i);
- let rect = eg
+ const rect = eg
.append('rect')
.attr('x', eventX)
.attr('y', 0)
@@ -129,7 +129,7 @@ function update(container, events, showAFK, chunkfunc, eventfunc) {
});
// Titleinfo box
- var infobox = titleinfo_list
+ const infobox = titleinfo_list
.append('div')
.attr('id', 'titleinfo_event_' + i)
.style('display', 'none');
@@ -145,14 +145,14 @@ function update(container, events, showAFK, chunkfunc, eventfunc) {
.attr('fill', 'black');
// Titleinfo
- var infolist = infobox.append('table');
+ const infolist = infobox.append('table');
_.each(e.data.subevents, function(t) {
- var inforow = infolist.append('tr');
+ const inforow = infolist.append('tr');
// Clocktime
- var clocktime = moment(t.timestamp).format('HH:mm:ss');
+ const clocktime = moment(t.timestamp).format('HH:mm:ss');
inforow.append('td').text(clocktime);
// Duration
- var duration = seconds_to_duration(t.duration);
+ const duration = seconds_to_duration(t.duration);
inforow
.append('td')
.text(duration)
diff --git a/test.js b/test.js
deleted file mode 100644
index 40e4ed8b..00000000
--- a/test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const jsdom = require("jsdom");
-const { JSDOM } = jsdom;
-const timeline = require("./src/visualizations/timeline.js");
-
-var dom = new JSDOM("")
-global.window = dom.window;
-global.document = dom.window.document;
-
-
-var root_el = dom.window.document.createElement("div");
-
-var example_events = [
- {"timestamp": "", "duration": 10, "data": {"title": "lololtitle", "app": "lololapp"}},
- {"timestamp": "", "duration": 10, "data": {"title": "lololtitle", "app": "lololapp"}}
-]
-
-var total_duration = 20;
-
-timeline.create(root_el)
-timeline.update(root_el, example_events, total_duration)
-