From 0a98d0cf664d84718a5a2ada821cc69130a87d9c Mon Sep 17 00:00:00 2001 From: Alberto Leal Date: Mon, 8 Jul 2019 17:51:09 -0400 Subject: [PATCH 1/5] SEN-796: Build basic transaction subtab in events v2 list --- .../app/components/events/eventEntries.jsx | 2 + .../app/views/organizationEventsV2/data.jsx | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/sentry/static/sentry/app/components/events/eventEntries.jsx b/src/sentry/static/sentry/app/components/events/eventEntries.jsx index 38a6f108ee3d..d2b9bf0637c4 100644 --- a/src/sentry/static/sentry/app/components/events/eventEntries.jsx +++ b/src/sentry/static/sentry/app/components/events/eventEntries.jsx @@ -32,6 +32,7 @@ import SentryTypes from 'app/sentryTypes'; import StacktraceInterface from 'app/components/events/interfaces/stacktrace'; import TemplateInterface from 'app/components/events/interfaces/template'; import ThreadsInterface from 'app/components/events/interfaces/threads'; +import SpansInterface from 'app/components/events/interfaces/spans'; import withApi from 'app/utils/withApi'; import withOrganization from 'app/utils/withOrganization'; @@ -48,6 +49,7 @@ export const INTERFACES = { breadcrumbs: BreadcrumbsInterface, threads: ThreadsInterface, debugmeta: DebugMetaInterface, + spans: SpansInterface, }; class EventEntries extends React.Component { diff --git a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx index 7b9218e8f868..e0c7a714a31c 100644 --- a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx +++ b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx @@ -65,6 +65,28 @@ export const ALL_VIEWS = deepFreeze([ ], columnWidths: ['3fr', '70px', '70px', '1fr', '1.5fr'], }, + { + id: 'transactions', + name: 'Transactions', + data: { + fields: ['transaction', 'project', 'rpm', 'avg', '75th', '95th', '% total'], + sort: ['-timestamp', '-id'], + query: 'event.type:transaction', + }, + tags: [ + 'event.type', + 'release', + 'project.name', + 'user.email', + 'user.ip', + 'environment', + 'trace', + 'trace.ctx', + 'trace.span', + 'transaction', + ], + columnWidths: ['3fr', '1fr', '1fr', '1fr', '1fr', '1fr', '1fr'], + }, ]); /** @@ -73,6 +95,30 @@ export const ALL_VIEWS = deepFreeze([ * displays with a custom render function. */ export const SPECIAL_FIELDS = { + '% total': { + fields: [], + sortField: false, + renderFunc: () => { + return % total; + }, + }, + transaction: { + fields: ['title', 'id', 'project.name', 'transaction'], + sortField: 'transaction', + renderFunc: (data, {organization, location}) => { + const target = { + pathname: `/organizations/${organization.slug}/events/`, + query: {...location.query, eventSlug: `${data['project.name']}:${data.id}`}, + }; + return ( + + + {data.transaction} + + + ); + }, + }, event: { fields: ['title', 'id', 'project.name'], sortField: 'title', From d6083a1cc4c78bc2fdc71338fd89ed3ec56aff6a Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 22 Jul 2019 12:43:59 -0400 Subject: [PATCH 2/5] Remove spans references. They are not part of these changes. --- src/sentry/static/sentry/app/components/events/eventEntries.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sentry/static/sentry/app/components/events/eventEntries.jsx b/src/sentry/static/sentry/app/components/events/eventEntries.jsx index d2b9bf0637c4..38a6f108ee3d 100644 --- a/src/sentry/static/sentry/app/components/events/eventEntries.jsx +++ b/src/sentry/static/sentry/app/components/events/eventEntries.jsx @@ -32,7 +32,6 @@ import SentryTypes from 'app/sentryTypes'; import StacktraceInterface from 'app/components/events/interfaces/stacktrace'; import TemplateInterface from 'app/components/events/interfaces/template'; import ThreadsInterface from 'app/components/events/interfaces/threads'; -import SpansInterface from 'app/components/events/interfaces/spans'; import withApi from 'app/utils/withApi'; import withOrganization from 'app/utils/withOrganization'; @@ -49,7 +48,6 @@ export const INTERFACES = { breadcrumbs: BreadcrumbsInterface, threads: ThreadsInterface, debugmeta: DebugMetaInterface, - spans: SpansInterface, }; class EventEntries extends React.Component { From e5517c54cc1bc8e024bc8cf782c88dbb9e021e12 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 22 Jul 2019 13:26:30 -0400 Subject: [PATCH 3/5] feat(events-v2) Remove non-functional columns Remove columns that aren't going to work for quite sometime. Add `transactionSlug` as a parameter to open the event details modal. Because we don't have a synthetic grouping column (like issue.id) for transaction events we need to rely on the combination of `project_id` and `transaction` name to act as a key to group transactions together. With these two pieces of data we can generate the summary graphs and locate the 'latest' event in the transaction series. Refs SEN-796 --- .../api/endpoints/organization_events.py | 2 +- .../app/views/organizationEventsV2/data.jsx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index 1e43a269352f..a2fec67a37bb 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -18,7 +18,7 @@ from sentry import features from sentry.models.project import Project -ALLOWED_GROUPINGS = frozenset(('issue.id', 'project.id')) +ALLOWED_GROUPINGS = frozenset(('issue.id', 'project.id', 'transaction')) logger = logging.getLogger(__name__) diff --git a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx index e0c7a714a31c..a3238f81c527 100644 --- a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx +++ b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx @@ -69,8 +69,9 @@ export const ALL_VIEWS = deepFreeze([ id: 'transactions', name: 'Transactions', data: { - fields: ['transaction', 'project', 'rpm', 'avg', '75th', '95th', '% total'], - sort: ['-timestamp', '-id'], + fields: ['transaction', 'project'], + groupby: ['transaction', 'project.id'], + sort: ['-transaction'], query: 'event.type:transaction', }, tags: [ @@ -80,10 +81,6 @@ export const ALL_VIEWS = deepFreeze([ 'user.email', 'user.ip', 'environment', - 'trace', - 'trace.ctx', - 'trace.span', - 'transaction', ], columnWidths: ['3fr', '1fr', '1fr', '1fr', '1fr', '1fr', '1fr'], }, @@ -95,20 +92,23 @@ export const ALL_VIEWS = deepFreeze([ * displays with a custom render function. */ export const SPECIAL_FIELDS = { - '% total': { + '% query': { fields: [], sortField: false, renderFunc: () => { - return % total; + return % query; }, }, transaction: { - fields: ['title', 'id', 'project.name', 'transaction'], + fields: ['project.name', 'transaction'], sortField: 'transaction', renderFunc: (data, {organization, location}) => { const target = { pathname: `/organizations/${organization.slug}/events/`, - query: {...location.query, eventSlug: `${data['project.name']}:${data.id}`}, + query: { + ...location.query, + transactionSlug: `${data['project.name']}:${data.transaction}`, + }, }; return ( From e195a45b26c1b5e70400c9351fe72d7a6a1af1b0 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 22 Jul 2019 17:04:35 -0400 Subject: [PATCH 4/5] Use aria-label instead of data-test-id The label lets us select a specific row more easily and confidently. --- .../app/views/organizationEventsV2/data.jsx | 24 +++++++------------ .../acceptance/test_organization_events_v2.py | 4 ++-- .../views/organizationEventsV2/index.spec.jsx | 5 ++-- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx index a3238f81c527..2f414f8d4da0 100644 --- a/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx +++ b/src/sentry/static/sentry/app/views/organizationEventsV2/data.jsx @@ -12,6 +12,7 @@ import UserBadge from 'app/components/idBadge/userBadge'; import DateTime from 'app/components/dateTime'; import pinIcon from 'app/../images/location-pin.png'; +import {t} from 'app/locale'; import {QueryLink} from './styles'; export const MODAL_QUERY_KEYS = ['eventSlug', 'groupSlug']; @@ -20,7 +21,7 @@ export const PIN_ICON = `image://${pinIcon}`; export const ALL_VIEWS = deepFreeze([ { id: 'all', - name: 'All Events', + name: t('All Events'), data: { fields: ['event', 'type', 'project', 'user', 'time'], sort: ['-timestamp', '-id'], @@ -37,7 +38,7 @@ export const ALL_VIEWS = deepFreeze([ }, { id: 'errors', - name: 'Errors', + name: t('Errors'), data: { fields: ['error', 'event_count', 'user_count', 'project', 'last_seen'], groupby: ['issue.id', 'project.id'], @@ -49,7 +50,7 @@ export const ALL_VIEWS = deepFreeze([ }, { id: 'csp', - name: 'CSP', + name: t('CSP'), data: { fields: ['csp', 'event_count', 'user_count', 'project', 'last_seen'], groupby: ['issue.id', 'project.id'], @@ -67,7 +68,7 @@ export const ALL_VIEWS = deepFreeze([ }, { id: 'transactions', - name: 'Transactions', + name: t('Transactions'), data: { fields: ['transaction', 'project'], groupby: ['transaction', 'project.id'], @@ -92,13 +93,6 @@ export const ALL_VIEWS = deepFreeze([ * displays with a custom render function. */ export const SPECIAL_FIELDS = { - '% query': { - fields: [], - sortField: false, - renderFunc: () => { - return % query; - }, - }, transaction: { fields: ['project.name', 'transaction'], sortField: 'transaction', @@ -112,7 +106,7 @@ export const SPECIAL_FIELDS = { }; return ( - + {data.transaction} @@ -129,7 +123,7 @@ export const SPECIAL_FIELDS = { }; return ( - + {data.title} @@ -218,7 +212,7 @@ export const SPECIAL_FIELDS = { }; return ( - + {data.issue_title} @@ -238,7 +232,7 @@ export const SPECIAL_FIELDS = { }; return ( - + {data.issue_title} diff --git a/tests/acceptance/test_organization_events_v2.py b/tests/acceptance/test_organization_events_v2.py index 2c61ad657216..a74afa559473 100644 --- a/tests/acceptance/test_organization_events_v2.py +++ b/tests/acceptance/test_organization_events_v2.py @@ -127,7 +127,7 @@ def test_modal_from_all_events(self, mock_now): self.wait_until_loaded() # Click the event link to open the modal - self.browser.element('[data-test-id="event-title"]').click() + self.browser.element('[aria-label="{}"]'.format(event.title)).click() self.wait_until_loaded() header = self.browser.element('[data-test-id="modal-dialog"] h2') @@ -169,7 +169,7 @@ def test_modal_from_errors_view(self, mock_now): self.wait_until_loaded() # Click the event link to open the modal - self.browser.element('[data-test-id="event-title"]').click() + self.browser.element('[aria-label="{}"]'.format(event.title)).click() self.wait_until_loaded() self.browser.snapshot('events-v2 - grouped error modal') diff --git a/tests/js/spec/views/organizationEventsV2/index.spec.jsx b/tests/js/spec/views/organizationEventsV2/index.spec.jsx index deddc52d4baf..173b75d6c996 100644 --- a/tests/js/spec/views/organizationEventsV2/index.spec.jsx +++ b/tests/js/spec/views/organizationEventsV2/index.spec.jsx @@ -4,13 +4,14 @@ import {mount} from 'enzyme'; import OrganizationEventsV2 from 'app/views/organizationEventsV2'; describe('OrganizationEventsV2', function() { + const eventTitle = 'Oh no something bad'; beforeEach(function() { MockApiClient.addMockResponse({ url: '/organizations/org-slug/events/', body: [ { id: 'deadbeef', - title: 'Oh no something bad', + title: eventTitle, 'project.name': 'project-slug', timestamp: '2019-05-23T22:12:48+00:00', }, @@ -108,7 +109,7 @@ describe('OrganizationEventsV2', function() { TestStubs.routerContext() ); - const link = wrapper.find('Table Link[data-test-id="event-title"]').first(); + const link = wrapper.find(`Table Link[aria-label="${eventTitle}"]`).first(); expect(link.props().to.query).toEqual({eventSlug: 'project-slug:deadbeef'}); }); From 9692e7ecc72a6edef3d5504b01779b6b58015920 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Tue, 23 Jul 2019 10:53:22 -0400 Subject: [PATCH 5/5] Fix assertion as message has changed. --- tests/snuba/api/endpoints/test_organization_events_v2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snuba/api/endpoints/test_organization_events_v2.py b/tests/snuba/api/endpoints/test_organization_events_v2.py index fc9fd6d069dd..80f3984b8a3b 100644 --- a/tests/snuba/api/endpoints/test_organization_events_v2.py +++ b/tests/snuba/api/endpoints/test_organization_events_v2.py @@ -530,7 +530,7 @@ def test_invalid_groupby(self): }, ) assert response.status_code == 400, response.content - assert response.data['detail'] == 'Invalid groupby value requested. Allowed values are project.id, issue.id' + assert response.data['detail'] == 'Invalid groupby value requested. Allowed values are transaction, project.id, issue.id' def test_non_aggregated_fields_with_groupby(self): self.login_as(user=self.user)