diff --git a/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.spec.ts b/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.spec.ts index cb55e8af3..6010adc46 100644 --- a/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.spec.ts +++ b/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.spec.ts @@ -90,17 +90,17 @@ describe("DetectedListView tests", () => { describe("filtering scenarios", () => { function getFilterNameElement() { - return screen.getByRole("searchbox", { name: /Filter by name/i }) as HTMLTextAreaElement; - } - - function getFilterNameTypeElement() { - return screen.getByRole("combobox", { name: /Filter name type/i }) as HTMLSelectElement; + return screen.getByRole("searchbox", { name: /Filter by name/i }) as HTMLInputElement; } function getFilterUnsetCheckboxElement() { return screen.getByRole("checkbox", { name: /Show only not set Endpoint Types/i }) as HTMLInputElement; } + function waitForDebounce(ms: number = 1000) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + test("by name", async () => { await renderComponent({ source: DataSource.WellKnownEndpoint }, async (driver) => { await driver.setUp( @@ -114,28 +114,28 @@ describe("DetectedListView tests", () => { const user = userEvent.setup(); const filterNameElement = getFilterNameElement(); - await user.type(filterNameElement, "Alpha"); + await user.type(filterNameElement, "Alpha*"); + await waitForDebounce(); expect(screen.queryAllByText(/Alpha\d/i).length).toBe(10); expect(screen.queryAllByText(/\dBeta/i).length).toBe(0); expect(screen.queryAllByText(/\dDelta\d/i).length).toBe(0); - - const filterNameTypeElement = getFilterNameTypeElement(); - await user.selectOptions(filterNameTypeElement, "Ends with"); await user.clear(filterNameElement); - await user.type(filterNameElement, "Beta"); + await user.type(filterNameElement, "*Beta"); + await waitForDebounce(); expect(screen.queryAllByText(/\dBeta/i).length).toBe(10); expect(screen.queryAllByText(/Alpha\d/i).length).toBe(0); expect(screen.queryAllByText(/\dDelta\d/i).length).toBe(0); - - await user.selectOptions(filterNameTypeElement, "Contains"); await user.clear(filterNameElement); - await user.type(filterNameElement, "Delta"); + await user.type(filterNameElement, "*Delta*"); + await waitForDebounce(); expect(screen.queryAllByText(/\dDelta\d/i).length).toBe(10); expect(screen.queryAllByText(/\dBeta/i).length).toBe(0); expect(screen.queryAllByText(/Alpha\d/i).length).toBe(0); + expect(screen.queryAllByText(/\dBeta/i).length).toBe(0); + expect(screen.queryAllByText(/Alpha\d/i).length).toBe(0); }); test("by unset only", async () => { @@ -176,9 +176,7 @@ describe("DetectedListView tests", () => { const filterCheckboxElement = getFilterUnsetCheckboxElement(); await user.click(filterCheckboxElement); - const filterNameTypeElement = getFilterNameTypeElement(); const filterNameElement = getFilterNameElement(); - await user.selectOptions(filterNameTypeElement, "Begins with"); await user.clear(filterNameElement); await user.type(filterNameElement, "boo"); diff --git a/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.vue b/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.vue index 18e77c09f..010677730 100644 --- a/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.vue +++ b/src/Frontend/src/views/throughputreport/endpoints/DetectedListView.vue @@ -14,13 +14,8 @@ import ResultsCount from "@/components/ResultsCount.vue"; import { useHiddenFeature } from "./useHiddenFeature"; import { license } from "@/composables/serviceLicense"; import FAIcon from "@/components/FAIcon.vue"; -import { faInfoCircle } from "@fortawesome/free-solid-svg-icons"; - -enum NameFilterType { - beginsWith = "Begins with", - contains = "Contains", - endsWith = "Ends with", -} +import { faInfoCircle, faAsterisk } from "@fortawesome/free-solid-svg-icons"; +import FilterInput from "@/components/FilterInput.vue"; interface SortData { text: string; @@ -51,17 +46,19 @@ const props = defineProps(); const data = ref([]); const dataChanges = ref(new Map()); -const filterData = reactive({ name: "", nameFilterType: NameFilterType.beginsWith, sort: "name", showUnsetOnly: false }); -const filterNameOptions = [ - { text: NameFilterType.beginsWith, filter: (a: EndpointThroughputSummary) => a.name.toLowerCase().startsWith(filterData.name.toLowerCase()) }, - { text: NameFilterType.contains, filter: (a: EndpointThroughputSummary) => a.name.toLowerCase().includes(filterData.name.toLowerCase()) }, - { text: NameFilterType.endsWith, filter: (a: EndpointThroughputSummary) => a.name.toLowerCase().endsWith(filterData.name.toLowerCase()) }, -]; +const filterData = reactive({ name: "", sort: "name", showUnsetOnly: false }); + const filteredData = computed(() => { const sortItem = sortData.find((value) => value.value === filterData.sort); return data.value - .filter((row) => !row.name || filterNameOptions.find((v) => v.text === filterData.nameFilterType)?.filter(row)) + .filter((row) => { + if (!filterData.name) return true; + // Escape regex special chars except * + const escaped = filterData.name.replace(/[-[\]/{}()+?.\\^$|]/g, "\\$&").replace(/\*/g, ".*"); + const regex = new RegExp(`^${escaped}$`, "i"); + return regex.test(row.name); + }) .filter((row) => { if (filterData.showUnsetOnly) { return dataChanges.value.get(row.name)?.indicator === ""; @@ -103,18 +100,10 @@ async function loadData() { data.value = results.filter((row) => row.is_known_endpoint === (props.source === DataSource.WellKnownEndpoint)); } -function nameFilterChanged(event: Event) { - filterData.name = (event.target as HTMLInputElement).value; -} - function sortChanged(item: Item) { filterData.sort = item.value; } -function searchTypeChanged(event: Event) { - filterData.nameFilterType = (event.target as HTMLInputElement).value as NameFilterType; -} - function updateIndicator(event: Event, name: string) { const value = (event.target as HTMLSelectElement).value; updateDataChanged(name, (item) => (item.indicator = value)); @@ -173,19 +162,17 @@ async function save() {
-
- -
-
- - + +
+ Use as a wildcard. E.g.: PRD_ or _PRD or _PRD_
-
-
+
+
@@ -259,17 +246,13 @@ async function save() { .formatThroughputColumn { padding-right: 20px; } -.format-text { - font-weight: unset; - font-size: 14px; - min-width: 120px; -} .text-search-container { - display: flex; - flex-direction: row; + width: 25rem; } -.text-search { - width: 130px; +.middle-column { + align-content: center; + display: flex; + padding-top: 5px; } .endpointType { width: 340px;