Skip to content

Commit d46c03a

Browse files
authored
Merge pull request #43 from Omniaevo/develop
Notification sending
2 parents d41693b + 89331c7 commit d46c03a

File tree

4 files changed

+153
-3
lines changed

4 files changed

+153
-3
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mqtt5-explorer",
3-
"version": "1.12.0",
3+
"version": "1.13.0",
44
"private": false,
55
"license": "GPLv3",
66
"description": "A simple MQTT client that supports MQTT5 protocol.",

src/main.js

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ Vue.mixin({
114114

115115
document.head.appendChild(scrollTheme);
116116
},
117+
sendNotification(title, body, onClick = () => {}) {
118+
new window.Notification(title, { body }).onclick = onClick;
119+
},
117120
},
118121
});
119122

src/models/TreeNode.js

+7
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ class TreeNode {
6868
);
6969
}
7070

71+
deepSearch(searchTerm, mode) {
72+
return [
73+
this.search(searchTerm, mode) ? this : undefined,
74+
...(this.child?.deepSearch(searchTerm, mode) ?? []),
75+
];
76+
}
77+
7178
#idFun = () => {};
7279

7380
#blink = () => {

src/views/MqttViewer.vue

+142-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,22 @@
116116
</v-text-field>
117117
</v-slide-y-transition>
118118
<v-spacer />
119-
<div v-if="selectedId !== -1" center-vertical>
119+
<div>
120+
<v-tooltip bottom>
121+
<template v-slot:activator="{ on, attrs }">
122+
<v-btn
123+
v-bind="attrs"
124+
v-on:click="notifySettings = true"
125+
v-on="on"
126+
icon
127+
>
128+
<v-icon>mdi-bell-cog-outline</v-icon>
129+
</v-btn>
130+
</template>
131+
<span>Enable notifications</span>
132+
</v-tooltip>
133+
</div>
134+
<div v-if="selectedId !== -1" center-vertical class="ms-2">
120135
<v-tooltip bottom>
121136
<template v-slot:activator="{ on, attrs }">
122137
<v-btn
@@ -145,12 +160,13 @@
145160
open-on-click
146161
rounded
147162
>
148-
<template slot="label" slot-scope="{ item, leaf }" class="ma-0">
163+
<template slot="label" slot-scope="{ item, leaf }">
149164
<div
150165
v-bind:class="{
151166
primary: item.blink || selectedId === item.id,
152167
'white--text': item.blink || selectedId === item.id,
153168
'px-2': true,
169+
'ma-0': true,
154170
rounded: true,
155171
}"
156172
v-on:click="getProperties(item)"
@@ -452,6 +468,98 @@
452468
</v-card>
453469
</v-dialog>
454470

471+
<v-dialog v-model="notifySettings" max-width="70ch" persistent scrollable>
472+
<v-card>
473+
<v-card-title>Notifications</v-card-title>
474+
<v-card-text class="d-flex flex-column">
475+
<div class="d-flex align-center">
476+
<v-text-field
477+
v-model="notifyEntry"
478+
v-bind:outlined="outline"
479+
v-on:click:append-outer="addNotifyEntry"
480+
v-on:keyup.enter="addNotifyEntry"
481+
append-outer-icon="mdi-bell-plus-outline"
482+
clear-icon="mdi-close"
483+
label="Notify topic"
484+
clearable
485+
/>
486+
<v-btn-toggle v-model="notifyFilterType" class="ms-4">
487+
<v-btn
488+
v-bind:value="searchModes.CASES"
489+
v-on:click.stop
490+
title="Uppercase/Lowercase"
491+
small
492+
icon
493+
>
494+
<v-icon small>mdi-format-letter-case</v-icon>
495+
</v-btn>
496+
<v-btn
497+
v-bind:value="searchModes.WORDS"
498+
v-on:click.stop
499+
title="Match whole word"
500+
small
501+
icon
502+
>
503+
<v-icon small>mdi-format-letter-matches</v-icon>
504+
</v-btn>
505+
<v-btn
506+
v-bind:value="searchModes.REG_EXP"
507+
v-on:click.stop
508+
title="Regular expression"
509+
small
510+
icon
511+
>
512+
<v-icon small>mdi-regex</v-icon>
513+
</v-btn>
514+
</v-btn-toggle>
515+
<v-tooltip bottom>
516+
<template v-slot:activator="{ on, attrs }">
517+
<v-btn
518+
v-bind="attrs"
519+
v-on="on"
520+
v-on:click="searchInfoDialog = true"
521+
class="ms-2"
522+
icon
523+
>
524+
<v-icon>mdi-information-outline</v-icon>
525+
</v-btn>
526+
</template>
527+
<span>Information about searching</span>
528+
</v-tooltip>
529+
</div>
530+
<div class="mt-2">
531+
<div>Notifications active for:</div>
532+
<v-list>
533+
<div v-for="(entry, i) in notifyEntries" v-bind:key="entry">
534+
<v-list-item>
535+
<v-list-item-avatar>
536+
<v-icon>mdi-bell-outline</v-icon>
537+
</v-list-item-avatar>
538+
<v-list-item-content>
539+
<v-list-item-title>{{ entry }}</v-list-item-title>
540+
</v-list-item-content>
541+
<v-list-item-action>
542+
<v-btn
543+
v-on:click="deleteNotifyEntry(entry)"
544+
color="error"
545+
icon
546+
>
547+
<v-icon>mdi-delete-outline</v-icon>
548+
</v-btn>
549+
</v-list-item-action>
550+
</v-list-item>
551+
<v-divider v-if="i < notifyEntries.length - 1" />
552+
</div>
553+
</v-list>
554+
</div>
555+
</v-card-text>
556+
<v-card-actions>
557+
<v-spacer />
558+
<v-btn v-on:click="notifySettings = false" text> Done </v-btn>
559+
</v-card-actions>
560+
</v-card>
561+
</v-dialog>
562+
455563
<v-dialog v-model="searchInfoDialog" max-width="70ch" persistent scrollable>
456564
<v-card>
457565
<v-card-title>How to search</v-card-title>
@@ -615,6 +723,10 @@ export default {
615723
filterType: undefined,
616724
searchModes: SearchEngine.modes,
617725
searchQuery: SearchEngine.QUERY,
726+
notifySettings: false,
727+
notifyFilterType: undefined,
728+
notifyEntry: undefined,
729+
notifyEntries: [],
618730
}),
619731
620732
computed: {
@@ -777,8 +889,36 @@ export default {
777889
this.treeData.splice(index, 1);
778890
}
779891
892+
if (!toDelete) {
893+
this.notify(node);
894+
}
895+
780896
return toDelete;
781897
},
898+
addNotifyEntry() {
899+
if (!this.notifyEntry) return;
900+
901+
this.notifyEntries.push(this.notifyEntry);
902+
903+
this.notifyEntries = [...new Set(this.notifyEntries)];
904+
this.notifyEntry = undefined;
905+
},
906+
deleteNotifyEntry(entry) {
907+
this.notifyEntries = this.notifyEntries.filter((item) => item !== entry);
908+
},
909+
notify(node) {
910+
this.notifyEntries
911+
.flatMap((entry) => {
912+
return node.deepSearch(
913+
entry,
914+
this.notifyFilterType || SearchEngine.modes.ALL
915+
);
916+
})
917+
.forEach((foundNode) => {
918+
if (!foundNode?.value) return;
919+
this.sendNotification(foundNode.value.topic, foundNode.value.payload);
920+
});
921+
},
782922
publishItem() {
783923
this.itemEditing.value.topic = this.itemEditing.topic;
784924

0 commit comments

Comments
 (0)