diff --git a/frontend-react/e2e/pages/authenticated/admin/receiver-status.ts b/frontend-react/e2e/pages/authenticated/admin/receiver-status.ts index 2f0673d9892..baa3808c4c4 100644 --- a/frontend-react/e2e/pages/authenticated/admin/receiver-status.ts +++ b/frontend-react/e2e/pages/authenticated/admin/receiver-status.ts @@ -4,6 +4,9 @@ import type { RSOrganizationSettings } from "../../../../src/config/endpoints/se import { RSReceiverStatus } from "../../../../src/hooks/api/UseReceiversConnectionStatus/UseReceiversConnectionStatus"; import { createStatusTimePeriodData, + isConnectionResultMatch, + MATCHING_FILTER_CLASSNAME_MAP, + MatchingFilter, SUCCESS_RATE_CLASSNAME_MAP, SuccessRate, } from "../../../../src/pages/admin/receiver-dashboard/utils"; @@ -403,9 +406,13 @@ export class AdminReceiverStatusPage extends BasePage { } async testReceiverStatusDisplay(isSmoke = false) { + const selectedSuccessRate = this.filterFormInputs.successType.value as SuccessRate; const [startDate, endDate] = this.filterFormInputs.dateRange.value; const statusRows = this.receiverStatusRowsLocator; - await expect(statusRows).toHaveCount(new Set(this.receiverStatus?.map((r) => r.receiverId)).size); + const timePeriodData = this.timePeriodData.filter( + (d) => selectedSuccessRate === SuccessRate.UNDEFINED || d.successRateType === selectedSuccessRate, + ); + await expect(statusRows).toHaveCount(timePeriodData.length); const expectedDaysText = [ dateShortFormat(startDate), @@ -415,7 +422,7 @@ export class AdminReceiverStatusPage extends BasePage { for (const [ i, { days, successRate, organizationName, receiverName, successRateType }, - ] of this.timePeriodData.entries()) { + ] of timePeriodData.entries()) { const { title, display, days: daysLoc } = statusRows.nthCustom(i); const expectedTitleText = this.getExpectedReceiverStatusRowTitle( @@ -438,9 +445,31 @@ export class AdminReceiverStatusPage extends BasePage { const daySlices = daysLoc.nthCustom(i).timePeriods; await expect(daySlices).toHaveCount(timePeriods.length); - for (const [i, { successRateType }] of timePeriods.entries()) { + for (const [i, { successRateType, entries }] of timePeriods.entries()) { const sliceEle = daySlices.nth(i); - const expectedClass = new RegExp(SUCCESS_RATE_CLASSNAME_MAP[successRateType]); + // filtering status isn't recalculated automatically, so do it here + const isResultFilterMatch = + this.filterFormInputs.resultMessage.value === "" + ? undefined + : entries.some((e) => + isConnectionResultMatch( + e.connectionCheckResult, + this.filterFormInputs.resultMessage.value, + ), + ); + const classStr = [ + SUCCESS_RATE_CLASSNAME_MAP[successRateType], + MATCHING_FILTER_CLASSNAME_MAP[ + isResultFilterMatch == null + ? MatchingFilter.NO_FILTER + : isResultFilterMatch + ? MatchingFilter.FILTER_IS_MATCHED + : MatchingFilter.FILTER_NOT_MATCHED + ], + ] + .filter(Boolean) + .join(" "); + const expectedClass = new RegExp(classStr); await expect(sliceEle).toBeVisible(); await expect(sliceEle).toHaveClass(expectedClass); @@ -456,17 +485,15 @@ export class AdminReceiverStatusPage extends BasePage { } async testReceiverName() { - const { organizationName, receiverName, successRate } = - this.timePeriodData[1]; + const { organizationName, receiverName, successRate } = this.timePeriodData[1]; const receiversStatusRows = this.receiverStatusRowsLocator; const expectedReceiverStatusRow = receiversStatusRows.nthCustom(0); - const expectedReceiverStatusRowTitle = - this.getExpectedReceiverStatusRowTitle( - organizationName, - receiverName, - successRate, - ); + const expectedReceiverStatusRowTitle = this.getExpectedReceiverStatusRowTitle( + organizationName, + receiverName, + successRate, + ); await expect(receiversStatusRows).toHaveCount(this.timePeriodData.length); @@ -491,8 +518,8 @@ export class AdminReceiverStatusPage extends BasePage { const dayI = 0; const timePeriodI = 2; const entryI = 0; - const {days} = this.timePeriodData[receiverI]; - const {connectionCheckResult} = days[dayI].timePeriods[timePeriodI].entries[entryI]; + const { days } = this.timePeriodData[receiverI]; + const { connectionCheckResult } = days[dayI].timePeriods[timePeriodI].entries[entryI]; const receiversStatusRows = this.receiverStatusRowsLocator; @@ -500,11 +527,11 @@ export class AdminReceiverStatusPage extends BasePage { resultMessage: connectionCheckResult, }); - for (const [i, {days}] of this.timePeriodData.entries()) { + for (const [i, { days }] of this.timePeriodData.entries()) { const isRowExpected = i === receiverI; const row = receiversStatusRows.nthCustom(i); - for (const [i, {timePeriods}] of days.entries()) { + for (const [i, { timePeriods }] of days.entries()) { const isDayExpected = isRowExpected && i === dayI; const rowDay = row.days.nthCustom(i); @@ -537,20 +564,18 @@ export class AdminReceiverStatusPage extends BasePage { const link = row.title.getByRole("link", { name: organizationName, exact: true }).first(); const expectedUrl = this.getExpectedStatusOrganizationUrl(i); await expect(link).toBeVisible(); - const p = this.page.route( - `/api/settings/organizations/${organizationName}`, - (route) => - route.fulfill({ - json: { - description: "fake", - filters: [], - name: organizationName, - jurisdiction: "fake", - version: 0, - createdAt: "", - createdBy: "", - } satisfies RSOrganizationSettings, - }), + const p = this.page.route(`/api/settings/organizations/${organizationName}`, (route) => + route.fulfill({ + json: { + description: "fake", + filters: [], + name: organizationName, + jurisdiction: "fake", + version: 0, + createdAt: "", + createdBy: "", + } satisfies RSOrganizationSettings, + }), ); await link.click(); await expect(this.page).toHaveURL(expectedUrl); @@ -624,9 +649,7 @@ export class AdminReceiverStatusPage extends BasePage { }); await expect(link).toBeVisible(); await link.click(); - await expect(this.page).toHaveURL( - this.getExpectedStatusReceiverUrl(i), - ); + await expect(this.page).toHaveURL(this.getExpectedStatusReceiverUrl(i)); await this.page.goBack(); if (isSmoke && i === 0) { diff --git a/frontend-react/e2e/spec/chromium-only/authenticated/receiver-status-page-user-flow.spec.ts b/frontend-react/e2e/spec/chromium-only/authenticated/receiver-status-page-user-flow.spec.ts index 8cb59f03528..152996d902e 100644 --- a/frontend-react/e2e/spec/chromium-only/authenticated/receiver-status-page-user-flow.spec.ts +++ b/frontend-react/e2e/spec/chromium-only/authenticated/receiver-status-page-user-flow.spec.ts @@ -1,4 +1,5 @@ import { addDays, endOfDay, startOfDay, subDays } from "date-fns"; +import { SuccessRate } from "../../../../src/pages/admin/receiver-dashboard/utils"; import { AdminReceiverStatusPage } from "../../../pages/authenticated/admin/receiver-status"; import { test as baseTest, expect, logins } from "../../../test"; @@ -36,74 +37,70 @@ const test = baseTest.extend({ }, }); -test.describe("Admin Receiver Status Page", +test.describe( + "Admin Receiver Status Page", { // TODO: Investigate Admin Receiver Status Page › functions correctly › receiver statuses › time period modals - // tag: "@smoke", - }, () => { + tag: "@smoke", + }, + () => { test.use({ storageState: logins.admin.path }); test.describe("displays correctly", () => { test.describe("header", () => { - test( - "has correct title + heading", - async ({ adminReceiverStatusPage }) => { - await adminReceiverStatusPage.testHeader(); - }, - ); + test("has correct title + heading", async ({ adminReceiverStatusPage }) => { + await adminReceiverStatusPage.testHeader(); + }); }); - test.describe( - "filters", - () => { - test("date range", async ({ adminReceiverStatusPage }) => { - const { button, label, modalOverlay, valueDisplay } = - adminReceiverStatusPage.filterFormInputs.dateRange; - await expect(label).toBeVisible(); - await expect(button).toBeVisible(); - await expect(valueDisplay).toHaveText(adminReceiverStatusPage.expectedDateRangeLabelText); - await expect(modalOverlay).toBeHidden(); - }); + test.describe("filters", () => { + test("date range", async ({ adminReceiverStatusPage }) => { + const { button, label, modalOverlay, valueDisplay } = + adminReceiverStatusPage.filterFormInputs.dateRange; + await expect(label).toBeVisible(); + await expect(button).toBeVisible(); + await expect(valueDisplay).toHaveText(adminReceiverStatusPage.expectedDateRangeLabelText); + await expect(modalOverlay).toBeHidden(); + }); - test("receiver name", async ({ adminReceiverStatusPage }) => { - const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = - adminReceiverStatusPage.filterFormInputs.receiverName; - await expect(label).toBeVisible(); - await expect(input).toBeVisible(); - await expect(input).toHaveValue(expectedDefaultValue); - - await expect(tooltip).toBeHidden(); - await input.hover(); - await expect(tooltip).toBeVisible(); - await expect(tooltip).toHaveText(expectedTooltipText); - }); + test("receiver name", async ({ adminReceiverStatusPage }) => { + const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = + adminReceiverStatusPage.filterFormInputs.receiverName; + await expect(label).toBeVisible(); + await expect(input).toBeVisible(); + await expect(input).toHaveValue(expectedDefaultValue); + + await expect(tooltip).toBeHidden(); + await input.hover(); + await expect(tooltip).toBeVisible(); + await expect(tooltip).toHaveText(expectedTooltipText); + }); - test("results message", async ({ adminReceiverStatusPage }) => { - const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = - adminReceiverStatusPage.filterFormInputs.resultMessage; - await expect(label).toBeVisible(); - await expect(input).toBeVisible(); - await expect(input).toHaveValue(expectedDefaultValue); - - await expect(tooltip).toBeHidden(); - await input.hover(); - await expect(tooltip).toBeVisible(); - await expect(tooltip).toHaveText(expectedTooltipText); - }); + test("results message", async ({ adminReceiverStatusPage }) => { + const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = + adminReceiverStatusPage.filterFormInputs.resultMessage; + await expect(label).toBeVisible(); + await expect(input).toBeVisible(); + await expect(input).toHaveValue(expectedDefaultValue); + + await expect(tooltip).toBeHidden(); + await input.hover(); + await expect(tooltip).toBeVisible(); + await expect(tooltip).toHaveText(expectedTooltipText); + }); - test("success type", async ({ adminReceiverStatusPage }) => { - const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = - adminReceiverStatusPage.filterFormInputs.successType; - await expect(label).toBeVisible(); - await expect(input).toBeVisible(); - await expect(input).toHaveValue(expectedDefaultValue); - - await expect(tooltip).toBeHidden(); - await input.hover(); - await expect(tooltip).toBeVisible(); - await expect(tooltip).toHaveText(expectedTooltipText); - }); - }, - ); + test("success type", async ({ adminReceiverStatusPage }) => { + const { input, expectedTooltipText, label, tooltip, expectedDefaultValue } = + adminReceiverStatusPage.filterFormInputs.successType; + await expect(label).toBeVisible(); + await expect(input).toBeVisible(); + await expect(input).toHaveValue(expectedDefaultValue); + + await expect(tooltip).toBeHidden(); + await input.hover(); + await expect(tooltip).toBeVisible(); + await expect(tooltip).toHaveText(expectedTooltipText); + }); + }); // Failures here indicate potential misalignment of playwright/browser timezone test.describe("receiver statuses", () => { @@ -114,85 +111,72 @@ test.describe("Admin Receiver Status Page", }); test.describe("has footer", () => { - test("has footer and explicit scroll to footer and scroll to top", - async ({ - adminReceiverStatusPage, - }) => { - await adminReceiverStatusPage.testFooter(); - }); + test("has footer and explicit scroll to footer and scroll to top", async ({ + adminReceiverStatusPage, + }) => { + await adminReceiverStatusPage.testFooter(); + }); }); }); test.describe("functions correctly", () => { test.describe("filters", () => { - test.describe( - "date range", - () => { - test("works through calendar", async ({ adminReceiverStatusPage }) => { - const { valueDisplay } = adminReceiverStatusPage.filterFormInputs.dateRange; - const now = new Date(); - const targetFrom = startOfDay(subDays(now, 3)); - const targetTo = addDays(endOfDay(now), 1); - - const reqUrl = await adminReceiverStatusPage.updateFilters({ - dateRange: { - value: [targetFrom, targetTo], - }, - }); - expect(reqUrl).toBeDefined(); - - await expect(valueDisplay).toHaveText( - adminReceiverStatusPage.expectedDateRangeLabelText, - ); - expect(Object.fromEntries(reqUrl!.searchParams.entries())).toMatchObject({ - start_date: targetFrom.toISOString(), - end_date: targetTo.toISOString(), - }); + test.describe("date range", () => { + test("works through calendar", async ({ adminReceiverStatusPage }) => { + const { valueDisplay } = adminReceiverStatusPage.filterFormInputs.dateRange; + const now = new Date(); + const targetFrom = startOfDay(subDays(now, 3)); + const targetTo = addDays(endOfDay(now), 1); + + const reqUrl = await adminReceiverStatusPage.updateFilters({ + dateRange: { + value: [targetFrom, targetTo], + }, + }); + expect(reqUrl).toBeDefined(); + + await expect(valueDisplay).toHaveText(adminReceiverStatusPage.expectedDateRangeLabelText); + expect(Object.fromEntries(reqUrl!.searchParams.entries())).toMatchObject({ + start_date: targetFrom.toISOString(), + end_date: targetTo.toISOString(), + }); + }); + + test("works through textboxes", async ({ adminReceiverStatusPage }) => { + const { valueDisplay } = adminReceiverStatusPage.filterFormInputs.dateRange; + await expect(adminReceiverStatusPage.receiverStatusRowsLocator).not.toHaveCount(0); + const now = new Date(); + const targetFrom = startOfDay(subDays(now, 3)); + const targetTo = addDays(endOfDay(now), 1); + + const reqUrl = await adminReceiverStatusPage.updateFilters({ + dateRange: { + value: [targetFrom, targetTo], + }, }); - test("works through textboxes", async ({ adminReceiverStatusPage }) => { - const { valueDisplay } = adminReceiverStatusPage.filterFormInputs.dateRange; - await expect(adminReceiverStatusPage.receiverStatusRowsLocator).not.toHaveCount(0); - const now = new Date(); - const targetFrom = startOfDay(subDays(now, 3)); - const targetTo = addDays(endOfDay(now), 1); - - const reqUrl = await adminReceiverStatusPage.updateFilters({ - dateRange: { - value: [targetFrom, targetTo], - }, - }); - - expect(reqUrl).toBeDefined(); - - await expect(valueDisplay).toHaveText( - adminReceiverStatusPage.expectedDateRangeLabelText, - ); - expect(Object.fromEntries(reqUrl!.searchParams.entries())).toMatchObject({ - start_date: targetFrom.toISOString(), - end_date: targetTo.toISOString(), - }); + expect(reqUrl).toBeDefined(); + + await expect(valueDisplay).toHaveText(adminReceiverStatusPage.expectedDateRangeLabelText); + expect(Object.fromEntries(reqUrl!.searchParams.entries())).toMatchObject({ + start_date: targetFrom.toISOString(), + end_date: targetTo.toISOString(), }); - }, - ); + }); + }); - // TODO: revisit after filters have been fixed per ticket #15737 - test.skip("receiver name", async ({adminReceiverStatusPage, isMockDisabled}) => { - test.skip(!isMockDisabled, "Mocks are ENABLED, skipping 'receiver name' test"); - const {organizationName, receiverName, successRate} = - adminReceiverStatusPage.timePeriodData[1]; + test("receiver name", async ({ adminReceiverStatusPage }) => { + const { organizationName, receiverName, successRate } = adminReceiverStatusPage.timePeriodData[1]; const receiversStatusRows = adminReceiverStatusPage.receiverStatusRowsLocator; + await expect(receiversStatusRows).toHaveCount(adminReceiverStatusPage.timePeriodData.length); const defaultReceiversStatusRowsCount = await receiversStatusRows.count(); const expectedReceiverStatusRow = receiversStatusRows.nthCustom(0); - const expectedReceiverStatusRowTitle = - adminReceiverStatusPage.getExpectedReceiverStatusRowTitle( - organizationName, - receiverName, - successRate, - ); - - expect(defaultReceiversStatusRowsCount).toBe(adminReceiverStatusPage.timePeriodData.length); + const expectedReceiverStatusRowTitle = adminReceiverStatusPage.getExpectedReceiverStatusRowTitle( + organizationName, + receiverName, + successRate, + ); await adminReceiverStatusPage.updateFilters({ receiverName, @@ -208,82 +192,33 @@ test.describe("Admin Receiver Status Page", expect(defaultReceiversStatusRowsCount).toBe(adminReceiverStatusPage.timePeriodData.length); }); - test.skip("result message", async ({adminReceiverStatusPage, isMockDisabled}) => { - test.skip(!isMockDisabled, "Mocks are ENABLED, skipping 'result message' test"); + test("result message", async ({ adminReceiverStatusPage }) => { // get first entry's result from all-fail receiver's first day -> third time period const receiverI = 0; const dayI = 0; const timePeriodI = 2; const entryI = 0; - const {days} = adminReceiverStatusPage.timePeriodData[receiverI]; - const {connectionCheckResult} = days[dayI].timePeriods[timePeriodI].entries[entryI]; - - const receiversStatusRows = adminReceiverStatusPage.receiverStatusRowsLocator; + const { days } = adminReceiverStatusPage.timePeriodData[receiverI]; + const { connectionCheckResult } = days[dayI].timePeriods[timePeriodI].entries[entryI]; await adminReceiverStatusPage.updateFilters({ resultMessage: connectionCheckResult, }); - for (const [i, {days}] of adminReceiverStatusPage.timePeriodData.entries()) { - const row = receiversStatusRows.nthCustom(i); - - for (const [i, {timePeriods}] of days.entries()) { - const rowDay = row.days.nthCustom(i); - - for (const [i] of timePeriods.entries()) { - const rowDayTimePeriod = rowDay.timePeriods.nth(i); - - await expect(rowDayTimePeriod).toHaveClass(/success-result-hidden/); - } - } - } + await adminReceiverStatusPage.testReceiverStatusDisplay(); await adminReceiverStatusPage.resetFilters(); - // TODO: revisit after filters have been fixed per ticket #15737 - // await adminReceiverStatusPage.testReceiverStatusDisplay(); + await adminReceiverStatusPage.testReceiverStatusDisplay(); }); - test.skip("success type", async ({ adminReceiverStatusPage, isMockDisabled }) => { - test.skip(!isMockDisabled, "Mocks are ENABLED, skipping 'success type' test"); - const [failRow, ,] = adminReceiverStatusPage.timePeriodData; - const failRowTitle = adminReceiverStatusPage.getExpectedReceiverStatusRowTitle( - failRow.organizationName, - failRow.receiverName, - failRow.successRate, - ); - // const mixedRowTitle = adminReceiverStatusPage.getExpectedReceiverStatusRowTitle( - // mixedRow.organizationName, - // mixedRow.receiverName, - // mixedRow.successRate, - // ); - - const receiversStatusRows = adminReceiverStatusPage.receiverStatusRowsLocator; - const defaultReceiversStatusRowsCount = await receiversStatusRows.count(); - const expectedRow = receiversStatusRows.nthCustom(0); - - expect(defaultReceiversStatusRowsCount).toBe(adminReceiverStatusPage.timePeriodData.length); - - await adminReceiverStatusPage.updateFilters({ - successType: "ALL_FAILURE", - }); - let receiversStatusRowsCount = await receiversStatusRows.count(); - - expect(receiversStatusRowsCount).toBeGreaterThanOrEqual(1); - await expect(expectedRow.title).toHaveText(failRowTitle); - - await adminReceiverStatusPage.updateFilters({ - successType: "MIXED_SUCCESS", - }); - receiversStatusRowsCount = await receiversStatusRows.count(); - expect(receiversStatusRowsCount).toBeGreaterThanOrEqual(1); - // TODO: revisit after filters have been fixed per ticket #15737 - // await expect(expectedRow.title).toHaveText(mixedRowTitle); + test("success type", async ({ adminReceiverStatusPage }) => { + const successTypes = [SuccessRate.ALL_FAILURE, SuccessRate.MIXED_SUCCESS, SuccessRate.UNDEFINED]; - // await adminReceiverStatusPage.resetFilters(); - // receiversStatusRowsCount = await receiversStatusRows.count(); - // - // expect(receiversStatusRowsCount).toBe(defaultReceiversStatusRowsCount); + for (const successType of successTypes) { + await adminReceiverStatusPage.updateFilterSuccessType(successType); + await adminReceiverStatusPage.testReceiverStatusDisplay(); + } }); }); @@ -320,7 +255,7 @@ test.describe("Admin Receiver Status Page", }); }); - test.skip("time period modals", async ({ adminReceiverStatusPage }) => { + test("time period modals", async ({ adminReceiverStatusPage }) => { const result = await adminReceiverStatusPage.testReceiverTimePeriodModals(true); expect(result).toBe(true); }); @@ -336,4 +271,5 @@ test.describe("Admin Receiver Status Page", }); }); }); - }); + }, +); diff --git a/frontend-react/src/pages/admin/receiver-dashboard/AdminReceiverDashboardPage/AdminReceiverDashboardPage.tsx b/frontend-react/src/pages/admin/receiver-dashboard/AdminReceiverDashboardPage/AdminReceiverDashboardPage.tsx index 33e5bbba69e..9a132dd5b05 100644 --- a/frontend-react/src/pages/admin/receiver-dashboard/AdminReceiverDashboardPage/AdminReceiverDashboardPage.tsx +++ b/frontend-react/src/pages/admin/receiver-dashboard/AdminReceiverDashboardPage/AdminReceiverDashboardPage.tsx @@ -1,13 +1,4 @@ -import { - GridContainer, - Label, - Modal, - ModalRef, - Select, - SiteAlert, - TextInput, - Tooltip, -} from "@trussworks/react-uswds"; +import { GridContainer, Label, Modal, ModalRef, Select, SiteAlert, TextInput, Tooltip } from "@trussworks/react-uswds"; import { endOfDay, startOfDay, subDays } from "date-fns"; import { useCallback, useMemo, useRef, useState } from "react"; @@ -32,22 +23,16 @@ function AdminReceiverDashboardPage() { end: endOfDay(new Date()), }); - const [startDate, setStartDate] = useState( - defaultDatesRef.current.start, - ); + const [startDate, setStartDate] = useState(defaultDatesRef.current.start); const [endDate, setEndDate] = useState(defaultDatesRef.current.end); // this is the text input box filter const [filterReceiver, setFilterReceiver] = useState(""); const [filterResultMessage, setFilterResultMessage] = useState(""); - const [filterSuccessState, setFilterSuccessState] = useState( - SuccessRate.UNDEFINED, - ); + const [filterSuccessState, setFilterSuccessState] = useState(SuccessRate.UNDEFINED); // used to show hide the modal const modalShowInfoRef = useRef(null); - const [timePeriodStatuses, setTimePeriodStatuses] = useState< - RSReceiverStatusParsed[] - >([]); + const [timePeriodStatuses, setTimePeriodStatuses] = useState([]); const handleTimePeriodClick = useCallback(({ entries }: TimePeriodData) => { setTimePeriodStatuses(entries); @@ -70,28 +55,13 @@ function AdminReceiverDashboardPage() { [endDate, filterResultMessage, results, startDate, timePeriodMinutes], ); - if (data.length === 0) { - return
No Data
; - } - - const filteredData = filterStatuses( - data, - filterReceiver, - filterSuccessState, - ); - - if (filteredData.length === 0) { - return
No data matching filters
; - } + const filteredData = filterStatuses(data, filterReceiver, filterSuccessState); return ( Receiver status dashboard - Admin - + CRON job results that check if receivers are working.
- Each slot is a 2hr time slice. Colored slots had a check - run. Clicking on a slot shows details. + Each slot is a 2hr time slice. Colored slots had a check run. Clicking on a slot shows details. { "Times shown are in YOUR LOCAL timezone. Be aware that receivers and servers may be in different zones." } -
+
-
-
-
-
- - - 0 && ( + + )} + + diff --git a/frontend-react/src/pages/admin/receiver-dashboard/ReceiversStatusesDisplay/ReceiversStatusesDisplay.tsx b/frontend-react/src/pages/admin/receiver-dashboard/ReceiversStatusesDisplay/ReceiversStatusesDisplay.tsx index b2cbb786713..716d0a6cb13 100644 --- a/frontend-react/src/pages/admin/receiver-dashboard/ReceiversStatusesDisplay/ReceiversStatusesDisplay.tsx +++ b/frontend-react/src/pages/admin/receiver-dashboard/ReceiversStatusesDisplay/ReceiversStatusesDisplay.tsx @@ -113,26 +113,19 @@ export interface ReceiversStatusesDisplayProps { * - perday-perslice-column has 4 color states as well * */ -export function ReceiversStatusesDisplay({ - receiverStatuses, - onTimePeriodClick, -}: ReceiversStatusesDisplayProps) { +export function ReceiversStatusesDisplay({ receiverStatuses, onTimePeriodClick }: ReceiversStatusesDisplayProps) { return ( {receiverStatuses.map((d) => ( - +
- + {d.organizationName}
@@ -148,60 +141,37 @@ export function ReceiversStatusesDisplay({ - {d.days.map( - ({ day, dayString, timePeriods }) => { - return ( - - - {dateShortFormat(day)} - - - {timePeriods.map( - (t) => { - return ( - - onTimePeriodClick?.( - t, - ) - } - > - {" "} - - ); - }, - )} - - - ); - }, - )} + {d.days.map(({ day, dayString, timePeriods }) => { + return ( + + + {dateShortFormat(day)} + + + {timePeriods.map((t) => { + return ( + onTimePeriodClick?.(t) + } + > + {" "} + + ); + })} + + + ); + })} diff --git a/frontend-react/src/pages/admin/receiver-dashboard/utils.ts b/frontend-react/src/pages/admin/receiver-dashboard/utils.ts index 4638f09fadc..3aee9572a76 100644 --- a/frontend-react/src/pages/admin/receiver-dashboard/utils.ts +++ b/frontend-react/src/pages/admin/receiver-dashboard/utils.ts @@ -32,11 +32,7 @@ export const MATCHING_FILTER_CLASSNAME_MAP = { * build the dictionary with a special path+key * @param dataIn */ -export const sortStatusData = < - T extends RSReceiverStatus[] | RSReceiverStatusParsed[], ->( - dataIn: T, -): T => { +export const sortStatusData = (dataIn: T): T => { const data = structuredClone(dataIn); const { orgNameMaxLength, receiverNameMaxLength } = data.reduce( (prev, curr) => { @@ -58,23 +54,17 @@ export const sortStatusData = < ); // sorting by organizationName, then receiverName, then connectionCheckStartedAt - data.sort( - ( - d1: RSReceiverStatus | RSReceiverStatusParsed, - d2: RSReceiverStatus | RSReceiverStatusParsed, - ) => { - // ideally the shape of this type will change so that all receivers, regardless if any status data was found, will get sorted - const [sortStrA, sortStrB] = [d1, d2].map( - (x) => - `${x.organizationName.padEnd(orgNameMaxLength, "-")}${x.receiverName.padEnd(receiverNameMaxLength, "-")}${new Date(x.connectionCheckStartedAt || Date.now()).toISOString()}`, - ); + data.sort((d1: RSReceiverStatus | RSReceiverStatusParsed, d2: RSReceiverStatus | RSReceiverStatusParsed) => { + // ideally the shape of this type will change so that all receivers, regardless if any status data was found, will get sorted + const [sortStrA, sortStrB] = [d1, d2].map( + (x) => + `${x.organizationName.padEnd(orgNameMaxLength, "-")}${x.receiverName.padEnd(receiverNameMaxLength, "-")}${new Date(x.connectionCheckStartedAt || Date.now()).toISOString()}`, + ); - const result = - sortStrA > sortStrB ? 1 : sortStrA < sortStrB ? -1 : 0; + const result = sortStrA > sortStrB ? 1 : sortStrA < sortStrB ? -1 : 0; - return result; - }, - ); + return result; + }); return data; }; @@ -103,33 +93,24 @@ export function createStatusTimePeriodData({ }): ReceiverStatusTimePeriod[] { const inter = interval(startDate, endDate, { assertPositive: true }); const numTimePeriodsPerDay = (24 * 60) / timePeriodMinutes; - if (numTimePeriodsPerDay % 1 !== 0) - throw new Error("Invalid time period duration"); + if (numTimePeriodsPerDay % 1 !== 0) throw new Error("Invalid time period duration"); - const timePeriodLabels = Array.from(Array(numTimePeriodsPerDay).keys()).map( - (_, i) => - addMinutes( - startDate, - (i + 1) * timePeriodMinutes, - ).toLocaleTimeString(), + const timePeriodLabels = Array.from(Array(numTimePeriodsPerDay).keys()).map((_, i) => + addMinutes(startDate, (i + 1) * timePeriodMinutes).toLocaleTimeString(), ); const sortedData = sortStatusData(data).map((d) => ({ ...d, connectionCheckCompletedAt: new Date(d.connectionCheckCompletedAt), connectionCheckStartedAt: new Date(d.connectionCheckStartedAt), })); - const receiverIds = Array.from( - new Set(sortedData.map((d) => d.receiverId)), - ); + const receiverIds = Array.from(new Set(sortedData.map((d) => d.receiverId))); return receiverIds.map((id) => { const entries = sortedData.filter((d) => d.receiverId === id); const { organizationName, receiverName } = entries[0]; const days = eachDayOfInterval(inter).map((day) => { const dayEntries = entries.filter( - (e) => - e.connectionCheckCompletedAt.toLocaleDateString() === - day.toLocaleDateString(), + (e) => e.connectionCheckCompletedAt.toLocaleDateString() === day.toLocaleDateString(), ); const dayString = day.toLocaleDateString(); const timePeriods = timePeriodLabels.map((time) => { @@ -137,26 +118,18 @@ export function createStatusTimePeriodData({ const end = addMinutes(start, timePeriodMinutes); const timePeriodEntries = dayEntries.filter((e) => { - return ( - e.connectionCheckCompletedAt >= start && - e.connectionCheckCompletedAt < end - ); + return e.connectionCheckCompletedAt >= start && e.connectionCheckCompletedAt < end; }); const agg = timePeriodEntries.reduce( - ( - agg, - { connectionCheckSuccessful, connectionCheckResult }, - ) => { + (agg, { connectionCheckSuccessful, connectionCheckResult }) => { if (connectionCheckSuccessful) agg.success += 1; else { agg.fail += 1; - if ( - connectionCheckResult - .toLowerCase() - .includes(filterResultMessage.toLowerCase()) - ) { - agg.isResultFilterMatch = true; - } + if (!agg.isResultFilterMatch) + agg.isResultFilterMatch = isConnectionResultMatch( + connectionCheckResult, + filterResultMessage, + ); } return agg; }, @@ -188,6 +161,7 @@ export function createStatusTimePeriodData({ successRateType, matchingFilter, entries: timePeriodEntries, + q: filterResultMessage, }; }); return { @@ -208,10 +182,7 @@ export function createStatusTimePeriodData({ }, { success: 0, fail: 0 }, ); - const successRate = - !!success || !!fail - ? Math.round((100 * success) / (success + fail)) - : 0; + const successRate = !!success || !!fail ? Math.round((100 * success) / (success + fail)) : 0; const successRateType = !success && !fail ? SuccessRate.UNDEFINED @@ -270,12 +241,14 @@ export function filterStatuses( ) { return statuses.filter(({ receiverName, successRateType }) => { const result = - (!receiverNameLike || - receiverName.toLowerCase().includes(receiverNameLike)) && - (!successRateLike || - successRateLike === SuccessRate.UNDEFINED || - successRateType === successRateLike); + (!receiverNameLike || receiverName.toLowerCase().includes(receiverNameLike)) && + (!successRateLike || successRateLike === SuccessRate.UNDEFINED || successRateType === successRateLike); return result; }); } + +export function isConnectionResultMatch(result: string, query: string) { + if (query === "") return true; + return result.toLowerCase().includes(query.toLowerCase()); +}