Skip to content
11 changes: 11 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ div#wrapper(v-if="loaded")
import { useSettingsStore } from '~/stores/settings';
import { useServerStore } from '~/stores/server';
import { detectPreferredTheme } from '~/util/theme';
import { setLocale } from '~/i18n';
// if vite is used, you can import css file as module
//import darkCssUrl from '../static/dark.css?url';
//import darkCssContent from '../static/dark.css?inline';
Expand All @@ -33,12 +34,22 @@ export default {
fullContainer() {
return this.$route.meta.fullContainer;
},
language() {
return useSettingsStore().language;
},
},

watch: {
language(language: string) {
setLocale(language);
},
},

async beforeCreate() {
// Get Theme From LocalStorage
const settingsStore = useSettingsStore();
await settingsStore.ensureLoaded();
setLocale(settingsStore.language);
const theme = settingsStore.theme;
const detectedTheme = theme === 'auto' ? detectPreferredTheme() : theme;

Expand Down
34 changes: 18 additions & 16 deletions src/components/BucketMerge.vue
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
<template lang="pug">
div
h3 Merge buckets
h3 {{ $t('bucketTools.mergeTitle') }}
p.small
| Sometimes, you might want to merge the events of two buckets together into one.
| This is commonly useful to address the case where your hostname might have changed,
| creating two buckets for the same watcher and host, which you want to combine together again.
| {{ $t('bucketTools.mergeDescription') }}

// TODO: select which buckets to merge
b-row
b-col
h4 Bucket from
h4 {{ $t('bucketTools.bucketFrom') }}
b-form-select(v-model="bucket_from" :options="buckets" :disabled="buckets.length === 0")
p.small
| Select the bucket from which you want to merge the events.
| This bucket will be deleted after the merge.
| {{ $t('bucketTools.mergeFromHelp') }}
|
| {{ $t('bucketTools.mergeFromDeleted') }}
p.small(v-if="events_from !== null")
| Events: {{ events_from.length }}
| {{ $t('bucketTools.events', { count: events_from.length }) }}
b-col
h4 Bucket to
h4 {{ $t('bucketTools.bucketTo') }}
b-form-select(v-model="bucket_to" :options="buckets" :disabled="buckets.length === 0")
p.small
| Select the bucket to which you want to merge the events.
| This bucket will remain after the merge.
| {{ $t('bucketTools.mergeToHelp') }}
|
| {{ $t('bucketTools.mergeToRemain') }}
p.small(v-if="events_to !== null")
| Events: {{ events_to.length }}
| {{ $t('bucketTools.events', { count: events_to.length }) }}

// TODO: check for overlapping events
div(v-if="overlappingEvents !== null && overlappingEvents.length > 0")
h3 Overlapping events
h3 {{ $t('bucketTools.overlappingEvents') }}
p
| The following {{ overlappingEvents.length }} events are overlapping:
| {{ $t('bucketTools.overlappingCount', { count: overlappingEvents.length }) }}
ul
li(v-for="event in overlappingEvents")
| {{ event[0].start }} - {{ event[0].end }} ({{ event[0].event.id }})
| overlaps with
|
| {{ $t('bucketTools.overlapsWith') }}
|
| {{ event[1].start }} - {{ event[1].end }} ({{ event[1].event.id }})

// TODO: confirm dialog
b-button(variant="success" :disabled="!validate" @click="merge()") Merge
b-button(variant="success" :disabled="!validate" @click="merge()") {{ $t('bucketTools.merge') }}

// TODO: delete old bucket? (ask user to backup their db if they want to be able to restore after delete)
</template>
Expand Down
30 changes: 15 additions & 15 deletions src/components/BucketValidate.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<template lang="pug">
div
h3 Validate buckets
h3 {{ $t('bucketTools.validateTitle') }}
p.small
| This is a small tool to check the validity of your buckets and their events.
| {{ $t('bucketTools.validateDescription') }}

// Form
b-row
b-col
h4 Bucket
h4 {{ $t('bucketTools.bucket') }}
b-form-select(v-model="bucket" :options="buckets" :disabled="buckets.length === 0")
p.small
| Select the bucket to validate.
| {{ $t('bucketTools.validateBucketHelp') }}
p.small(v-if="events !== null")
| Events: {{ events.length }}
| {{ $t('bucketTools.events', { count: events.length }) }}

// Checks
// check for duplicate events
Expand All @@ -21,12 +21,12 @@ div
summary
icon.mx-2(name="check", style="color: #0C0", v-if="duplicateEvents.length === 0")
icon.mx-2(name="exclamation-triangle", style="color: #CC0", v-else)
| Duplicates: {{ duplicateEvents.length }}
| {{ $t('bucketTools.duplicates', { count: duplicateEvents.length }) }}
div.p-2
p(v-if="duplicateEvents.length === 0")
| No duplicate events found.
| {{ $t('bucketTools.noDuplicates') }}
p(v-else)
| The following {{ duplicateEvents.length }} duplicates were found.
| {{ $t('bucketTools.duplicatesFound', { count: duplicateEvents.length }) }}
ul.mt-2
li(v-for="overlap in duplicateEvents")
| {{ overlap[0].start.toISOString() }} - (id: {{ overlap[0].event.id }} & {{ overlap[1].event.id }}): {{ JSON.stringify(overlap[0].data) }}
Expand All @@ -37,15 +37,15 @@ div
summary
icon.mx-2(name="check", style="color: #0C0", v-if="overlappingEvents.length === 0")
icon.mx-2(name="exclamation-triangle", style="color: #CC0", v-else)
| Overlaps: {{ overlappingEvents.length }}x with a total duration of {{ overlapDuration / 1000 | friendlyduration }}
| {{ $t('bucketTools.overlapsBefore', { count: overlappingEvents.length }) }} {{ overlapDuration / 1000 | friendlyduration }}
div.p-2
p(v-if="overlappingEvents.length === 0")
| No overlapping events found.
| {{ $t('bucketTools.noOverlaps') }}
p(v-else)
| The following {{ overlappingEvents.length }} overlaps were found.
| {{ $t('bucketTools.overlapsFound', { count: overlappingEvents.length }) }}
br
span(v-if="overlapDurationSameData > 0")
| Of these, {{ overlapDurationSameData / 1000 | friendlyduration }} are overlaps where the data is the same. These events could potentially be merged.
| {{ $t('bucketTools.sameDataOverlapsBefore') }} {{ overlapDurationSameData / 1000 | friendlyduration }} {{ $t('bucketTools.sameDataOverlapsAfter') }}
p.mt-2(v-for="event in overlappingEvents")
ul
li {{ event[0].start.toISOString() }}/{{ event[0].end.toISOString() }} - (id: {{ event[0].event.id }}): {{ JSON.stringify(event[0].event.data) }}
Expand All @@ -57,12 +57,12 @@ div
summary
icon.mx-2(name="check", style="color: #0C0", v-if="zeroDurationEvents.length === 0")
icon.mx-2(name="info-circle", style="color: #09F", v-else)
| Zero-duration events: {{ zeroDurationEvents.length }}
| {{ $t('bucketTools.zeroDuration', { count: zeroDurationEvents.length }) }}
div.p-2
p.ml-3(v-if="zeroDurationEvents.length === 0")
| No zero-duration events found.
| {{ $t('bucketTools.noZeroDuration') }}
p.ml-3(v-else)
| The following {{ zeroDurationEvents.length }} zero-duration events were found:
| {{ $t('bucketTools.zeroDurationFound', { count: zeroDurationEvents.length }) }}
ul.mt-2
li(v-for="event in zeroDurationEvents")
| {{ event.timestamp.toISOString() }}/{{ new Date(new Date(event.timestamp).valueOf() + 1000 * event.duration).toISOString() }} - (id: {{ event.id }}): {{ JSON.stringify(event.data) }}
Expand Down
43 changes: 22 additions & 21 deletions src/components/CategoryEditModal.vue
Original file line number Diff line number Diff line change
@@ -1,59 +1,58 @@
<template lang="pug">
// The category edit modal
b-modal(id="edit" ref="edit" title="Edit category" @show="resetModal" @hidden="hidden" @ok="handleOk")
b-modal(id="edit" ref="edit" :title="$t('categoryEdit.editTitle')" @show="resetModal" @hidden="hidden" @ok="handleOk")
div.my-1
b-input-group.my-1(prepend="Name")
b-input-group.my-1(:prepend="$t('categoryEdit.name')")
b-form-input(v-model="editing.name")
b-input-group(prepend="Parent")
b-input-group(:prepend="$t('categoryEdit.parent')")
b-select(v-model="editing.parent", :options="allCategories")
//| ID: {{editing.id}}

hr
div.my-1
b Rule
b-input-group.my-1(prepend="Type")
b {{ $t('categoryEdit.rule') }}
b-input-group.my-1(:prepend="$t('categoryEdit.type')")
b-select(v-model="editing.rule.type", :options="allRuleTypes")
div(v-if="editing.rule.type === 'regex'")
b-input-group.my-1(prepend="Pattern")
b-input-group.my-1(:prepend="$t('categoryEdit.pattern')")
b-form-input(v-model="editing.rule.regex")
div.d-flex
div.flex-grow-1
b-form-checkbox(v-model="editing.rule.ignore_case" switch)
| Case insensitive
| {{ $t('categoryEdit.caseInsensitive') }}
div.flex-grow-1
small.text-right
div.text-danger(v-if="!validPattern") Invalid pattern
div.text-warning(v-if="validPattern && broad_pattern") Pattern too broad
div.text-danger(v-if="!validPattern") {{ $t('categoryEdit.invalidPattern') }}
div.text-warning(v-if="validPattern && broad_pattern") {{ $t('categoryEdit.patternTooBroad') }}

hr
div.my-1
b Color
b {{ $t('categoryEdit.color') }}

b-form-checkbox(v-model="editing.inherit_color" switch)
| Inherit parent color
| {{ $t('categoryEdit.inheritParentColor') }}
div.mt-1(v-show="!editing.inherit_color")
color-picker(v-model="editing.color")

hr
div.my-1
b Productivity score
b {{ $t('categoryEdit.productivityScore') }}
b-form-checkbox(v-model="editing.inherit_score" switch)
| Inherit parent score
b-input-group.my-1(prepend="Score" v-if="!editing.inherit_score")
| {{ $t('categoryEdit.inheritParentScore') }}
b-input-group.my-1(:prepend="$t('categoryEdit.score')" v-if="!editing.inherit_score")
b-form-input(v-model="editing.score")

hr
div.my-1
b-btn(variant="danger", @click="removeClass(categoryId); $refs.edit.hide()")
icon(name="trash")
| Remove category
| {{ $t('categoryEdit.removeCategory') }}
</template>

<script lang="ts">
import _ from 'lodash';
import ColorPicker from '~/components/ColorPicker.vue';
import { useCategoryStore } from '~/stores/categories';
import { mapState } from 'pinia';
import { validateRegex, isRegexBroad } from '~/util/validate';

import 'vue-awesome/icons/trash';
Expand Down Expand Up @@ -83,13 +82,15 @@ export default {
};
},
computed: {
...mapState(useCategoryStore, {
allCategories: state => [{ value: [], text: 'None' }].concat(state.allCategoriesSelect),
}),
allCategories: function () {
return [{ value: [], text: this.$t('categoryEdit.none') }].concat(
this.categoryStore.allCategoriesSelect
);
},
allRuleTypes: function () {
return [
{ value: 'none', text: 'None' },
{ value: 'regex', text: 'Regular Expression' },
{ value: 'none', text: this.$t('categoryEdit.none') },
{ value: 'regex', text: this.$t('categoryEdit.regularExpression') },
//{ value: 'glob', text: 'Glob pattern' },
];
},
Expand Down
6 changes: 3 additions & 3 deletions src/components/CategoryEditTree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ div

div.col-4.col-md-8
span.d-none.d-md-inline
span(v-if="_class.rule.type === 'regex'") Rule ({{_class.rule.type}}): #[code {{_class.rule.regex}}]
span.text-muted(v-else) No rule
span(v-if="_class.rule.type === 'regex'") {{ $t('categoryEdit.ruleWithType', { type: _class.rule.type }) }} #[code {{_class.rule.regex}}]
span.text-muted(v-else) {{ $t('categoryEdit.noRule') }}
span.float-right
b-btn.ml-1.border-0(size="sm", variant="outline-secondary", @click="showEditModal(_class.id)" pill)
icon(name="edit")
Expand Down Expand Up @@ -76,7 +76,7 @@ export default {
methods: {
addSubclass: function (parent) {
// Generate a unique default name to prevent duplicate name conflicts (#702)
const baseName = 'New class';
const baseName = this.$t('categories.newClass');
let name = baseName;
let counter = 2;
const existingNames = this.categoryStore.classes.map(c => JSON.stringify(c.name));
Expand Down
4 changes: 2 additions & 2 deletions src/components/DevOnly.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template lang="pug">
div(v-if="show", style="border: 1px solid #aaa; border-radius: 5px")
b-alert(v-if="note", variant="warning" show)
span.float-left This will not appear in the production build #[span(v-if="reason") ({{ reason }})]
span.float-left {{ $t('experiments.devOnlyProductionNote') }} #[span(v-if="reason") ({{ reason }})]
b-btn.float-right.hide-devonly(@click="() => { hide = true }", variant="outline-secondary", size="sm")
| Hide
| {{ $t('experiments.hide') }}
| .
slot
</template>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ErrorBoundary.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default {
msg = err.response.data.message;
} else if (err.name && err.message) {
msg = `${err.name}: ${err.message}.
See dev console (F12) and/or server logs for more info.`;
${this.$t('experiments.errorMoreInfo')}`;
}

this.errors.push({
Expand Down
24 changes: 12 additions & 12 deletions src/components/EventEditor.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<template lang="pug">
b-modal(v-if="event && event.id", :id="'edit-modal-' + event.id", ref="eventEditModal", title="Edit event", centered, hide-footer)
b-modal(v-if="event && event.id", :id="'edit-modal-' + event.id", ref="eventEditModal", :title="$t('eventEditor.editTitle')" centered, hide-footer)
div(v-if="!editedEvent")
| Loading event...
| {{ $t('eventEditor.loading') }}

div(v-else)
table(style="width: 100%")
tr
th Bucket
th {{ $t('eventEditor.bucket') }}
td {{ bucket_id }}
tr
th ID
th {{ $t('eventEditor.id') }}
td {{ event.id }}
tr
th Start
th {{ $t('eventEditor.start') }}
datetime(type="datetime" v-model="start")
tr
th End
th {{ $t('eventEditor.end') }}
datetime(type="datetime" v-model="end")
tr
th Duration
th {{ $t('eventEditor.duration') }}
td {{ editedEvent.duration | friendlyduration }}

hr

table(style="width: 100%")
tr
th Key
th Value
th {{ $t('eventEditor.key') }}
th {{ $t('eventEditor.value') }}
tr(v-for="(v, k) in editedEvent.data" :key="k")
td
b-input(disabled, :value="k", size="sm")
Expand All @@ -40,14 +40,14 @@ b-modal(v-if="event && event.id", :id="'edit-modal-' + event.id", ref="eventEdit
div.float-left
b-button.mx-1(@click="delete_(); close();" variant="danger")
icon.mx-1(name="trash")
| Delete
| {{ $t('common.delete') }}
div.float-right
b-button.mx-1(@click="close")
icon.mx-1(name="times")
| Cancel
| {{ $t('common.cancel') }}
b-button.mx-1(@click="save(); close();", variant="primary")
icon.mx-1(name="save")
| Save
| {{ $t('common.save') }}
</template>

<style lang="scss"></style>
Expand Down
Loading