Skip to content

Commit

Permalink
Fix: Update star and comment label counts in the UI dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
jkppr committed Jan 23, 2025
1 parent bc96728 commit c94ba06
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 44 deletions.
2 changes: 2 additions & 0 deletions timesketch/frontend-ng/src/components/Explore/Comments.vue
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export default {
this.comments.push(response.data.objects[0][0])
this.event._source.comment.push(this.comment)
this.comment = ''
this.$store.dispatch('updateEventLabels', { labels: [...this.$store.state.meta.filter_labels], label: "__ts_comment", num: 1 })
})
.catch((e) => {})
},
Expand All @@ -135,6 +136,7 @@ export default {
.then((response) => {
this.comments.splice(commentIndex, 1)
this.event._source.comment.splice(commentIndex, 1)
this.$store.dispatch('updateEventLabels', { labels: [...this.$store.state.meta.filter_labels], label: "__ts_comment", num: -1 })
})
.catch((e) => {
console.error(e)
Expand Down
11 changes: 10 additions & 1 deletion timesketch/frontend-ng/src/components/Explore/EventList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -986,27 +986,36 @@ export default {
this.selectedFields.splice(index, 1)
},
toggleStar(event) {
let count = 0
if (event._source.label.includes('__ts_star')) {
event._source.label.splice(event._source.label.indexOf('__ts_star'), 1)
count = -1
} else {
event._source.label.push('__ts_star')
count = 1
}
ApiClient.saveEventAnnotation(this.sketch.id, 'label', '__ts_star', event, this.currentSearchNode)
.then((response) => {})
.then((response) => {
this.$store.dispatch('updateEventLabels', { labels: [...this.$store.state.meta.filter_labels], label: "__ts_star", num: count })
})
.catch((e) => {
console.error(e)
})
},
toggleMultipleStars: function () {
let netStarCountChange = 0
this.selectedEvents.forEach((event) => {
if (event._source.label.includes('__ts_star')) {
event._source.label.splice(event._source.label.indexOf('__ts_star'), 1)
netStarCountChange--
} else {
event._source.label.push('__ts_star')
netStarCountChange++
}
})
ApiClient.saveEventAnnotation(this.sketch.id, 'label', '__ts_star', this.selectedEvents, this.currentSearchNode)
.then((response) => {
this.$store.dispatch('updateEventLabels',{ labels: [...this.$store.state.meta.filter_labels], label: "__ts_star", num: netStarCountChange })
this.selectedEvents = []
})
.catch((e) => {})
Expand Down
107 changes: 64 additions & 43 deletions timesketch/frontend-ng/src/components/LeftPanel/TagsList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,44 @@ limitations under the License.
-->
<template>
<div>
<div
v-for="label in labels"
:key="label.label"
@click="applyFilterChip(term=label.label, termType='label')"
style="cursor: pointer; font-size: 0.9em"
>
<v-row no-gutters class="pa-2 pl-5" :class="$vuetify.theme.dark ? 'dark-hover' : 'light-hover'">
<v-icon v-if="label.label === '__ts_star'" left small color="amber">mdi-star</v-icon>
<v-icon v-if="label.label === '__ts_comment'" left small>mdi-comment-multiple-outline</v-icon>
<span>
{{ label.label | formatLabelText }} (<small
><strong>{{ label.count | compactNumber }}</strong></small
>)
</span>
</v-row>
</div>
<div
v-for="tag in assignedQuickTags"
:key="tag.tag"
@click="applyFilterChip(term=tag.tag, termField='tag', termType='term')"
style="cursor: pointer; font-size: 0.9em"
>
<v-row no-gutters class="pa-2 pl-5" :class="$vuetify.theme.dark ? 'dark-hover' : 'light-hover'">
<v-icon small left :color="getQuickTag(tag.tag).color">{{ getQuickTag(tag.tag).label }}</v-icon>
<span
>{{ tag.tag }} (<small
><strong>{{ tag.count | compactNumber }}</strong></small
>)</span
>
</v-row>
</div>
<div
v-for="tag in customTags"
:key="tag.tag"
@click="applyFilterChip(term=tag.tag, termField='tag', termType='term')"
style="cursor: pointer; font-size: 0.9em"
>
<v-row no-gutters class="pa-2 pl-5" :class="$vuetify.theme.dark ? 'dark-hover' : 'light-hover'">
<span
>{{ tag.tag }} (<small
><strong>{{ tag.count | compactNumber }}</strong></small
>)</span
<div>
<v-data-iterator
:items="allTagsAndLabels"
:items-per-page.sync="itemsPerPage"
:search="search"
:hide-default-footer="allTagsAndLabels.length <= itemsPerPage"
>
</v-row>
<template v-slot:header v-if="allTagsAndLabels.length > itemsPerPage">
<v-toolbar flat>
<v-text-field
v-model="search"
clearable
hide-details
outlined
dense
prepend-inner-icon="mdi-magnify"
label="Search for tags ..."
></v-text-field>
</v-toolbar>
</template>
<template v-slot:default="props">
<div
v-for="item in props.items"
:key="item.tag || item.label"
@click="applyFilterChip(item.tag || item.label, item.tag ? 'tag' : '', item.tag ? 'term' : 'label')"
style="cursor: pointer; font-size: 0.9em"
>
<v-row no-gutters class="pa-2 pl-5" :class="$vuetify.theme.dark ? 'dark-hover' : 'light-hover'">
<v-icon v-if="item.label === '__ts_star'" left small color="amber">mdi-star</v-icon>
<v-icon v-if="item.label === '__ts_comment'" left small>mdi-comment-multiple-outline</v-icon>
<v-icon v-if="getQuickTag(item.tag)" small left :color="getQuickTag(item.tag).color">{{ getQuickTag(item.tag).label }}</v-icon>
<span>
{{ (item.tag || item.label) | formatLabelText }} (<small><strong>{{ item.count | compactNumber }}</strong></small>)
</span>
</v-row>
</div>
</template>
</v-data-iterator>
</div>
</div>
</template>
Expand All @@ -76,6 +70,8 @@ export default {
{ tag: 'suspicious', color: 'orange', textColor: 'white', label: 'mdi-help-circle-outline' },
{ tag: 'good', color: 'green', textColor: 'white', label: 'mdi-check-circle-outline' },
],
itemsPerPage: 10,
search: ''
}
},
computed: {
Expand All @@ -94,6 +90,31 @@ export default {
assignedQuickTags() {
return this.tags.filter((tag) => this.getQuickTag(tag.tag))
},
allTagsAndLabels() {
const labelOrder = ['__ts_star', '__ts_comment', 'bad', 'suspicious', 'good']
return [...this.labels, ...this.assignedQuickTags, ...this.customTags]
.sort((a, b) => {
const aLabel = a.tag || a.label
const bLabel = b.tag || b.label

const aIsLabel = !!a.label
const bIsLabel = !!b.label

// Sort labels before tags
if (aIsLabel && !bIsLabel) return -1
if (!aIsLabel && bIsLabel) return 1

// Within labels and tags, sort by predefined order first, then alphabetically
const aOrder = labelOrder.indexOf(aLabel)
const bOrder = labelOrder.indexOf(bLabel)

if (aOrder > -1 && bOrder > -1) return aOrder - bOrder // Sort by predefined order
if (aOrder > -1) return -1 // Predefined labels come first
if (bOrder > -1) return 1 // Predefined labels come first

return aLabel.localeCompare(bLabel)
})
},
},
methods: {
getQuickTag(tag) {
Expand Down
16 changes: 16 additions & 0 deletions timesketch/frontend-ng/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export default new Vuex.Store({
SET_TIMELINE_TAGS(state, buckets) {
Vue.set(state, 'tags', buckets)
},
SET_EVENT_LABELS(state, payload) {
Vue.set(state.meta, 'filter_labels', payload)
},
SET_DATA_TYPES(state, payload) {
let buckets = payload.objects[0]['field_bucket']['buckets']
Vue.set(state, 'dataTypes', buckets)
Expand Down Expand Up @@ -239,6 +242,19 @@ export default new Vuex.Store({
})
.catch((e) => {})
},
updateEventLabels(context, payload) {
if (!payload.labels || !payload.label || !payload.num) {
return
}
let labels = payload.labels
let starLabelIndex = labels.findIndex(label => label.label === payload.label);
if (starLabelIndex > -1) {
labels[starLabelIndex].count = labels[starLabelIndex].count + payload.num
} else {
labels.push({ label: payload.label, count: 1 })
}
context.commit('SET_EVENT_LABELS', labels)
},
updateTimelineTags(context, payload) {
if (!context.state.sketch.active_timelines.length) {
return
Expand Down

0 comments on commit c94ba06

Please sign in to comment.