From 43a07a783c54bbef4be8285a61daf52606cadcb6 Mon Sep 17 00:00:00 2001 From: Colin Chartier Date: Mon, 5 May 2025 15:14:18 -0400 Subject: [PATCH 1/4] feat(ourlogs): Better frozen handling, more tests --- .../combinedBreadcrumbsAndLogsSection.tsx | 3 +- .../explore/contexts/logs/logsPageParams.tsx | 25 +-- .../views/explore/logs/logsIssuesSection.tsx | 5 +- .../app/views/explore/logs/logsTable.spec.tsx | 195 ++++++++++++++++++ static/app/views/explore/logs/logsTable.tsx | 12 +- .../app/views/explore/logs/logsTableRow.tsx | 8 +- .../logs/useLogAttributesTreeActions.tsx | 4 +- .../traceDrawer/details/span/index.tsx | 2 +- .../newTraceDetails/traceOurlogs.tsx | 2 +- 9 files changed, 224 insertions(+), 32 deletions(-) create mode 100644 static/app/views/explore/logs/logsTable.spec.tsx diff --git a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx b/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx index acd428d8285aa1..c813fd72b0503e 100644 --- a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx +++ b/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx @@ -25,7 +25,7 @@ export function CombinedBreadcrumbsAndLogsSection({ return ( @@ -55,7 +55,6 @@ function CombinedBreadcrumbsAndLogsSectionContent({ /> ( @@ -89,7 +88,7 @@ export function LogsIssuesSection({ > diff --git a/static/app/views/explore/logs/logsTable.spec.tsx b/static/app/views/explore/logs/logsTable.spec.tsx new file mode 100644 index 00000000000000..fd2b32797e71cd --- /dev/null +++ b/static/app/views/explore/logs/logsTable.spec.tsx @@ -0,0 +1,195 @@ +import {LocationFixture} from 'sentry-fixture/locationFixture'; + +import {initializeOrg} from 'sentry-test/initializeOrg'; +import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary'; + +import ProjectsStore from 'sentry/stores/projectsStore'; +import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent'; +import {useLocation} from 'sentry/utils/useLocation'; +import { + LOGS_FIELDS_KEY, + LOGS_QUERY_KEY, + LogsPageParamsProvider, +} from 'sentry/views/explore/contexts/logs/logsPageParams'; +import {LOGS_SORT_BYS_KEY} from 'sentry/views/explore/contexts/logs/sortBys'; +import {LogsTable} from 'sentry/views/explore/logs/logsTable'; +import {OurLogKnownFieldKey} from 'sentry/views/explore/logs/types'; +import type {UseExploreLogsTableResult} from 'sentry/views/explore/logs/useLogsQuery'; + +jest.mock('sentry/utils/useLocation'); +const mockUseLocation = jest.mocked(useLocation); + +jest.mock('sentry/utils/useRelease', () => ({ + useRelease: jest.fn().mockReturnValue({ + data: { + id: 10, + lastCommit: { + id: '1e5a9462e6ac23908299b218e18377837297bda1', + }, + }, + }), +})); + +jest.mock('sentry/components/events/interfaces/frame/useStacktraceLink', () => ({ + __esModule: true, + default: jest.fn().mockReturnValue({ + data: { + sourceUrl: 'https://some-stacktrace-link', + integrations: [], + }, + error: null, + isPending: false, + }), +})); + +describe('LogsTable', function () { + const {organization, project} = initializeOrg({ + organization: { + features: ['ourlogs'], + }, + }); + ProjectsStore.loadInitialData([project]); + + const tableData = { + data: [ + { + 'sentry.item_id': '0196a1bc022d76d3bff2106ebbf65f49', + 'project.id': project.id, + trace: '32986bcdac1f43ed87445a2021b0099c', + severity_number: 9, + severity: 'info', + timestamp: '2025-05-05T18:36:15+00:00', + message: + '10.5.55.212 - - [05/May/2025:18:36:15 +0000] "POST /v1/automation/autofix/state HTTP/1.1" 200 293642 "-" "python-requests/2.32.3"', + 'sentry.release': '985bae16edc2f3f8132e346a4f6c5a559f7c968b', + 'code.file.path': '/usr/local/lib/python3.11/dist-packages/gunicorn/glogging.py', + 'tags[sentry.timestamp_precise,number]': 1.7464701752771756e18, + }, + { + 'sentry.item_id': '0196a1bc00e3720f8d47c84c53131891', + 'project.id': project.id, + trace: '6141dca24986471398232d340a4fd588', + severity_number: 9, + severity: 'info', + timestamp: '2025-05-05T18:36:14+00:00', + message: + '10.5.58.189 - - [05/May/2025:18:36:14 +0000] "POST /v0/issues/similar-issues HTTP/1.1" 200 131 "-" "python-urllib3/2.2.2"', + 'sentry.release': '985bae16edc2f3f8132e346a4f6c5a559f7c968b', + 'code.file.path': '/usr/local/lib/python3.11/dist-packages/gunicorn/glogging.py', + 'tags[sentry.timestamp_precise,number]': 1.746470174947077e18, + }, + { + 'sentry.item_id': '0196a1bc007c7dfbbe099b6328e41d12', + 'project.id': project.id, + trace: '6141dca24986471398232d340a4fd588', + severity_number: 9, + severity: 'info', + timestamp: '2025-05-05T18:36:14+00:00', + message: + '10.5.62.140 - - [05/May/2025:18:36:14 +0000] "POST /v0/issues/similar-issues HTTP/1.1" 200 586 "-" "python-urllib3/2.2.2"', + 'sentry.release': '985bae16edc2f3f8132e346a4f6c5a559f7c968b', + 'code.file.path': '/usr/local/lib/python3.11/dist-packages/gunicorn/glogging.py', + 'tags[sentry.timestamp_precise,number]': 1.7464701748443016e18, + }, + ], + meta: { + fields: { + 'sentry.item_id': 'string', + 'project.id': 'string', + trace: 'string', + severity_number: 'integer', + severity: 'string', + timestamp: 'string', + message: 'string', + 'sentry.release': 'string', + 'code.file.path': 'string', + 'tags[sentry.timestamp_precise,number]': 'number', + }, + }, + isLoading: false, + isPending: false, + isError: false, + error: null, + pageLinks: undefined, + } as unknown as UseExploreLogsTableResult; + + const visibleColumnFields = [ + 'message', + 'trace', + 'severity_number', + 'severity', + 'timestamp', + 'sentry.release', + 'code.file.path', + ]; + const frozenColumnFields = [OurLogKnownFieldKey.TIMESTAMP, OurLogKnownFieldKey.MESSAGE]; + + beforeEach(function () { + MockApiClient.clearMockResponses(); + mockUseLocation.mockReturnValue( + LocationFixture({ + pathname: `/organizations/${organization.slug}/explore/logs/?end=2025-04-10T20%3A04%3A51&project=${project.id}&start=2025-04-10T14%3A37%3A55`, + query: { + [LOGS_FIELDS_KEY]: visibleColumnFields, + [LOGS_SORT_BYS_KEY]: '-timestamp', + [LOGS_QUERY_KEY]: 'severity:error', + }, + }) + ); + + MockApiClient.addMockResponse({ + url: `/organizations/${organization.slug}/releases/stats/`, + method: 'GET', + body: {}, + }); + }); + + it('should be interactable', async () => { + render( + + + + ); + + const allTreeRows = await screen.findAllByTestId('log-table-row'); + expect(allTreeRows).toHaveLength(3); + for (const row of allTreeRows) { + for (const field of visibleColumnFields) { + const cell = await within(row).findByTestId(`log-table-cell-${field}`); + await userEvent.hover(cell); + const actionsButton = within(cell).queryByRole('button', { + name: 'Actions', + }); + if (field === 'timestamp') { + expect(actionsButton).toBeNull(); + } else { + expect(actionsButton).toBeInTheDocument(); + } + } + } + }); + + it('should not be interactable on embedded views', async () => { + render( + + + + ); + + const allTreeRows = await screen.findAllByTestId('log-table-row'); + expect(allTreeRows).toHaveLength(3); + for (const row of allTreeRows) { + for (const field of frozenColumnFields) { + const cell = await within(row).findByTestId(`log-table-cell-${field}`); + await userEvent.hover(cell); + const actionsButton = within(cell).queryByRole('button', { + name: 'Actions', + }); + expect(actionsButton).not.toBeInTheDocument(); + } + } + }); +}); diff --git a/static/app/views/explore/logs/logsTable.tsx b/static/app/views/explore/logs/logsTable.tsx index faa7aab152c619..5334843dfca489 100644 --- a/static/app/views/explore/logs/logsTable.tsx +++ b/static/app/views/explore/logs/logsTable.tsx @@ -20,7 +20,7 @@ import { } from 'sentry/views/explore/components/table'; import { useLogsFields, - useLogsIsTableEditingFrozen, + useLogsIsTableFrozen, useLogsSearch, useLogsSortBys, useSetLogsCursor, @@ -58,8 +58,8 @@ export function LogsTable({ const fields = useLogsFields(); const search = useLogsSearch(); const setCursor = useSetLogsCursor(); - const isTableEditingFrozen = useLogsIsTableEditingFrozen(); - const hideTableBorder = !!isTableEditingFrozen; + const isTableFrozen = useLogsIsTableFrozen(); + const hideTableBorder = !!isTableFrozen; const {data, isError, isPending, pageLinks, meta} = tableData; @@ -113,10 +113,8 @@ export function LogsTable({ isFirst={index === 0} > setSortBys([{field}]) - } - isFrozen={isTableEditingFrozen} + onClick={isTableFrozen ? undefined : () => setSortBys([{field}])} + isFrozen={isTableFrozen} > {headerLabel} diff --git a/static/app/views/explore/logs/logsTableRow.tsx b/static/app/views/explore/logs/logsTableRow.tsx index b3a34a7def88ed..357447df2fa20a 100644 --- a/static/app/views/explore/logs/logsTableRow.tsx +++ b/static/app/views/explore/logs/logsTableRow.tsx @@ -21,6 +21,7 @@ import {AttributesTree} from 'sentry/views/explore/components/traceItemAttribute import { useLogsAnalyticsPageSource, useLogsFields, + useLogsIsTableFrozen, useLogsSearch, useSetLogsSearch, } from 'sentry/views/explore/contexts/logs/logsPageParams'; @@ -92,6 +93,7 @@ export function LogRowContent({ const fields = useLogsFields(); const search = useLogsSearch(); const setLogsSearch = useSetLogsSearch(); + const isTableFrozen = useLogsIsTableFrozen(); function toggleExpanded() { setExpanded(e => !e); @@ -203,7 +205,7 @@ export function LogRowContent({ }; return ( - + { diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx index 4a4d0cd7c52fc0..9f8109fbd26a37 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx @@ -365,7 +365,7 @@ function EAPSpanNodeDetails({ /> From 43eef0e283fcd3630a7239a2b322044b6efa7603 Mon Sep 17 00:00:00 2001 From: Colin Chartier Date: Mon, 5 May 2025 15:26:14 -0400 Subject: [PATCH 2/4] test? --- static/app/views/explore/logs/logsTable.spec.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/app/views/explore/logs/logsTable.spec.tsx b/static/app/views/explore/logs/logsTable.spec.tsx index fd2b32797e71cd..2392da4d5064cb 100644 --- a/static/app/views/explore/logs/logsTable.spec.tsx +++ b/static/app/views/explore/logs/logsTable.spec.tsx @@ -30,6 +30,11 @@ jest.mock('sentry/utils/useRelease', () => ({ }), })); +jest.mock('sentry/views/explore/logs/useLogsQuery', () => ({ + useExploreLogsTableRow: jest.fn().mockReturnValue({}), + usePrefetchLogTableRowOnHover: jest.fn().mockReturnValue({}), +})); + jest.mock('sentry/components/events/interfaces/frame/useStacktraceLink', () => ({ __esModule: true, default: jest.fn().mockReturnValue({ From cf8c0acb6fd22eb10d309ce9b74b75b80ce7e970 Mon Sep 17 00:00:00 2001 From: Colin Chartier Date: Mon, 5 May 2025 15:51:07 -0400 Subject: [PATCH 3/4] add a new prop, finagle things a bit more --- .../combinedBreadcrumbsAndLogsSection.tsx | 1 + .../explore/contexts/logs/logsPageParams.tsx | 11 +++++- .../views/explore/logs/logsIssuesSection.tsx | 1 + .../app/views/explore/logs/logsTableRow.tsx | 38 +++++++++++-------- static/app/views/explore/logs/styles.tsx | 8 +++- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx b/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx index c813fd72b0503e..762097fa7849b3 100644 --- a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx +++ b/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx @@ -26,6 +26,7 @@ export function CombinedBreadcrumbsAndLogsSection({ return ( diff --git a/static/app/views/explore/contexts/logs/logsPageParams.tsx b/static/app/views/explore/contexts/logs/logsPageParams.tsx index 35214541438c93..b7ec09675715f4 100644 --- a/static/app/views/explore/contexts/logs/logsPageParams.tsx +++ b/static/app/views/explore/contexts/logs/logsPageParams.tsx @@ -31,6 +31,7 @@ export const LOGS_FIELDS_KEY = 'logsFields'; interface LogsPageParams { readonly analyticsPageSource: LogsAnalyticsPageSource; + readonly blockRowExpanding: boolean | undefined; readonly cursor: string; readonly fields: string[]; readonly isTableFrozen: boolean | undefined; @@ -57,6 +58,7 @@ const [_LogsPageParamsProvider, _useLogsPageParams, LogsPageParamsContext] = export interface LogsPageParamsProviderProps { analyticsPageSource: LogsAnalyticsPageSource; children: React.ReactNode; + blockRowExpanding?: boolean; isTableFrozen?: boolean; limitToProjectIds?: number[]; limitToSpanId?: string; @@ -68,6 +70,7 @@ export function LogsPageParamsProvider({ limitToTraceId, limitToSpanId, limitToProjectIds, + blockRowExpanding, isTableFrozen, analyticsPageSource, }: LogsPageParamsProviderProps) { @@ -103,6 +106,7 @@ export function LogsPageParamsProvider({ sortBys, cursor, isTableFrozen, + blockRowExpanding, baseSearch, projectIds, analyticsPageSource, @@ -202,7 +206,12 @@ export function useSetLogsSearch() { export function useLogsIsTableFrozen() { const {isTableFrozen} = useLogsPageParams(); - return isTableFrozen; + return !!isTableFrozen; +} + +export function useLogsBlockRowExpanding() { + const {blockRowExpanding} = useLogsPageParams(); + return !!blockRowExpanding; } export function usePersistedLogsPageParams() { diff --git a/static/app/views/explore/logs/logsIssuesSection.tsx b/static/app/views/explore/logs/logsIssuesSection.tsx index 8e88794f703b42..ccf396ee8e8e4e 100644 --- a/static/app/views/explore/logs/logsIssuesSection.tsx +++ b/static/app/views/explore/logs/logsIssuesSection.tsx @@ -89,6 +89,7 @@ export function LogsIssuesSection({ diff --git a/static/app/views/explore/logs/logsTableRow.tsx b/static/app/views/explore/logs/logsTableRow.tsx index 357447df2fa20a..ada262d5f9fed7 100644 --- a/static/app/views/explore/logs/logsTableRow.tsx +++ b/static/app/views/explore/logs/logsTableRow.tsx @@ -1,4 +1,4 @@ -import type {SyntheticEvent} from 'react'; +import type {ComponentProps, SyntheticEvent} from 'react'; import {Fragment, useCallback, useState} from 'react'; import {useTheme} from '@emotion/react'; @@ -20,6 +20,7 @@ import type {TableColumn} from 'sentry/views/discover/table/types'; import {AttributesTree} from 'sentry/views/explore/components/traceItemAttributes/attributesTree'; import { useLogsAnalyticsPageSource, + useLogsBlockRowExpanding, useLogsFields, useLogsIsTableFrozen, useLogsSearch, @@ -94,6 +95,7 @@ export function LogRowContent({ const search = useLogsSearch(); const setLogsSearch = useSetLogsSearch(); const isTableFrozen = useLogsIsTableFrozen(); + const blockRowExpanding = useLogsBlockRowExpanding(); function toggleExpanded() { setExpanded(e => !e); @@ -165,24 +167,30 @@ export function LogRowContent({ projectSlug, }; + const rowInteractProps: ComponentProps = blockRowExpanding + ? {} + : { + ...hoverProps, + onPointerUp, + onTouchEnd: onPointerUp, + isClickable: true, + }; + return ( - + - } - aria-label={t('Toggle trace details')} - aria-expanded={expanded} - size="zero" - borderless - onClick={() => toggleExpanded()} - /> + {blockRowExpanding ? null : ( + } + aria-label={t('Toggle trace details')} + aria-expanded={expanded} + size="zero" + borderless + onClick={() => toggleExpanded()} + /> + )} diff --git a/static/app/views/explore/logs/styles.tsx b/static/app/views/explore/logs/styles.tsx index d12941625cc45e..c7054ba91ae6ee 100644 --- a/static/app/views/explore/logs/styles.tsx +++ b/static/app/views/explore/logs/styles.tsx @@ -19,9 +19,13 @@ const StyledPanel = styled(Panel)` margin-bottom: 0; `; -export const LogTableRow = styled(TableRow)` +interface LogTableRowProps { + isClickable?: boolean; +} + +export const LogTableRow = styled(TableRow)` &:not(thead > &) { - cursor: pointer; + cursor: ${p => (p.isClickable ? 'pointer' : 'default')}; &:hover { background-color: ${p => p.theme.backgroundSecondary}; From 523246e95d08b20016523683a933ce048c7d925f Mon Sep 17 00:00:00 2001 From: Colin Chartier Date: Tue, 6 May 2025 13:54:29 -0400 Subject: [PATCH 4/4] move everything around, fix many bugs --- .../combinedBreadcrumbsAndLogsSection.tsx | 66 ---------- .../events/ourlogs/ourlogsDrawer.tsx} | 46 ++++--- .../events/ourlogs/ourlogsSection.tsx} | 113 +++++++++--------- .../explore/contexts/logs/logsPageParams.tsx | 33 ++--- static/app/views/explore/logs/logsTable.tsx | 3 +- .../groupEventDetailsContent.tsx | 9 +- .../newTraceDetails/traceOurlogs.tsx | 13 +- 7 files changed, 124 insertions(+), 159 deletions(-) delete mode 100644 static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx rename static/app/{views/explore/logs/logsIssueDrawer.tsx => components/events/ourlogs/ourlogsDrawer.tsx} (58%) rename static/app/{views/explore/logs/logsIssuesSection.tsx => components/events/ourlogs/ourlogsSection.tsx} (64%) diff --git a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx b/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx deleted file mode 100644 index 762097fa7849b3..00000000000000 --- a/static/app/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import {Fragment} from 'react'; - -import type {BreadcrumbsDataSectionProps} from 'sentry/components/events/breadcrumbs/breadcrumbsDataSection'; -import BreadcrumbsDataSection from 'sentry/components/events/breadcrumbs/breadcrumbsDataSection'; -import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent'; -import useOrganization from 'sentry/utils/useOrganization'; -import {LogsPageParamsProvider} from 'sentry/views/explore/contexts/logs/logsPageParams'; -import {LogsIssuesSection} from 'sentry/views/explore/logs/logsIssuesSection'; -import {useExploreLogsTable} from 'sentry/views/explore/logs/useLogsQuery'; - -/** - * This component is a coordinator and provider wrapper to determine which section to display, collapse etc. since only one section should be displayed by default. - */ -export function CombinedBreadcrumbsAndLogsSection({ - event, - group, - project, -}: BreadcrumbsDataSectionProps) { - const organization = useOrganization(); - const feature = organization.features.includes('ourlogs-enabled'); - if (!feature) { - // If we don't have the feature, we should skip the providers as they make api calls. - return ; - } - - return ( - - - - ); -} - -function CombinedBreadcrumbsAndLogsSectionContent({ - event, - group, - project, -}: BreadcrumbsDataSectionProps) { - const tableData = useExploreLogsTable({}); - const shouldCollapseLogs = tableData.data.length === 0; - return ( - - - - - ); -} diff --git a/static/app/views/explore/logs/logsIssueDrawer.tsx b/static/app/components/events/ourlogs/ourlogsDrawer.tsx similarity index 58% rename from static/app/views/explore/logs/logsIssueDrawer.tsx rename to static/app/components/events/ourlogs/ourlogsDrawer.tsx index 94aa64fe4640b5..7f6e7f09e5cbb8 100644 --- a/static/app/views/explore/logs/logsIssueDrawer.tsx +++ b/static/app/components/events/ourlogs/ourlogsDrawer.tsx @@ -9,16 +9,21 @@ import { NavigationCrumbs, ShortId, } from 'sentry/components/events/eventDrawer'; +import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Event} from 'sentry/types/event'; import type {Group} from 'sentry/types/group'; import type {Project} from 'sentry/types/project'; import {getShortEventId} from 'sentry/utils/events'; -import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; +import {MutableSearch} from 'sentry/utils/tokenizeSearch'; +import { + TraceItemSearchQueryBuilder, + useSearchQueryBuilderProps, +} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; import { useLogsSearch, - useSetLogsQuery, + useSetLogsSearch, } from 'sentry/views/explore/contexts/logs/logsPageParams'; import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {LogsTable} from 'sentry/views/explore/logs/logsTable'; @@ -31,12 +36,24 @@ interface LogIssueDrawerProps { project: Project; } -export function LogsIssueDrawer({event, project, group}: LogIssueDrawerProps) { - const setLogsQuery = useSetLogsQuery(); +export function OurlogsDrawer({event, project, group}: LogIssueDrawerProps) { + const setLogsSearch = useSetLogsSearch(); const logsSearch = useLogsSearch(); const tableData = useExploreLogsTable({}); - const {attributes: stringTags} = useTraceItemAttributes('string'); - const {attributes: numberTags} = useTraceItemAttributes('number'); + const {attributes: stringAttributes} = useTraceItemAttributes('string'); + const {attributes: numberAttributes} = useTraceItemAttributes('number'); + + const tracesItemSearchQueryBuilderProps = { + initialQuery: logsSearch.formatString(), + searchSource: 'ourlogs', + onSearch: (query: string) => setLogsSearch(new MutableSearch(query)), + numberAttributes, + stringAttributes, + itemType: TraceItemDataset.LOGS, + }; + const searchQueryBuilderProps = useSearchQueryBuilderProps( + tracesItemSearchQueryBuilderProps + ); return ( @@ -57,17 +74,12 @@ export function LogsIssueDrawer({event, project, group}: LogIssueDrawerProps) { /> - - - - + + + + + + ); diff --git a/static/app/views/explore/logs/logsIssuesSection.tsx b/static/app/components/events/ourlogs/ourlogsSection.tsx similarity index 64% rename from static/app/views/explore/logs/logsIssuesSection.tsx rename to static/app/components/events/ourlogs/ourlogsSection.tsx index ccf396ee8e8e4e..2f7f4a7c122cbb 100644 --- a/static/app/views/explore/logs/logsIssuesSection.tsx +++ b/static/app/components/events/ourlogs/ourlogsSection.tsx @@ -2,6 +2,7 @@ import {useCallback} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/core/button'; +import {OurlogsDrawer} from 'sentry/components/events/ourlogs/ourlogsDrawer'; import useDrawer from 'sentry/components/globalDrawer'; import {IconChevron} from 'sentry/icons'; import {t} from 'sentry/locale'; @@ -14,36 +15,53 @@ import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent import useOrganization from 'sentry/utils/useOrganization'; import { LogsPageParamsProvider, - type LogsPageParamsProviderProps, + useLogsSearch, } from 'sentry/views/explore/contexts/logs/logsPageParams'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {LogsIssueDrawer} from 'sentry/views/explore/logs/logsIssueDrawer'; import {LogsTable} from 'sentry/views/explore/logs/logsTable'; -import { - useExploreLogsTable, - type UseExploreLogsTableResult, -} from 'sentry/views/explore/logs/useLogsQuery'; +import {useExploreLogsTable} from 'sentry/views/explore/logs/useLogsQuery'; import {TraceItemDataset} from 'sentry/views/explore/types'; import {SectionKey} from 'sentry/views/issueDetails/streamline/context'; import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection'; -export function LogsIssuesSection({ - initialCollapse, - limitToTraceId, +export function OurlogsSection({ event, project, group, }: { event: Event; group: Group; - initialCollapse: boolean; project: Project; -} & Omit) { +}) { + return ( + + + + ); +} + +function OurlogsSectionContent({ + event, + project, + group, +}: { + event: Event; + group: Group; + project: Project; +}) { const organization = useOrganization(); const feature = organization.features.includes('ourlogs-enabled'); const tableData = useExploreLogsTable({enabled: feature, limit: 10}); + const logsSearch = useLogsSearch(); + const abbreviatedTableData = {...tableData, data: (tableData.data ?? []).slice(0, 5)}; const {openDrawer} = useDrawer(); + const limitToTraceId = event.contexts?.trace?.trace_id; const onOpenLogsDrawer = useCallback(() => { trackAnalytics('logs.issue_details.drawer_opened', { organization, @@ -56,7 +74,7 @@ export function LogsIssuesSection({ limitToTraceId={limitToTraceId} > - + ), @@ -74,7 +92,7 @@ export function LogsIssuesSection({ // We may change this in the future if we have a trace-group or we generate trace sids for these issue types. return null; } - if (tableData?.data?.length === 0) { + if (!tableData || (tableData.data?.length === 0 && logsSearch.isEmpty())) { // Like breadcrumbs, we don't show the logs section if there are no logs. return null; } @@ -84,53 +102,40 @@ export function LogsIssuesSection({ type={SectionKey.LOGS} title={t('Logs')} data-test-id="logs-data-section" - initialCollapse={initialCollapse} > - - - + onOpenLogsDrawer()}> + + {tableData.data?.length > 5 ? ( +
+ +
+ ) : null} +
); } -function LogsSectionContent({ - tableData, - openDrawer, -}: { - openDrawer: () => void; - tableData: UseExploreLogsTableResult; -}) { - const abbreviatedTableData = {...tableData, data: (tableData.data ?? []).slice(0, 5)}; - return ( - - - {tableData.data?.length > 5 ? ( -
- -
- ) : null} -
- ); -} - -const LogContentWrapper = styled('div')` +const LogContentWrapper = styled('button')` + all: unset; display: flex; flex-direction: column; gap: ${space(1)}; + pointer-events: auto; + cursor: pointer; + + * { + pointer-events: none !important; + cursor: inherit !important; + } `; diff --git a/static/app/views/explore/contexts/logs/logsPageParams.tsx b/static/app/views/explore/contexts/logs/logsPageParams.tsx index b7ec09675715f4..03cbe4f9362c1c 100644 --- a/static/app/views/explore/contexts/logs/logsPageParams.tsx +++ b/static/app/views/explore/contexts/logs/logsPageParams.tsx @@ -1,4 +1,4 @@ -import {useCallback, useLayoutEffect} from 'react'; +import {useCallback, useLayoutEffect, useState} from 'react'; import type {Location} from 'history'; import type {CursorHandler} from 'sentry/components/pagination'; @@ -36,9 +36,14 @@ interface LogsPageParams { readonly fields: string[]; readonly isTableFrozen: boolean | undefined; readonly search: MutableSearch; + /** + * On frozen pages (like the issues page), we don't want to store the search in the URL + * Instead, use a useState in the context, so that it's dropped if you navigate away or refresh. + */ + readonly setSearchForFrozenPages: (val: MutableSearch) => void; readonly sortBys: Sort[]; /** - * The base search, which doesn't appear in the URL or the search bar, used for adding traceid etc.. + * The base search, which doesn't appear in the URL or the search bar, used for adding traceid etc. */ readonly baseSearch?: MutableSearch; /** @@ -76,7 +81,11 @@ export function LogsPageParamsProvider({ }: LogsPageParamsProviderProps) { const location = useLocation(); const logsQuery = decodeLogsQuery(location); - const search = new MutableSearch(logsQuery); + + // on embedded pages with search bars, use a useState instead of a URL parameter + const [searchForFrozenPages, setSearchForFrozenPages] = useState(new MutableSearch('')); + + const search = isTableFrozen ? searchForFrozenPages : new MutableSearch(logsQuery); let baseSearch: MutableSearch | undefined = undefined; if (limitToSpanId && limitToTraceId) { baseSearch = baseSearch ?? new MutableSearch(''); @@ -103,6 +112,7 @@ export function LogsPageParamsProvider({ value={{ fields, search, + setSearchForFrozenPages, sortBys, cursor, isTableFrozen, @@ -184,24 +194,19 @@ export function useLogsBaseSearch(): MutableSearch | undefined { return baseSearch; } -export function useSetLogsQuery() { - const setPageParams = useSetLogsPageParams(); - return useCallback( - (query: string) => { - setPageParams({search: new MutableSearch(query)}); - }, - [setPageParams] - ); -} - export function useSetLogsSearch() { const setPageParams = useSetLogsPageParams(); - return useCallback( + const {setSearchForFrozenPages, isTableFrozen} = useLogsPageParams(); + const setPageParamsCallback = useCallback( (search: MutableSearch) => { setPageParams({search}); }, [setPageParams] ); + if (isTableFrozen) { + return setSearchForFrozenPages; + } + return setPageParamsCallback; } export function useLogsIsTableFrozen() { diff --git a/static/app/views/explore/logs/logsTable.tsx b/static/app/views/explore/logs/logsTable.tsx index 5334843dfca489..067340177bfe59 100644 --- a/static/app/views/explore/logs/logsTable.tsx +++ b/static/app/views/explore/logs/logsTable.tsx @@ -59,7 +59,6 @@ export function LogsTable({ const search = useLogsSearch(); const setCursor = useSetLogsCursor(); const isTableFrozen = useLogsIsTableFrozen(); - const hideTableBorder = !!isTableFrozen; const {data, isError, isPending, pageLinks, meta} = tableData; @@ -84,7 +83,7 @@ export function LogsTable({ ref={tableRef} styles={initialTableStyles} data-test-id="logs-table" - hideBorder={hideTableBorder} + hideBorder={isTableFrozen} > {showHeader ? ( diff --git a/static/app/views/issueDetails/groupEventDetails/groupEventDetailsContent.tsx b/static/app/views/issueDetails/groupEventDetails/groupEventDetailsContent.tsx index 69f07c42253643..f3af43891c5e02 100644 --- a/static/app/views/issueDetails/groupEventDetails/groupEventDetailsContent.tsx +++ b/static/app/views/issueDetails/groupEventDetails/groupEventDetailsContent.tsx @@ -3,11 +3,12 @@ import {ClassNames} from '@emotion/react'; import styled from '@emotion/styled'; import {usePrompt} from 'sentry/actionCreators/prompts'; +import Feature from 'sentry/components/acl/feature'; import GuideAnchor from 'sentry/components/assistant/guideAnchor'; import {CommitRow} from 'sentry/components/commitRow'; import {Button} from 'sentry/components/core/button'; import ErrorBoundary from 'sentry/components/errorBoundary'; -import {CombinedBreadcrumbsAndLogsSection} from 'sentry/components/events/breadcrumbs/combinedBreadcrumbsAndLogsSection'; +import BreadcrumbsDataSection from 'sentry/components/events/breadcrumbs/breadcrumbsDataSection'; import {EventContexts} from 'sentry/components/events/contexts'; import {EventDevice} from 'sentry/components/events/device'; import {EventAttachments} from 'sentry/components/events/eventAttachments'; @@ -48,6 +49,7 @@ import {StackTrace} from 'sentry/components/events/interfaces/stackTrace'; import {Template} from 'sentry/components/events/interfaces/template'; import {Threads} from 'sentry/components/events/interfaces/threads'; import {UptimeDataSection} from 'sentry/components/events/interfaces/uptime/uptimeDataSection'; +import {OurlogsSection} from 'sentry/components/events/ourlogs/ourlogsSection'; import {EventPackageData} from 'sentry/components/events/packageData'; import {EventRRWebIntegration} from 'sentry/components/events/rrwebIntegration'; import {DataSection} from 'sentry/components/events/styles'; @@ -407,7 +409,10 @@ export function EventDetailsContent({