Skip to content

Commit

Permalink
feat(QuickFilter): Add results count (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
grafakus authored Sep 27, 2024
1 parent 2d87a4f commit dc4012d
Show file tree
Hide file tree
Showing 29 changed files with 89 additions and 19 deletions.
7 changes: 6 additions & 1 deletion e2e/fixtures/pages/ExploreProfilesPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,21 @@ export class ExploreProfilesPage extends PyroscopePage {
return this.getByLabel('Quick filter');
}

async assertQuickFilter(explectedPlaceholder: string, expectedValue: string) {
async assertQuickFilter(explectedPlaceholder: string, expectedValue: string, expectedResultsCount: number) {
await expect(await this.getQuickFilterInput().getAttribute('placeholder')).toBe(explectedPlaceholder);
await expect(this.getQuickFilterInput()).toHaveValue(expectedValue);
await this.assertQuickFilterResultsCount(expectedResultsCount);
}

async enterQuickFilterText(searchText: string) {
await this.getQuickFilterInput().fill(searchText);
await this.waitForTimeout(250); // see SceneQuickFilter.DEBOUNCE_DELAY
}

async assertQuickFilterResultsCount(expectedCount: number) {
await expect(this.getByTestId('quick-filter-results-count')).toHaveText(String(expectedCount));
}

/* Layout switcher */

getLayoutSwitcher() {
Expand Down
6 changes: 5 additions & 1 deletion e2e/tests/all-services-view/all-services.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test.describe('All services view', () => {

// body scene controls
await exploreProfilesPage.assertSelectedProfileType('process_cpu/cpu');
await exploreProfilesPage.assertQuickFilter('Search services (comma-separated regexes are supported)', '');
await exploreProfilesPage.assertQuickFilter('Search services (comma-separated regexes are supported)', '', 3);
await exploreProfilesPage.assertSelectedLayout('Grid');

// body
Expand Down Expand Up @@ -53,8 +53,12 @@ test.describe('All services view', () => {
});

test('Quick filter', async ({ exploreProfilesPage }) => {
await exploreProfilesPage.assertQuickFilterResultsCount(3);

await exploreProfilesPage.enterQuickFilterText('sharing,load');

await exploreProfilesPage.assertQuickFilterResultsCount(2);

await expect(exploreProfilesPage.getPanels()).toHaveCount(2);
await expect(exploreProfilesPage.getPanelByTitle('load-generator')).toBeVisible();
await expect(exploreProfilesPage.getPanelByTitle('ride-sharing-app')).toBeVisible();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion e2e/tests/favorites-view/favorites-view.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test.describe('Favorites view', () => {
await exploreProfilesPage.assertSelectedTimeRange('2024-03-13 19:00:00 to 2024-03-13 19:50:00');

// body scene controls
await exploreProfilesPage.assertQuickFilter('Search favorites (comma-separated regexes are supported)', '');
await exploreProfilesPage.assertQuickFilter('Search favorites (comma-separated regexes are supported)', '', 4);
await exploreProfilesPage.assertSelectedLayout('Grid');
await exploreProfilesPage.assertHideNoDataSwitcher(false);

Expand All @@ -38,8 +38,12 @@ test.describe('Favorites view', () => {
});

test('Quick filter', async ({ exploreProfilesPage }) => {
await exploreProfilesPage.assertQuickFilterResultsCount(4);

await exploreProfilesPage.enterQuickFilterText('load,ride');

await exploreProfilesPage.assertQuickFilterResultsCount(3);

await expect(exploreProfilesPage.getPanels()).toHaveCount(3);
await expect(exploreProfilesPage.getPanelByTitle('load-generator · cpu (process_cpu)')).toBeVisible();
await expect(exploreProfilesPage.getPanelByTitle('ride-sharing-app · inuse_space (memory)')).toBeVisible();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion e2e/tests/labels-view/labels.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test.describe('Labels view', () => {
await exploreProfilesPage.assertSelectedService('ride-sharing-app');
await exploreProfilesPage.assertSelectedProfileType('process_cpu/cpu');
await exploreProfilesPage.assertFilters([]);
await exploreProfilesPage.assertQuickFilter('Search labels (comma-separated regexes are supported)', '');
await exploreProfilesPage.assertQuickFilter('Search labels (comma-separated regexes are supported)', '', 7);
await exploreProfilesPage.assertSelectedPanelType('Time series');
await exploreProfilesPage.assertSelectedLayout('Grid');
await exploreProfilesPage.assertHideNoDataSwitcher(false);
Expand Down Expand Up @@ -153,8 +153,12 @@ test.describe('Labels view', () => {
});

test('Quick filter', async ({ exploreProfilesPage }) => {
await exploreProfilesPage.assertQuickFilterResultsCount(3);

await exploreProfilesPage.enterQuickFilterText('us-east');

await exploreProfilesPage.assertQuickFilterResultsCount(1);

await expect(exploreProfilesPage.getGroupByPanels()).toHaveCount(1);
await expect(exploreProfilesPage.getPanelByTitle('us-east')).toBeVisible();
});
Expand Down Expand Up @@ -229,8 +233,12 @@ test.describe('Labels view', () => {
});

test('Quick filter', async ({ exploreProfilesPage }) => {
await exploreProfilesPage.assertQuickFilterResultsCount(7);

await exploreProfilesPage.enterQuickFilterText('region,vehicle');

await exploreProfilesPage.assertQuickFilterResultsCount(2);

await expect(exploreProfilesPage.getGroupByPanels()).toHaveCount(2);
await expect(exploreProfilesPage.getPanelByTitle('region (3)')).toBeVisible();
await expect(exploreProfilesPage.getPanelByTitle('vehicle (4)')).toBeVisible();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion e2e/tests/profile-types-view/profile-types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ async function assertMainUiElements(exploreProfilesPage: ExploreProfilesPage) {

// body scene controls
await exploreProfilesPage.assertSelectedService('ride-sharing-app');
await exploreProfilesPage.assertQuickFilter('Search profile types (comma-separated regexes are supported)', '');
await exploreProfilesPage.assertQuickFilter('Search profile types (comma-separated regexes are supported)', '', 6);
await exploreProfilesPage.assertSelectedLayout('Grid');
}

Expand All @@ -37,8 +37,12 @@ test.describe('Profile types view', () => {
});

test('Quick filter', async ({ exploreProfilesPage }) => {
await exploreProfilesPage.assertQuickFilterResultsCount(6);

await exploreProfilesPage.enterQuickFilterText('samples,alloc_space');

await exploreProfilesPage.assertQuickFilterResultsCount(2);

await expect(exploreProfilesPage.getPanels()).toHaveCount(2);
await expect(exploreProfilesPage.getPanelByTitle('samples (process_cpu)')).toBeVisible();
await expect(exploreProfilesPage.getPanelByTitle('alloc_space (memory)')).toBeVisible();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ export class SceneByVariableRepeaterGrid extends SceneObjectBase<SceneByVariable
subscribeToQuickFilterChange() {
const quickFilter = sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter);

this.subscribeToState((newState, prevState) => {
if (newState.items.length !== prevState.items.length) {
quickFilter.setResultsCount(newState.items.length);
}
});

const onChangeState = (newState: SceneQuickFilterState, prevState?: SceneQuickFilterState) => {
if (newState.searchText !== prevState?.searchText) {
this.renderGridItems();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import {
SceneComponentProps,
SceneObjectBase,
SceneObjectState,
SceneObjectUrlSyncConfig,
SceneObjectUrlValues,
} from '@grafana/scenes';
import { Icon, IconButton, Input, useStyles2 } from '@grafana/ui';
import { Icon, IconButton, Input, Tag, useStyles2 } from '@grafana/ui';
import { reportInteraction } from '@shared/domain/reportInteraction';
import React from 'react';

export interface SceneQuickFilterState extends SceneObjectState {
placeholder: string;
searchText: string;
onChange?: (searchText: string) => void;
resultsCount: string;
}

export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {
Expand All @@ -28,13 +30,18 @@ export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {
key: 'quick-filter',
placeholder,
searchText: SceneQuickFilter.DEFAULT_SEARCH_TEXT,
resultsCount: '',
});
}

setPlaceholder(placeholder: string) {
this.setState({ placeholder });
}

setResultsCount(resultsCount: number) {
this.setState({ resultsCount: String(resultsCount) });
}

getUrlState() {
return {
searchText: this.state.searchText,
Expand All @@ -55,7 +62,11 @@ export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {
this.setState({ searchText: e.target.value });
};

clear = () => {
reset() {
this.setState({ placeholder: '', searchText: '', resultsCount: '' });
}

clearSearchText = () => {
this.setState({ searchText: '' });
};

Expand All @@ -65,7 +76,7 @@ export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {

static Component = ({ model }: SceneComponentProps<SceneQuickFilter>) => {
const styles = useStyles2(getStyles);
const { placeholder, searchText } = model.useState();
const { placeholder, searchText, resultsCount } = model.useState();

return (
<div className={styles.filter}>
Expand All @@ -75,11 +86,23 @@ export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {
placeholder={placeholder}
value={searchText}
prefix={<Icon name="search" />}
suffix={<IconButton name="times" aria-label="Clear search" onClick={model.clear} />}
suffix={
<>
{resultsCount !== '' && (
<Tag
className={styles.resultsCount}
name={resultsCount}
colorIndex={9}
data-testid="quick-filter-results-count"
/>
)}
<IconButton name="times" aria-label="Clear search" onClick={model.clearSearchText} />
</>
}
onChange={model.onChange}
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Escape') {
model.clear();
model.clearSearchText();
}
}}
onFocus={model.onFocus}
Expand All @@ -89,9 +112,16 @@ export class SceneQuickFilter extends SceneObjectBase<SceneQuickFilterState> {
};
}

const getStyles = () => ({
const getStyles = (theme: GrafanaTheme2) => ({
filter: css`
flex: 1;
min-width: 112px;
`,
resultsCount: css`
margin-right: ${theme.spacing(1)};
border-radius: 11px;
padding: 2px 8px;
color: ${theme.colors.text.primary};
background-color: ${theme.colors.background.secondary};
`,
});
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ export class SceneExploreAllServices extends SceneObjectBase<SceneExploreAllServ
}

onActivate() {
const quickFilter = sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter);
quickFilter.setPlaceholder('Search services (comma-separated regexes are supported)');
sceneGraph
.findByKeyAndType(this, 'quick-filter', SceneQuickFilter)
.setPlaceholder('Search services (comma-separated regexes are supported)');
}

// see SceneProfilesExplorer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ export class SceneExploreFavorites extends SceneObjectBase<SceneExploreFavorites
}

onActivate() {
const quickFilter = sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter);
quickFilter.setPlaceholder('Search favorites (comma-separated regexes are supported)');
sceneGraph
.findByKeyAndType(this, 'quick-filter', SceneQuickFilter)
.setPlaceholder('Search favorites (comma-separated regexes are supported)');

const expandPanelSub = this.subscribeToEvent(EventExpandPanel, async (event) => {
this.openExpandedPanelDrawer(event.payload.item);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class SceneGroupByLabels extends SceneObjectBase<SceneGroupByLabelsState>

return groupByVariable.subscribeToState((newState, prevState) => {
if (newState.value !== prevState?.value) {
quickFilter.clear();
quickFilter.clearSearchText();

this.renderBody(newState);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ export class SceneLabelValuesGrid extends SceneObjectBase<SceneLabelValuesGridSt
subscribeToQuickFilterChange() {
const quickFilter = sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter);

this.subscribeToState((newState, prevState) => {
if (newState.items.length !== prevState.items.length) {
quickFilter.setResultsCount(newState.items.length);
}
});

const onChangeState = (newState: SceneQuickFilterState, prevState?: SceneQuickFilterState) => {
if (newState.searchText !== prevState?.searchText) {
this.renderGridItems();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ export class SceneExploreServiceProfileTypes extends SceneObjectBase<SceneExplor
}

onActivate(item?: GridItemData) {
const quickFilter = sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter);
quickFilter.setPlaceholder('Search profile types (comma-separated regexes are supported)');
sceneGraph
.findByKeyAndType(this, 'quick-filter', SceneQuickFilter)
.setPlaceholder('Search profile types (comma-separated regexes are supported)');

if (item) {
this.initVariables(item);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ export class SceneProfilesExplorer extends SceneObjectBase<SceneProfilesExplorer
}

resetVariables(nextExplorationType: string) {
sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter).clear();
sceneGraph.findByKeyAndType(this, 'quick-filter', SceneQuickFilter).reset();
sceneGraph.findByKeyAndType(this, 'groupBy', GroupByVariable).changeValueTo(GroupByVariable.DEFAULT_VALUE);
sceneGraph.findByKeyAndType(this, 'panel-type-switcher', ScenePanelTypeSwitcher).reset();

Expand Down

1 comment on commit dc4012d

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unit test coverage

Lines Statements Branches Functions
Coverage: 10%
10.74% (416/3873) 8.58% (115/1340) 8.25% (101/1224)

Please sign in to comment.