Skip to content

Commit d805a02

Browse files
authored
feat(wip): added bucket merge tool (#434)
1 parent 384cb82 commit d805a02

File tree

2 files changed

+146
-1
lines changed

2 files changed

+146
-1
lines changed

src/components/BucketMerge.vue

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<template lang="pug">
2+
div
3+
h3 Merge buckets
4+
p.small
5+
| Sometimes, you might want to merge the events of two buckets together into one.
6+
| This is commonly useful to address the case where your hostname might have changed,
7+
| creating two buckets for the same watcher and host, which you want to combine together again.
8+
9+
// TODO: select which buckets to merge
10+
b-row
11+
b-col
12+
h4 Bucket from
13+
b-form-select(v-model="bucket_from" :options="buckets" :disabled="buckets.length === 0")
14+
p.small
15+
| Select the bucket from which you want to merge the events.
16+
| This bucket will be deleted after the merge.
17+
p.small(v-if="events_from !== null")
18+
| Events: {{ events_from.length }}
19+
b-col
20+
h4 Bucket to
21+
b-form-select(v-model="bucket_to" :options="buckets" :disabled="buckets.length === 0")
22+
p.small
23+
| Select the bucket to which you want to merge the events.
24+
| This bucket will remain after the merge.
25+
p.small(v-if="events_to !== null")
26+
| Events: {{ events_to.length }}
27+
28+
// TODO: check for overlapping events
29+
div(v-if="overlappingEvents !== null && overlappingEvents.length > 0")
30+
h3 Overlapping events
31+
p
32+
| The following {{ overlappingEvents.length }} events are overlapping:
33+
ul
34+
li(v-for="event in overlappingEvents")
35+
| {{ event.from.start }} - {{ event.from.end }} ({{ event.from.event.id }})
36+
| overlaps with
37+
| {{ event.to.start }} - {{ event.to.end }} ({{ event.to.event.id }})
38+
39+
// TODO: confirm dialog
40+
b-button(variant="success" :disabled="!validate" @click="merge()") Merge
41+
42+
// TODO: delete old bucket? (ask user to backup their db if they want to be able to restore after delete)
43+
</template>
44+
45+
<script lang="ts">
46+
import { getClient } from '~/util/awclient';
47+
48+
export default {
49+
name: 'aw-bucket-merge',
50+
data() {
51+
return {
52+
buckets: [],
53+
bucket_from: null,
54+
bucket_to: null,
55+
events_from: null,
56+
events_to: null,
57+
};
58+
},
59+
computed: {
60+
validate() {
61+
const set = this.bucket_from !== null && this.bucket_to !== null;
62+
const not_same = this.bucket_from !== this.bucket_to;
63+
const not_overlapping =
64+
this.overlappingEvents !== null && this.overlappingEvents.length === 0;
65+
return set && not_same && not_overlapping;
66+
},
67+
overlappingEvents() {
68+
if (this.events_from === null || this.events_to === null) {
69+
return null;
70+
}
71+
// check for overlapping events
72+
const overlapping = [];
73+
console.log('events_from', this.events_from);
74+
console.log('events_to', this.events_to);
75+
for (const event_from of this.events_from) {
76+
const from = {
77+
start: new Date(event_from.timestamp),
78+
end: new Date(event_from.timestamp + event_from.duration),
79+
event: event_from,
80+
};
81+
for (const event_to of this.events_to) {
82+
const to = {
83+
start: new Date(event_to.timestamp),
84+
end: new Date(event_to.timestamp + event_to.duration),
85+
event: event_to,
86+
};
87+
// Check for overlap
88+
if (
89+
// `from` start is within `to`
90+
(from.start > to.start && from.start < to.end) ||
91+
// `from` end is within `to`
92+
(from.end > to.start && from.end < to.end)
93+
) {
94+
overlapping.push({ from, to });
95+
}
96+
}
97+
}
98+
if (overlapping.length > 0) {
99+
console.warn('Overlapping events found', overlapping);
100+
}
101+
return overlapping;
102+
},
103+
},
104+
watch: {
105+
bucket_from: async function (new_bucket_id) {
106+
this.events_from = await this.getEvents(new_bucket_id);
107+
},
108+
bucket_to: async function (new_bucket_id) {
109+
this.events_to = await this.getEvents(new_bucket_id);
110+
},
111+
},
112+
mounted() {
113+
this.getBuckets();
114+
},
115+
methods: {
116+
merge: async function () {
117+
const client = getClient();
118+
const events = this.events_from;
119+
const bucket_id = this.bucket_to;
120+
const result = await client.insertEvents(bucket_id, events);
121+
console.log('result', result);
122+
},
123+
getBuckets: async function () {
124+
const client = getClient();
125+
const buckets = await client.getBuckets();
126+
console.log('buckets', buckets);
127+
this.buckets = Object.keys(buckets).map(bucket_id => {
128+
return { value: bucket_id, text: bucket_id };
129+
});
130+
},
131+
getEvents: async function (bucket_id) {
132+
const client = getClient();
133+
return await client.getEvents(bucket_id);
134+
},
135+
},
136+
};
137+
</script>

src/views/Buckets.vue

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ div
2626
icon(name="folder-open").d-none.d-md-inline-block
2727
| Open
2828
b-dropdown(variant="outline-secondary", size="sm", text="More")
29+
// FIXME: These also exist as almost-copies in the Bucket view, can maybe be shared/reused instead.
2930
b-dropdown-item(
3031
:href="$aw.baseURL + '/api/0/buckets/' + data.item.id + '/export'",
3132
:download="'aw-bucket-export-' + data.item.id + '.json'",
@@ -64,7 +65,7 @@ div
6465
b-alert(v-if="import_error" show variant="danger" dismissable)
6566
| {{ import_error }}
6667
b-form-file(v-model="import_file"
67-
placeholder="Choose a file or drop file here..."
68+
placeholder="Choose or drop a file here..."
6869
drop-placeholder="Drop file here...")
6970
// TODO: This spinner could be placed in a more suitable place
7071
div(v-if="import_file" class="spinner-border" role="status")
@@ -79,6 +80,10 @@ div
7980
icon(name="download")
8081
| Export all buckets as JSON
8182

83+
hr
84+
85+
aw-devonly(reason="This component is still under development")
86+
aw-bucket-merge.p-2
8287
</template>
8388

8489
<style lang="scss">
@@ -116,6 +121,9 @@ import { useBucketsStore } from '~/stores/buckets';
116121
117122
export default {
118123
name: 'Buckets',
124+
components: {
125+
'aw-bucket-merge': () => import('~/components/BucketMerge.vue'),
126+
},
119127
data() {
120128
return {
121129
bucketsStore: useBucketsStore(),

0 commit comments

Comments
 (0)