|
476 | 476 | <v-text-field
|
477 | 477 | v-model="notifyEntry"
|
478 | 478 | v-bind:outlined="outline"
|
479 |
| - v-on:click:append-outer="addNotifyEntry" |
480 | 479 | v-on:keyup.enter="addNotifyEntry"
|
481 |
| - append-outer-icon="mdi-bell-plus-outline" |
482 | 480 | clear-icon="mdi-close"
|
483 |
| - label="Notify topic" |
| 481 | + label="Add condition" |
484 | 482 | 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> |
| 483 | + > |
| 484 | + <template slot="append-outer"> |
| 485 | + <div class="d-flex align-center"> |
| 486 | + <v-btn-toggle v-model="notifyFilterType"> |
| 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-btn |
| 516 | + v-bind:disabled="!notifyEntry" |
| 517 | + v-on:click="addNotifyEntry" |
| 518 | + class="ms-1" |
| 519 | + icon |
| 520 | + > |
| 521 | + <v-icon>mdi-plus</v-icon> |
| 522 | + </v-btn> |
| 523 | + </div> |
| 524 | + </template> |
| 525 | + </v-text-field> |
515 | 526 | <v-tooltip bottom>
|
516 | 527 | <template v-slot:activator="{ on, attrs }">
|
517 | 528 | <v-btn
|
518 | 529 | v-bind="attrs"
|
519 | 530 | v-on="on"
|
520 | 531 | v-on:click="searchInfoDialog = true"
|
521 |
| - class="ms-2" |
| 532 | + class="ms-4" |
522 | 533 | icon
|
523 | 534 | >
|
524 | 535 | <v-icon>mdi-information-outline</v-icon>
|
|
528 | 539 | </v-tooltip>
|
529 | 540 | </div>
|
530 | 541 | <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> |
| 542 | + <div class="d-flex justify-space-between align-center"> |
| 543 | + <span>Notification conditions:</span> |
| 544 | + <v-btn-toggle v-model="notifyJoinType"> |
| 545 | + <v-btn |
| 546 | + v-bind:value="joinModes.OR" |
| 547 | + v-on:click.stop |
| 548 | + title="Join conditions with OR operator" |
| 549 | + small |
| 550 | + icon |
| 551 | + > |
| 552 | + <span class="px-2">{{ joinModes.OR }}</span> |
| 553 | + </v-btn> |
| 554 | + <v-btn |
| 555 | + v-bind:value="joinModes.AND" |
| 556 | + v-on:click.stop |
| 557 | + title="Join conditions with AND operator" |
| 558 | + small |
| 559 | + icon |
| 560 | + > |
| 561 | + <span class="px-2">{{ joinModes.AND }}</span> |
| 562 | + </v-btn> |
| 563 | + </v-btn-toggle> |
| 564 | + </div> |
| 565 | + <v-list dense> |
| 566 | + <div |
| 567 | + v-for="(entry, i) in notifyEntries" |
| 568 | + v-bind:key="entry.notifyEntry" |
| 569 | + > |
| 570 | + <v-list-item dense> |
535 | 571 | <v-list-item-avatar>
|
536 |
| - <v-icon>mdi-bell-outline</v-icon> |
| 572 | + <v-icon color="primary" small>mdi-pin-outline</v-icon> |
537 | 573 | </v-list-item-avatar>
|
538 | 574 | <v-list-item-content>
|
539 |
| - <v-list-item-title>{{ entry }}</v-list-item-title> |
| 575 | + <v-list-item-title |
| 576 | + style="font-size: 1.1em" |
| 577 | + class="d-flex align-center justify-space-between" |
| 578 | + > |
| 579 | + <span>{{ entry.notifyEntry }}</span> |
| 580 | + <v-tooltip bottom> |
| 581 | + <template v-slot:activator="{ attr, on }"> |
| 582 | + <v-chip |
| 583 | + v-bind="attr" |
| 584 | + v-on="on" |
| 585 | + class="me-4" |
| 586 | + color="primary" |
| 587 | + outlined |
| 588 | + small |
| 589 | + > |
| 590 | + <v-icon small> |
| 591 | + {{ getFilterTypeIcon(entry.filterType) }} |
| 592 | + </v-icon> |
| 593 | + </v-chip> |
| 594 | + </template> |
| 595 | + <span>Selected match mode</span> |
| 596 | + </v-tooltip> |
| 597 | + </v-list-item-title> |
540 | 598 | </v-list-item-content>
|
541 | 599 | <v-list-item-action>
|
542 | 600 | <v-btn
|
543 | 601 | v-on:click="deleteNotifyEntry(entry)"
|
544 | 602 | color="error"
|
545 | 603 | icon
|
| 604 | + small |
546 | 605 | >
|
547 |
| - <v-icon>mdi-delete-outline</v-icon> |
| 606 | + <v-icon small>mdi-delete-outline</v-icon> |
548 | 607 | </v-btn>
|
549 | 608 | </v-list-item-action>
|
550 | 609 | </v-list-item>
|
551 |
| - <v-divider v-if="i < notifyEntries.length - 1" /> |
| 610 | + <div |
| 611 | + v-if="i < notifyEntries.length - 1" |
| 612 | + class="d-flex align-center" |
| 613 | + > |
| 614 | + <v-divider /> |
| 615 | + <span class="mx-4 caption"> {{ notifyJoinType }} </span> |
| 616 | + <v-divider /> |
| 617 | + </div> |
552 | 618 | </div>
|
553 | 619 | </v-list>
|
554 | 620 | </div>
|
555 | 621 | </v-card-text>
|
556 | 622 | <v-card-actions>
|
| 623 | + <v-btn v-on:click="notifyEntries = []" color="error" text> |
| 624 | + Reset |
| 625 | + </v-btn> |
557 | 626 | <v-spacer />
|
558 | 627 | <v-btn v-on:click="notifySettings = false" text> Done </v-btn>
|
559 | 628 | </v-card-actions>
|
@@ -695,6 +764,7 @@ div[center-vertical] {
|
695 | 764 | </style>
|
696 | 765 |
|
697 | 766 | <script>
|
| 767 | +import Vue from "vue"; |
698 | 768 | import Connection from "../utils/Connection";
|
699 | 769 | import ConnectionProperties from "../models/ConnectionProperties";
|
700 | 770 | import SearchEngine from "../utils/SearchEngine";
|
@@ -727,6 +797,11 @@ export default {
|
727 | 797 | notifyFilterType: undefined,
|
728 | 798 | notifyEntry: undefined,
|
729 | 799 | notifyEntries: [],
|
| 800 | + notifyJoinType: "or", |
| 801 | + joinModes: { |
| 802 | + OR: "or", |
| 803 | + AND: "and", |
| 804 | + }, |
730 | 805 | }),
|
731 | 806 |
|
732 | 807 | computed: {
|
@@ -898,26 +973,65 @@ export default {
|
898 | 973 | addNotifyEntry() {
|
899 | 974 | if (!this.notifyEntry) return;
|
900 | 975 |
|
901 |
| - this.notifyEntries.push(this.notifyEntry); |
| 976 | + const entry = { |
| 977 | + notifyEntry: this.notifyEntry, |
| 978 | + filterType: this.notifyFilterType || SearchEngine.modes.ALL, |
| 979 | + }; |
| 980 | + const entryIndex = this.notifyEntries.findIndex( |
| 981 | + (e) => e.notifyEntry === entry.notifyEntry |
| 982 | + ); |
| 983 | +
|
| 984 | + if (entryIndex < 0) this.notifyEntries.push(entry); |
| 985 | + else Vue.set(this.notifyEntries, entryIndex, entry); |
902 | 986 |
|
903 |
| - this.notifyEntries = [...new Set(this.notifyEntries)]; |
904 | 987 | this.notifyEntry = undefined;
|
| 988 | + this.notifyFilterType = undefined; |
| 989 | + }, |
| 990 | + getFilterTypeIcon(filterType) { |
| 991 | + switch (filterType) { |
| 992 | + case this.searchModes.CASES: |
| 993 | + return "mdi-format-letter-case"; |
| 994 | + case this.searchModes.WORDS: |
| 995 | + return "mdi-format-letter-matches"; |
| 996 | + case this.searchModes.REG_EXP: |
| 997 | + return "mdi-regex"; |
| 998 | + default: |
| 999 | + return "mdi-equal"; |
| 1000 | + } |
905 | 1001 | },
|
906 | 1002 | deleteNotifyEntry(entry) {
|
907 | 1003 | this.notifyEntries = this.notifyEntries.filter((item) => item !== entry);
|
908 | 1004 | },
|
909 | 1005 | 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); |
| 1006 | + let foundNodes = this.notifyEntries.flatMap((entry) => { |
| 1007 | + return node.deepSearch(entry.notifyEntry, entry.filterType); |
| 1008 | + }); |
| 1009 | +
|
| 1010 | + if (this.notifyJoinType === this.joinModes.AND) { |
| 1011 | + foundNodes = foundNodes.filter((foundNode) => { |
| 1012 | + return foundNode |
| 1013 | + ? this.notifyEntries.reduce((previous, entry) => { |
| 1014 | + return ( |
| 1015 | + previous && |
| 1016 | + foundNode.search(entry.notifyEntry, entry.filterType) |
| 1017 | + ); |
| 1018 | + }, true) |
| 1019 | + : false; |
920 | 1020 | });
|
| 1021 | + } |
| 1022 | +
|
| 1023 | + foundNodes.forEach((foundNode) => { |
| 1024 | + if (!foundNode?.value) return; |
| 1025 | + this.sendNotification( |
| 1026 | + foundNode.value.topic, |
| 1027 | + foundNode.value.payload, |
| 1028 | + () => { |
| 1029 | + // Open the app if closed/minimized and select the topic |
| 1030 | + this.getProperties(foundNode); |
| 1031 | + ipcRenderer.send("focusWindow"); |
| 1032 | + } |
| 1033 | + ); |
| 1034 | + }); |
921 | 1035 | },
|
922 | 1036 | publishItem() {
|
923 | 1037 | this.itemEditing.value.topic = this.itemEditing.topic;
|
|
0 commit comments