Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions front-end/src/renderer/composables/useFilterNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import useNotificationsStore from '@renderer/stores/storeNotifications.ts';

export default function useFilterNotifications(
transactionNode: Ref<ITransactionNode>,
notificationType: Ref<NotificationType|null>,
notificationType: Ref<NotificationType | NotificationType[] | null>,
) {

/* Stores */
Expand All @@ -22,16 +22,24 @@ export default function useFilterNotifications(
const filteredNotificationIds = computed(() => {
return filteredNotifications.value.map(candidate => candidate.id);
});

const notificationsKey = computed(() => user.selectedOrganization?.serverUrl ?? '');

const notificationTypesArray = computed(() => {
const type = notificationType.value;
if (type === null) return [];
return Array.isArray(type) ? type : [type];
});

const candidateNotifications = computed(() => {
let result: INotificationReceiver[];
if (notificationType.value !== null) {
if (notificationTypesArray.value.length > 0) {
const serverNotifications = notifications.notifications[notificationsKey.value] ?? [];
result = serverNotifications.filter((n: INotificationReceiver) => {
return n.notification.type === notificationType.value;
return notificationTypesArray.value.includes(n.notification.type);
});
} else {
result = []
result = [];
}
return result;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script setup lang="ts">
import type { INotificationReceiver } from '@shared/interfaces';

import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';

import useNotificationsStore from '@renderer/stores/storeNotifications.ts';
import useFilterNotifications from '@renderer/composables/useFilterNotifications.ts';
import { getTransactionTypeFromBackendType } from '@renderer/utils/sdk/transactions.ts';
Expand All @@ -23,6 +26,7 @@ const props = defineProps<{
collection: TransactionNodeCollection;
node: ITransactionNode;
index: number;
oldNotifications?: INotificationReceiver[];
}>();

/* Emits */
Expand All @@ -44,11 +48,8 @@ const router = useRouter();
const createTooltips = useCreateTooltips();

/* Computed */
const hasNotifications = computed(() => {
return notificationMonitor.filteredNotifications.value.length > 0;
});
const filteringNotificationType = computed(() => {
let result: NotificationType | null;
let result: NotificationType | NotificationType[] | null;
switch (props.collection) {
case TransactionNodeCollection.READY_FOR_REVIEW:
result = NotificationType.TRANSACTION_INDICATOR_APPROVE;
Expand All @@ -59,18 +60,54 @@ const filteringNotificationType = computed(() => {
case TransactionNodeCollection.READY_FOR_EXECUTION:
result = NotificationType.TRANSACTION_INDICATOR_EXECUTABLE;
break;
case TransactionNodeCollection.IN_PROGRESS:
case TransactionNodeCollection.HISTORY:
result = [
NotificationType.TRANSACTION_INDICATOR_EXECUTED,
NotificationType.TRANSACTION_INDICATOR_EXPIRED,
NotificationType.TRANSACTION_INDICATOR_ARCHIVED,
NotificationType.TRANSACTION_INDICATOR_CANCELLED,
NotificationType.TRANSACTION_INDICATOR_FAILED,
];
break;
case TransactionNodeCollection.IN_PROGRESS:
result = null;
break;
}
return result;
});

const notificationMonitor = useFilterNotifications(
computed(() => props.node),
filteringNotificationType,
);

const hasOldNotifications = computed(() => {
if (!props.oldNotifications || props.oldNotifications.length === 0) {
return false;
}

const notificationTypes = Array.isArray(filteringNotificationType.value)
? filteringNotificationType.value
: filteringNotificationType.value
? [filteringNotificationType.value]
: [];

if (notificationTypes.length === 0) {
return false;
}

// Check if any old notifications match this node
return props.oldNotifications.some(n => {
const matchesType = notificationTypes.includes(n.notification.type);
const matchesEntity = n.notification.entityId === (props.node.transactionId || props.node.groupId);
return matchesType && matchesEntity;
});
});

const hasNotifications = computed(() => {
return notificationMonitor.filteredNotifications.value.length > 0 || hasOldNotifications.value;
});

const transactionType = computed(() => {
let result: string;
if (props.node.transactionType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import AppLoader from '@renderer/components/ui/AppLoader.vue';
import EmptyTransactions from '@renderer/components/EmptyTransactions.vue';
import TransactionNodeHead from '@renderer/pages/Transactions/components/TransactionNodeHead.vue';
import TransactionNodeRow from '@renderer/pages/Transactions/components/TransactionNodeRow.vue';
import { computed, onBeforeMount, onMounted, ref, watch } from 'vue';
import { useToast } from 'vue-toast-notification';

import {
type ITransactionNode,
TransactionNodeCollection,
} from '../../../../../../shared/src/ITransactionNode.ts';

import { BackEndTransactionType, NotificationType, TransactionStatus } from '@shared/interfaces';

import AppLoader from '@renderer/components/ui/AppLoader.vue';
import EmptyTransactions from '@renderer/components/EmptyTransactions.vue';
import TransactionNodeHead from '@renderer/pages/Transactions/components/TransactionNodeHead.vue';
import TransactionNodeRow from '@renderer/pages/Transactions/components/TransactionNodeRow.vue';
import AppPager from '@renderer/components/ui/AppPager.vue';
import { getTransactionNodes } from '@renderer/services/organization/transactionNode.ts';
import useUserStore from '@renderer/stores/storeUser.ts';
import useNetworkStore from '@renderer/stores/storeNetwork.ts';
import { useToast } from 'vue-toast-notification';
import { isLoggedInOrganization } from '@renderer/utils';
import { errorToastOptions } from '@renderer/utils/toastOptions.ts';
import {
sortTransactionNodes,
TransactionNodeSortField,
} from '@renderer/utils/sortTransactionNodes.ts';
import { BackEndTransactionType, TransactionStatus } from '@shared/interfaces';
import TransactionsFilterV2 from '@renderer/components/Filter/v2/TransactionsFilterV2.vue';
import useMarkNotifications from '@renderer/composables/useMarkNotifications';
import useDisposableWs from '@renderer/composables/useDisposableWs';
import { TRANSACTION_ACTION } from '@shared/constants';
import useWebsocketConnection from '@renderer/stores/storeWebsocketConnection';

/* Props */
const props = defineProps<{
Expand All @@ -30,7 +37,20 @@ const props = defineProps<{
/* Stores */
const user = useUserStore();
const network = useNetworkStore();
const wsStore = useWebsocketConnection();

/* Composables */
const toast = useToast();
const ws = useDisposableWs();
// Mark relevant notifications as read onMounted and onBeforeUnmount
const { oldNotifications } = useMarkNotifications([
NotificationType.TRANSACTION_INDICATOR_EXECUTABLE,
NotificationType.TRANSACTION_INDICATOR_EXECUTED,
NotificationType.TRANSACTION_INDICATOR_EXPIRED,
NotificationType.TRANSACTION_INDICATOR_ARCHIVED,
NotificationType.TRANSACTION_INDICATOR_CANCELLED,
NotificationType.TRANSACTION_INDICATOR_FAILED,
]);

/* State */
const nodes = ref<ITransactionNode[]>([]);
Expand Down Expand Up @@ -98,6 +118,7 @@ function initialSort() {
}
return result;
}

async function fetchNodes(): Promise<void> {
if (isLoggedInOrganization(user.selectedOrganization)) {
isLoading.value = true;
Expand Down Expand Up @@ -132,14 +153,29 @@ function resetPagination(): void {
currentPage.value = 1;
}

const subscribeToTransactionAction = () => {
if (!user.selectedOrganization?.serverUrl) return;
ws.on(user.selectedOrganization?.serverUrl, TRANSACTION_ACTION, async () => {
await fetchNodes();
});
};

/* Watchers */
wsStore.$onAction(ctx => {
if (ctx.name !== 'setup') return;
ctx.after(() => subscribeToTransactionAction());
});

watch(sort, () => {
resetPagination();
sortNodes();
},
);

watch([statusFilter, transactionTypeFilter], fetchNodes, { deep: true });

onBeforeMount(subscribeToTransactionAction);

onMounted(fetchNodes);
</script>

Expand All @@ -166,6 +202,7 @@ onMounted(fetchNodes);
:collection="props.collection"
:node="node"
:index="index"
:old-notifications="oldNotifications"
@transaction-signed="fetchNodes"
@transaction-group-signed="fetchNodes"
/>
Expand Down
Loading