diff --git a/CHANGELOG.md b/CHANGELOG.md index 1059cf2dda..352afc3b25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated wording throughout plugin to use 'Alert Group' instead of 'Incident' ([1565](https://github.com/grafana/oncall/pull/1565), [1576](https://github.com/grafana/oncall/pull/1576)) - Filtering for Editors/Admins was added to rotation form. It is not allowed to assign Viewer to rotation ([1124](https://github.com/grafana/oncall/issues/1124)) +- Modified search behaviour on the Escalation Chains page to allow for "partial searching" ([1578](https://github.com/grafana/oncall/pull/1578)) ### Fixed diff --git a/engine/apps/api/views/escalation_chain.py b/engine/apps/api/views/escalation_chain.py index 81cd1ecbef..7cbc1f9348 100644 --- a/engine/apps/api/views/escalation_chain.py +++ b/engine/apps/api/views/escalation_chain.py @@ -46,7 +46,7 @@ class EscalationChainViewSet( } filter_backends = [SearchFilter] - search_fields = ("^name",) + search_fields = ("name",) serializer_class = EscalationChainSerializer list_serializer_class = EscalationChainListSerializer diff --git a/grafana-plugin/integration-tests/escalationChains/searching.test.ts b/grafana-plugin/integration-tests/escalationChains/searching.test.ts new file mode 100644 index 0000000000..e9eaba5eac --- /dev/null +++ b/grafana-plugin/integration-tests/escalationChains/searching.test.ts @@ -0,0 +1,36 @@ +import { test, expect, Page } from '@playwright/test'; +import { configureOnCallPlugin } from '../utils/configurePlugin'; +import { generateRandomValue } from '../utils/forms'; +import { createEscalationChain } from '../utils/escalationChain'; + +test.beforeEach(async ({ page }) => { + await configureOnCallPlugin(page); +}); + +const assertEscalationChainSearchWorks = async ( + page: Page, + searchTerm: string, + escalationChainFullName: string +): Promise => { + await page.getByTestId('escalation-chain-search-input').fill(searchTerm); + + // wait for the API call(s) to finish + await page.waitForLoadState('networkidle'); + + await expect(page.getByTestId('escalation-chains-list')).toHaveText(escalationChainFullName); +}; + +test('searching allows case-insensitive partial matches', async ({ page }) => { + const escalationChainName = `${generateRandomValue()} ${generateRandomValue()}`; + const [firstHalf, secondHalf] = escalationChainName.split(' '); + + await createEscalationChain(page, escalationChainName); + + await assertEscalationChainSearchWorks(page, firstHalf, escalationChainName); + await assertEscalationChainSearchWorks(page, firstHalf.toUpperCase(), escalationChainName); + await assertEscalationChainSearchWorks(page, firstHalf.toLowerCase(), escalationChainName); + + await assertEscalationChainSearchWorks(page, secondHalf, escalationChainName); + await assertEscalationChainSearchWorks(page, secondHalf.toUpperCase(), escalationChainName); + await assertEscalationChainSearchWorks(page, secondHalf.toLowerCase(), escalationChainName); +}); diff --git a/grafana-plugin/integration-tests/utils/alertGroup.ts b/grafana-plugin/integration-tests/utils/alertGroup.ts index f729f1a797..7f9b39fc18 100644 --- a/grafana-plugin/integration-tests/utils/alertGroup.ts +++ b/grafana-plugin/integration-tests/utils/alertGroup.ts @@ -15,7 +15,7 @@ const incidentTimelineContainsStep = async (page: Page, triggeredStepText: strin return Promise.resolve(false); } - if (!page.locator('div[data-testid="incident-timeline-list"]').getByText(triggeredStepText)) { + if (!page.getByTestId('incident-timeline-list').getByText(triggeredStepText)) { await page.reload({ waitUntil: 'networkidle' }); return incidentTimelineContainsStep(page, triggeredStepText, (retryNum += 1)); } diff --git a/grafana-plugin/integration-tests/utils/escalationChain.ts b/grafana-plugin/integration-tests/utils/escalationChain.ts index 3a4263ce56..f2bec76683 100644 --- a/grafana-plugin/integration-tests/utils/escalationChain.ts +++ b/grafana-plugin/integration-tests/utils/escalationChain.ts @@ -16,8 +16,8 @@ const escalationStepValuePlaceholder: Record = { export const createEscalationChain = async ( page: Page, escalationChainName: string, - escalationStep: EscalationStep | null, - escalationStepValue: string | null + escalationStep?: EscalationStep, + escalationStepValue?: string ): Promise => { // go to the escalation chains page await goToOnCallPage(page, 'escalations'); @@ -32,7 +32,7 @@ export const createEscalationChain = async ( await clickButton({ page, buttonText: 'Create' }); await page.waitForSelector(`text=${escalationChainName}`); - if (!escalationStep) { + if (!escalationStep || !escalationStepValue) { return; } diff --git a/grafana-plugin/integration-tests/utils/integrations.ts b/grafana-plugin/integration-tests/utils/integrations.ts index eb93ceff69..664fcd7943 100644 --- a/grafana-plugin/integration-tests/utils/integrations.ts +++ b/grafana-plugin/integration-tests/utils/integrations.ts @@ -24,7 +24,7 @@ export const createIntegrationAndSendDemoAlert = async ( await fillInInput(page, 'div[data-testid="edit-integration-name-modal"] >> input', integrationName); await clickButton({ page, buttonText: 'Update' }); - const integrationSettingsElement = page.locator('div[data-testid="integration-settings"]'); + const integrationSettingsElement = page.getByTestId('integration-settings'); // assign the escalation chain to the integration await selectDropdownValue({ diff --git a/grafana-plugin/src/components/EscalationsFilters/EscalationsFilters.tsx b/grafana-plugin/src/components/EscalationsFilters/EscalationsFilters.tsx index bcbf313448..f2387261c3 100644 --- a/grafana-plugin/src/components/EscalationsFilters/EscalationsFilters.tsx +++ b/grafana-plugin/src/components/EscalationsFilters/EscalationsFilters.tsx @@ -39,6 +39,7 @@ const EscalationsFilters: FC = (props) => {
} placeholder="Search escalations..." diff --git a/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx b/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx index 729da47865..fb9b0cd7f6 100644 --- a/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx +++ b/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx @@ -175,7 +175,7 @@ class EscalationChainsPage extends React.Component )} -
+
{searchResult ? (