-
-
-
-
-
-
-
-
- {{ broadcast.content.subject }}
-
-
-
-
-
-
-
-
- {{ actionLink.action_name }}
-
-
-
-
-
-
-
- Dismiss
-
-
-
-
+
+
+
+
+
+
+
+
+ {{ currentBroadcast.content.subject }}
+
+
+
+
+
+
+
+
+ {{ actionLink.action_name }}
+
+
+
+
+
+
+
+ Dismiss
+
+
+
From b113a1b988cb19f98393f6052c63393d7f7b9c54 Mon Sep 17 00:00:00 2001
From: davelopez <46503462+davelopez@users.noreply.github.com>
Date: Mon, 24 Jul 2023 14:18:10 +0200
Subject: [PATCH 03/18] Add remaining broadcasts indicator
Helps manage the expectations when multiple broadcasts will be displayed.
---
.../Notifications/Broadcasts/BroadcastsOverlay.vue | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
index e2423a5eff9..a93167e365d 100644
--- a/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
+++ b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
@@ -22,6 +22,11 @@ const { renderMarkdown } = useMarkdown({ openLinksInNewPage: true });
const currentBroadcast = computed(() => getNextActiveBroadcast());
+const remainingBroadcastsCountText = computed(() => {
+ const count = activeBroadcasts.value.length - 1;
+ return count > 0 ? `${count} more` : "";
+});
+
function getNextActiveBroadcast(): BroadcastNotification | undefined {
return activeBroadcasts.value.sort(sortByPublicationTime).at(0);
}
@@ -94,6 +99,9 @@ function onDismiss(item: BroadcastNotification) {
Dismiss
+
+ {{ remainingBroadcastsCountText }}...
+
From 0b09a6df69543948acc68d85c0d186fd769dcc6e Mon Sep 17 00:00:00 2001
From: davelopez <46503462+davelopez@users.noreply.github.com>
Date: Mon, 24 Jul 2023 15:40:44 +0200
Subject: [PATCH 04/18] Add unit tests for BroadcastsOverlay component
---
.../Broadcasts/BroadcastsOverlay.test.ts | 81 +++++++++++++++++++
.../Broadcasts/BroadcastsOverlay.vue | 6 +-
2 files changed, 86 insertions(+), 1 deletion(-)
create mode 100644 client/src/components/Notifications/Broadcasts/BroadcastsOverlay.test.ts
diff --git a/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.test.ts b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.test.ts
new file mode 100644
index 00000000000..9c423edb6dd
--- /dev/null
+++ b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.test.ts
@@ -0,0 +1,81 @@
+import { setActivePinia } from "pinia";
+import flushPromises from "flush-promises";
+import { getLocalVue } from "@tests/jest/helpers";
+import { createTestingPinia } from "@pinia/testing";
+import BroadcastsOverlay from "./BroadcastsOverlay.vue";
+import { shallowMount } from "@vue/test-utils";
+import { type BroadcastNotification, useBroadcastsStore } from "@/stores/broadcastsStore";
+
+const localVue = getLocalVue(true);
+
+const now = new Date();
+const inTwoMonths = new Date(now.setMonth(now.getMonth() + 2));
+
+function generateBroadcastNotification(id: string): BroadcastNotification {
+ return {
+ id: id,
+ create_time: now.toISOString(),
+ update_time: now.toISOString(),
+ publication_time: now.toISOString(),
+ expiration_time: inTwoMonths.toISOString(),
+ source: "testing",
+ variant: "info",
+ content: {
+ subject: `Test subject ${id}`,
+ message: `Test message ${id}`,
+ },
+ };
+}
+
+const FAKE_BROADCASTS: BroadcastNotification[] = [
+ generateBroadcastNotification("1"),
+ generateBroadcastNotification("2"),
+];
+
+async function mountBroadcastsOverlayWith(broadcasts: BroadcastNotification[] = []) {
+ const pinia = createTestingPinia();
+ setActivePinia(pinia);
+
+ const broadcastsStore = useBroadcastsStore();
+ broadcastsStore.broadcasts = broadcasts;
+
+ const spyOnDismissBroadcast = jest.spyOn(broadcastsStore, "dismissBroadcast");
+ spyOnDismissBroadcast.mockImplementation(async (broadcast) => {
+ broadcastsStore.broadcasts = broadcastsStore.broadcasts.filter((b) => b.id !== broadcast.id);
+ });
+
+ const wrapper = shallowMount(BroadcastsOverlay, {
+ localVue,
+ pinia,
+ });
+
+ await flushPromises();
+ return wrapper;
+}
+
+describe("BroadcastsOverlay.vue", () => {
+ it("should not render anything when there is no broadcast", async () => {
+ const wrapper = await mountBroadcastsOverlayWith();
+
+ expect(wrapper.exists()).toBe(true);
+ expect(wrapper.html()).toBe("");
+ });
+
+ it("should render only one broadcast at a time", async () => {
+ const wrapper = await mountBroadcastsOverlayWith(FAKE_BROADCASTS);
+ expect(wrapper.findAll(".broadcast-message")).toHaveLength(1);
+ expect(wrapper.find(".broadcast-message").text()).toContain("Test message 1");
+ });
+
+ it("should render the next broadcast when the current one is dismissed", async () => {
+ const wrapper = await mountBroadcastsOverlayWith(FAKE_BROADCASTS);
+ expect(wrapper.findAll(".broadcast-message")).toHaveLength(1);
+ expect(wrapper.find(".broadcast-message").text()).toContain("Test message 1");
+
+ const dismissButton = wrapper.find("#dismiss-button");
+ await dismissButton.trigger("click");
+
+ expect(wrapper.findAll(".broadcast-message")).toHaveLength(1);
+ expect(wrapper.find(".broadcast-message").text()).toContain("Test message 2");
+ });
+});
diff --git a/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
index a93167e365d..d6dcd19fcb8 100644
--- a/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
+++ b/client/src/components/Notifications/Broadcasts/BroadcastsOverlay.vue
@@ -95,7 +95,11 @@ function onDismiss(item: BroadcastNotification) {