From dbfbc2329b59bf2497cc41e9bc2239642b6f8699 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Fri, 29 May 2026 16:38:09 +0200 Subject: [PATCH 1/5] feat(inbound-filters): add v2 page skeleton --- .../project/projectFilters/index.spec.tsx | 33 ++++++++++++++++ .../settings/project/projectFilters/index.tsx | 39 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/static/app/views/settings/project/projectFilters/index.spec.tsx b/static/app/views/settings/project/projectFilters/index.spec.tsx index 7c6551a4afe22d..54d68d1002310c 100644 --- a/static/app/views/settings/project/projectFilters/index.spec.tsx +++ b/static/app/views/settings/project/projectFilters/index.spec.tsx @@ -342,6 +342,39 @@ describe('ProjectFilters', () => { ); }); + it('shows inbound filters v2 tab between data filters and discarded issues', () => { + const organizationWithFlag = OrganizationFixture({ + ...organization, + features: ['inbound-filters-v2'], + }); + const projectWithDiscardGroups = ProjectFixture({ + ...project, + features: ['discard-groups'], + }); + + render(, { + organization: organizationWithFlag, + outletContext: {project: projectWithDiscardGroups}, + initialRouterConfig: { + location: { + pathname: `/settings/${organizationWithFlag.slug}/projects/${projectWithDiscardGroups.slug}/filters/inbound-filters/`, + }, + route: '/settings/:orgId/projects/:projectId/filters/:filterType/', + }, + }); + + expect(screen.getAllByRole('tab').map(tab => tab.textContent)).toEqual([ + 'Data Filters', + 'Inbound Filters', + 'Discarded Issues', + ]); + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getByRole('columnheader', {name: 'Filter'})).toBeInTheDocument(); + expect(screen.getByRole('columnheader', {name: 'Status'})).toBeInTheDocument(); + expect(screen.getByRole('columnheader', {name: 'Action'})).toBeInTheDocument(); + expect(screen.getByText('No inbound filters found')).toBeInTheDocument(); + }); + it('disables configuration for non project:write users', async () => { render(, { organization: OrganizationFixture({access: []}), diff --git a/static/app/views/settings/project/projectFilters/index.tsx b/static/app/views/settings/project/projectFilters/index.tsx index 8a76b23487ffc6..14a11165e43c62 100644 --- a/static/app/views/settings/project/projectFilters/index.tsx +++ b/static/app/views/settings/project/projectFilters/index.tsx @@ -4,8 +4,10 @@ import styled from '@emotion/styled'; import {TabList, Tabs} from '@sentry/scraps/tabs'; import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle'; +import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {t} from 'sentry/locale'; import {recreateRoute} from 'sentry/utils/recreateRoute'; +import {useOrganization} from 'sentry/utils/useOrganization'; import {useParams} from 'sentry/utils/useParams'; import {useRoutes} from 'sentry/utils/useRoutes'; import {SettingsPageHeader} from 'sentry/views/settings/components/settingsPageHeader'; @@ -20,12 +22,16 @@ export default function ProjectFilters() { const params = useParams<{filterType: string; projectId: string}>(); const {projectId, filterType} = params; const {project} = useProjectSettingsOutlet(); + const organization = useOrganization(); if (!project) { return null; } const features = new Set(project.features); + const hasInboundFiltersV2 = organization.features.includes('inbound-filters-v2'); + const hasDiscardGroups = features.has('discard-groups'); + const showTabs = hasDiscardGroups || hasInboundFiltersV2; return ( @@ -42,7 +48,7 @@ export default function ProjectFilters() {
- {features.has('discard-groups') && ( + {showTabs && ( @@ -52,8 +58,20 @@ export default function ProjectFilters() { > {t('Data Filters')} + Date: Fri, 29 May 2026 16:45:02 +0200 Subject: [PATCH 3/5] wip --- .../settings/project/projectFilters/index.spec.tsx | 13 ++++++++++--- .../views/settings/project/projectFilters/index.tsx | 11 ++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/static/app/views/settings/project/projectFilters/index.spec.tsx b/static/app/views/settings/project/projectFilters/index.spec.tsx index 1040cbb8dcea9e..bd8e4e795cc030 100644 --- a/static/app/views/settings/project/projectFilters/index.spec.tsx +++ b/static/app/views/settings/project/projectFilters/index.spec.tsx @@ -369,9 +369,16 @@ describe('ProjectFilters', () => { 'Discarded Issues', ]); expect(screen.getByRole('table')).toBeInTheDocument(); - expect(screen.getByRole('columnheader', {name: 'Filter'})).toBeInTheDocument(); - expect(screen.getByRole('columnheader', {name: 'Status'})).toBeInTheDocument(); - expect(screen.getByRole('columnheader', {name: 'Action'})).toBeInTheDocument(); + for (const column of [ + 'Active', + 'Name', + 'Conditions', + 'Created', + 'Edited', + 'Action', + ]) { + expect(screen.getByRole('columnheader', {name: column})).toBeInTheDocument(); + } expect(screen.getByText('No inbound filters found')).toBeInTheDocument(); }); diff --git a/static/app/views/settings/project/projectFilters/index.tsx b/static/app/views/settings/project/projectFilters/index.tsx index 2bb75c77bf00b1..7e5c04ad446afe 100644 --- a/static/app/views/settings/project/projectFilters/index.tsx +++ b/static/app/views/settings/project/projectFilters/index.tsx @@ -97,8 +97,11 @@ function InboundFiltersV2() { return ( - {t('Filter')} - {t('Status')} + {t('Active')} + {t('Name')} + {t('Conditions')} + {t('Created')} + {t('Edited')} {t('Action')} {t('No inbound filters found')} @@ -111,5 +114,7 @@ const TabsContainer = styled('div')` `; const InboundFiltersV2Table = styled(SimpleTable)` - grid-template-columns: minmax(0, 1fr) max-content max-content; + grid-template-columns: + max-content minmax(0, 1fr) minmax(0, 2fr) max-content max-content + max-content; `; From 7f133025e9b00664d518e4cf352c739d881fd1dd Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Fri, 29 May 2026 16:55:28 +0200 Subject: [PATCH 4/5] remove dividers --- .../views/settings/project/projectFilters/index.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/static/app/views/settings/project/projectFilters/index.tsx b/static/app/views/settings/project/projectFilters/index.tsx index 7e5c04ad446afe..5020f97c1b4793 100644 --- a/static/app/views/settings/project/projectFilters/index.tsx +++ b/static/app/views/settings/project/projectFilters/index.tsx @@ -97,12 +97,12 @@ function InboundFiltersV2() { return ( - {t('Active')} - {t('Name')} - {t('Conditions')} - {t('Created')} - {t('Edited')} - {t('Action')} + {t('Active')} + {t('Name')} + {t('Conditions')} + {t('Created')} + {t('Edited')} + {t('Action')} {t('No inbound filters found')} From 5acbfdfd802a01880c79541e18bb9feb7cf24d36 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 1 Jun 2026 16:19:59 +0200 Subject: [PATCH 5/5] move custom filter table code to separate file --- .../project/projectFilters/customFilters.tsx | 26 ++++++++++++++++++ .../settings/project/projectFilters/index.tsx | 27 +++---------------- 2 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 static/app/views/settings/project/projectFilters/customFilters.tsx diff --git a/static/app/views/settings/project/projectFilters/customFilters.tsx b/static/app/views/settings/project/projectFilters/customFilters.tsx new file mode 100644 index 00000000000000..0e99dcd1e9656f --- /dev/null +++ b/static/app/views/settings/project/projectFilters/customFilters.tsx @@ -0,0 +1,26 @@ +import styled from '@emotion/styled'; + +import {SimpleTable} from 'sentry/components/tables/simpleTable'; +import {t} from 'sentry/locale'; + +export function CustomFilters() { + return ( + + + {t('Active')} + {t('Name')} + {t('Conditions')} + {t('Created')} + {t('Edited')} + {t('Action')} + + {t('No inbound filters found')} + + ); +} + +const CustomFiltersTable = styled(SimpleTable)` + grid-template-columns: + max-content minmax(0, 1fr) minmax(0, 2fr) max-content max-content + max-content; +`; diff --git a/static/app/views/settings/project/projectFilters/index.tsx b/static/app/views/settings/project/projectFilters/index.tsx index 5020f97c1b4793..63f161cae7b977 100644 --- a/static/app/views/settings/project/projectFilters/index.tsx +++ b/static/app/views/settings/project/projectFilters/index.tsx @@ -4,7 +4,6 @@ import styled from '@emotion/styled'; import {TabList, Tabs} from '@sentry/scraps/tabs'; import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle'; -import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {t} from 'sentry/locale'; import {recreateRoute} from 'sentry/utils/recreateRoute'; import {useOrganization} from 'sentry/utils/useOrganization'; @@ -17,6 +16,8 @@ import {ProjectFiltersSettings} from 'sentry/views/settings/project/projectFilte import {ProjectPermissionAlert} from 'sentry/views/settings/project/projectPermissionAlert'; import {useProjectSettingsOutlet} from 'sentry/views/settings/project/projectSettingsLayout'; +import {CustomFilters} from './customFilters'; + export default function ProjectFilters() { const routes = useRoutes(); const params = useParams<{filterType: string; projectId: string}>(); @@ -84,7 +85,7 @@ export default function ProjectFilters() { {filterType === 'discarded-groups' ? ( ) : hasInboundFiltersV2 && filterType === 'inbound-filters' ? ( - + ) : ( )} @@ -93,28 +94,6 @@ export default function ProjectFilters() { ); } -function InboundFiltersV2() { - return ( - - - {t('Active')} - {t('Name')} - {t('Conditions')} - {t('Created')} - {t('Edited')} - {t('Action')} - - {t('No inbound filters found')} - - ); -} - const TabsContainer = styled('div')` margin-bottom: ${p => p.theme.space.xl}; `; - -const InboundFiltersV2Table = styled(SimpleTable)` - grid-template-columns: - max-content minmax(0, 1fr) minmax(0, 2fr) max-content max-content - max-content; -`;