diff --git a/static/app/views/explore/components/schemaHints/schemaHintsList.tsx b/static/app/views/explore/components/schemaHints/schemaHintsList.tsx index dddab9649b3e83..bb80f0884f31c4 100644 --- a/static/app/views/explore/components/schemaHints/schemaHintsList.tsx +++ b/static/app/views/explore/components/schemaHints/schemaHintsList.tsx @@ -118,6 +118,8 @@ const FILTER_KEY_SECTIONS: Record = { [SchemaHintsSources.EXPLORE]: SPANS_FILTER_KEY_SECTIONS, [SchemaHintsSources.LOGS]: LOGS_FILTER_KEY_SECTIONS, [SchemaHintsSources.CONVERSATIONS]: SPANS_FILTER_KEY_SECTIONS, + // TODO: add error filter key sections when they are implemented + [SchemaHintsSources.ERRORS]: [], }; function getFilterKeySections(source: SchemaHintsSources) { diff --git a/static/app/views/explore/components/schemaHints/schemaHintsUtils.tsx b/static/app/views/explore/components/schemaHints/schemaHintsUtils.tsx index 74dbbe618a239a..dccb123996a0c0 100644 --- a/static/app/views/explore/components/schemaHints/schemaHintsUtils.tsx +++ b/static/app/views/explore/components/schemaHints/schemaHintsUtils.tsx @@ -63,9 +63,11 @@ const SCHEMA_HINTS_HIDDEN_KEYS: string[] = [ ]; export enum SchemaHintsSources { + // TODO: change Explore to Spans because Explore is too broad and confusing here EXPLORE = 'explore', LOGS = 'logs', CONVERSATIONS = 'conversations', + ERRORS = 'errors', } export const getSchemaHintsListOrder = (source: SchemaHintsSources) => { @@ -76,6 +78,11 @@ export const getSchemaHintsListOrder = (source: SchemaHintsSources) => { return SCHEMA_HINTS_LIST_ORDER_KEYS_CONVERSATIONS; } + if (source === SchemaHintsSources.ERRORS) { + // TODO: check to see which keys we want to display for errors + return []; + } + return SCHEMA_HINTS_LIST_ORDER_KEYS_EXPLORE; }; diff --git a/static/app/views/explore/errors/body.spec.tsx b/static/app/views/explore/errors/body.spec.tsx new file mode 100644 index 00000000000000..0150fc02ec34c2 --- /dev/null +++ b/static/app/views/explore/errors/body.spec.tsx @@ -0,0 +1,57 @@ +import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; + +import {ErrorsContentSection, ErrorsControlSection} from './body'; + +describe('ErrorsControlSection', () => { + beforeEach(() => { + localStorage.clear(); + }); + + it('renders as an aside element', () => { + render(); + expect(screen.getByRole('complementary')).toBeInTheDocument(); + }); +}); + +describe('ErrorsContentSection', () => { + it('renders collapse sidebar button when expanded', () => { + const setControlSectionExpanded = jest.fn(); + render( + + ); + + const collapseButton = screen.getByRole('button', {name: 'Collapse sidebar'}); + expect(collapseButton).toBeInTheDocument(); + expect(collapseButton).not.toHaveTextContent('Advanced'); + }); + + it('renders expand sidebar button when collapsed', () => { + const setControlSectionExpanded = jest.fn(); + render( + + ); + + const expandButton = screen.getByRole('button', {name: 'Expand sidebar'}); + expect(expandButton).toBeInTheDocument(); + expect(expandButton).toHaveTextContent('Advanced'); + }); + + it('calls setControlSectionExpanded when clicking collapse button', async () => { + const setControlSectionExpanded = jest.fn(); + render( + + ); + + await userEvent.click(screen.getByRole('button', {name: 'Collapse sidebar'})); + expect(setControlSectionExpanded).toHaveBeenCalledWith(false); + }); +}); diff --git a/static/app/views/explore/errors/body.tsx b/static/app/views/explore/errors/body.tsx new file mode 100644 index 00000000000000..23f7076862e9e5 --- /dev/null +++ b/static/app/views/explore/errors/body.tsx @@ -0,0 +1,52 @@ +import {IconChevron} from 'sentry/icons/iconChevron'; +import {t} from 'sentry/locale'; +import {OverChartButtonGroup} from 'sentry/views/explore/components/overChartButtonGroup'; +import { + ExploreContentSection, + ExploreControlSection, +} from 'sentry/views/explore/components/styles'; +import {ChevronButton} from 'sentry/views/explore/spans/spansTab'; + +interface ErrorsControlSectionProps { + controlSectionExpanded: boolean; +} + +export function ErrorsControlSection({ + controlSectionExpanded, +}: ErrorsControlSectionProps) { + return ; +} + +interface ErrorsContentSectionProps { + controlSectionExpanded: boolean; + setControlSectionExpanded: (expanded: boolean) => void; +} + +export function ErrorsContentSection({ + controlSectionExpanded, + setControlSectionExpanded, +}: ErrorsContentSectionProps) { + return ( + + + + } + onClick={() => setControlSectionExpanded(!controlSectionExpanded)} + > + {controlSectionExpanded ? null : t('Advanced')} + + + + ); +} diff --git a/static/app/views/explore/errors/content.spec.tsx b/static/app/views/explore/errors/content.spec.tsx index d4198cf7f3ad4f..19dde6ac6f698f 100644 --- a/static/app/views/explore/errors/content.spec.tsx +++ b/static/app/views/explore/errors/content.spec.tsx @@ -1,11 +1,11 @@ import {OrganizationFixture} from 'sentry-fixture/organization'; import {ProjectFixture} from 'sentry-fixture/project'; -import {render, screen} from 'sentry-test/reactTestingLibrary'; +import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; import {PageFiltersStore} from 'sentry/components/pageFilters/store'; -import ErrorsContent from './content'; +import ErrorsContent, {ErrorsBody} from './content'; describe('ErrorsContent', () => { beforeEach(() => { @@ -59,3 +59,27 @@ describe('ErrorsContent', () => { ).toBeInTheDocument(); }); }); + +describe('ErrorsBody', () => { + beforeEach(() => { + localStorage.clear(); + }); + + it('renders with sidebar expanded by default', () => { + render(); + const collapseButton = screen.getByRole('button', {name: 'Collapse sidebar'}); + expect(collapseButton).toBeInTheDocument(); + expect(collapseButton).not.toHaveTextContent('Advanced'); + }); + + it('collapses sidebar when chevron button is clicked', async () => { + render(); + + const collapseButton = screen.getByRole('button', {name: 'Collapse sidebar'}); + await userEvent.click(collapseButton); + + const expandButton = screen.getByRole('button', {name: 'Expand sidebar'}); + expect(expandButton).toBeInTheDocument(); + expect(expandButton).toHaveTextContent('Advanced'); + }); +}); diff --git a/static/app/views/explore/errors/content.tsx b/static/app/views/explore/errors/content.tsx index 2d3fb49ad0fb3a..c90ebe193d5ce4 100644 --- a/static/app/views/explore/errors/content.tsx +++ b/static/app/views/explore/errors/content.tsx @@ -6,8 +6,16 @@ import {PageFiltersContainer} from 'sentry/components/pageFilters/container'; import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle'; import {t} from 'sentry/locale'; import {useOrganization} from 'sentry/utils/useOrganization'; -import {ExploreBodySearch} from 'sentry/views/explore/components/styles'; +import { + ExploreBodyContent, + ExploreBodySearch, +} from 'sentry/views/explore/components/styles'; +import { + ErrorsContentSection, + ErrorsControlSection, +} from 'sentry/views/explore/errors/body'; import {ErrorsFilterSection} from 'sentry/views/explore/errors/filterContent'; +import {useControlSectionExpanded} from 'sentry/views/explore/hooks/useControlSectionExpanded'; export default function ErrorsContent() { const organization = useOrganization(); @@ -22,6 +30,7 @@ export default function ErrorsContent() { + ); @@ -41,3 +50,21 @@ function ErrorsHeader() { ); } + +const ERRORS_TOOLBAR_STORAGE_KEY = 'explore-errors-toolbar'; + +export function ErrorsBody() { + const [controlSectionExpanded, setControlSectionExpanded] = useControlSectionExpanded( + ERRORS_TOOLBAR_STORAGE_KEY + ); + + return ( + + + + + ); +} diff --git a/static/app/views/explore/errors/filterContent.tsx b/static/app/views/explore/errors/filterContent.tsx index 2e0240d87e6a6d..836a9dc37e3fcc 100644 --- a/static/app/views/explore/errors/filterContent.tsx +++ b/static/app/views/explore/errors/filterContent.tsx @@ -6,6 +6,9 @@ import {EnvironmentPageFilter} from 'sentry/components/pageFilters/environment/e import {ProjectPageFilter} from 'sentry/components/pageFilters/project/projectPageFilter'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; import {t} from 'sentry/locale'; +import {SchemaHintsList} from 'sentry/views/explore/components/schemaHints/schemaHintsList'; +import {SchemaHintsSources} from 'sentry/views/explore/components/schemaHints/schemaHintsUtils'; +import {ExploreSchemaHintsSection} from 'sentry/views/explore/components/styles'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; import {StyledPageFilterBar} from 'sentry/views/explore/spans/spansTabSearchSection'; import {TraceItemDataset} from 'sentry/views/explore/types'; @@ -40,6 +43,17 @@ export function ErrorsFilterSection() { stringSecondaryAliases={{}} /> + + + ); diff --git a/static/app/views/explore/hooks/useControlSectionExpanded.tsx b/static/app/views/explore/hooks/useControlSectionExpanded.tsx new file mode 100644 index 00000000000000..9eb607cc50b0bd --- /dev/null +++ b/static/app/views/explore/hooks/useControlSectionExpanded.tsx @@ -0,0 +1,19 @@ +import {useCallback} from 'react'; + +import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; + +export function useControlSectionExpanded(localStorageKey: string) { + const [controlSectionExpanded, _setControlSectionExpanded] = useLocalStorageState( + localStorageKey, + 'expanded' + ); + + const setControlSectionExpanded = useCallback( + (expanded: boolean) => { + _setControlSectionExpanded(expanded ? 'expanded' : ''); + }, + [_setControlSectionExpanded] + ); + + return [controlSectionExpanded === 'expanded', setControlSectionExpanded] as const; +} diff --git a/static/app/views/explore/metrics/metricsTab.tsx b/static/app/views/explore/metrics/metricsTab.tsx index a10923b340c4e5..14a248c3ff8767 100644 --- a/static/app/views/explore/metrics/metricsTab.tsx +++ b/static/app/views/explore/metrics/metricsTab.tsx @@ -1,4 +1,3 @@ -import {useCallback} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; @@ -13,7 +12,6 @@ import {ProjectPageFilter} from 'sentry/components/pageFilters/project/projectPa import {IconChevron} from 'sentry/icons/iconChevron'; import {t} from 'sentry/locale'; import {useChartInterval} from 'sentry/utils/useChartInterval'; -import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; import {useOrganization} from 'sentry/utils/useOrganization'; import {WidgetSyncContextProvider} from 'sentry/views/dashboards/contexts/widgetSyncContext'; import {OverChartButtonGroup} from 'sentry/views/explore/components/overChartButtonGroup'; @@ -25,6 +23,7 @@ import { } from 'sentry/views/explore/components/styles'; import {ToolbarVisualizeAddChart} from 'sentry/views/explore/components/toolbar/toolbarVisualize'; import {useMetricsAnalytics} from 'sentry/views/explore/hooks/useAnalytics'; +import {useControlSectionExpanded} from 'sentry/views/explore/hooks/useControlSectionExpanded'; import {useMetricOptions} from 'sentry/views/explore/hooks/useMetricOptions'; import {MetricPanel} from 'sentry/views/explore/metrics/metricPanel'; import {canUseMetricsUIRefresh} from 'sentry/views/explore/metrics/metricsFlags'; @@ -50,25 +49,10 @@ type MetricsTabProps = { const METRICS_TOOLBAR_STORAGE_KEY = 'explore-metrics-toolbar'; -function useMetricsControlSectionExpanded() { - const [controlSectionExpanded, _setControlSectionExpanded] = useLocalStorageState( - METRICS_TOOLBAR_STORAGE_KEY, - 'expanded' - ); - - const setControlSectionExpanded = useCallback( - (expanded: boolean) => { - _setControlSectionExpanded(expanded ? 'expanded' : ''); - }, - [_setControlSectionExpanded] - ); - - return [controlSectionExpanded === 'expanded', setControlSectionExpanded] as const; -} - function MetricsTabContentRefreshLayout({datePageFilterProps}: MetricsTabProps) { - const [controlSectionExpanded, setControlSectionExpanded] = - useMetricsControlSectionExpanded(); + const [controlSectionExpanded, setControlSectionExpanded] = useControlSectionExpanded( + METRICS_TOOLBAR_STORAGE_KEY + ); return ( diff --git a/static/app/views/explore/spans/spansTab.tsx b/static/app/views/explore/spans/spansTab.tsx index 61b7c5c78cfbbd..18d6128cd9af06 100644 --- a/static/app/views/explore/spans/spansTab.tsx +++ b/static/app/views/explore/spans/spansTab.tsx @@ -1,4 +1,4 @@ -import {Fragment, useCallback, useEffect, useMemo} from 'react'; +import {Fragment, useEffect, useMemo} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; @@ -22,7 +22,6 @@ import type {Project} from 'sentry/types/project'; import {defined} from 'sentry/utils'; import {DiscoverDatasets} from 'sentry/utils/discover/types'; import {useChartInterval} from 'sentry/utils/useChartInterval'; -import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; import {useOrganization} from 'sentry/utils/useOrganization'; import {ChartSelectionProvider} from 'sentry/views/explore/components/attributeBreakdowns/chartSelectionContext'; import {OverChartButtonGroup} from 'sentry/views/explore/components/overChartButtonGroup'; @@ -34,6 +33,7 @@ import { } from 'sentry/views/explore/components/styles'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; import {useAnalytics} from 'sentry/views/explore/hooks/useAnalytics'; +import {useControlSectionExpanded} from 'sentry/views/explore/hooks/useControlSectionExpanded'; import {useCrossEventQueries} from 'sentry/views/explore/hooks/useCrossEventQueries'; import {useExploreAggregatesTable} from 'sentry/views/explore/hooks/useExploreAggregatesTable'; import {useExploreSpansTable} from 'sentry/views/explore/hooks/useExploreSpansTable'; @@ -90,30 +90,18 @@ export function SpansTabOnboarding({ ); } -function useControlSectionExpanded() { - const [controlSectionExpanded, _setControlSectionExpanded] = useLocalStorageState( - 'explore-spans-toolbar', - 'expanded' - ); - - const setControlSectionExpanded = useCallback( - (expanded: boolean) => { - _setControlSectionExpanded(expanded ? 'expanded' : ''); - }, - [_setControlSectionExpanded] - ); - - return [controlSectionExpanded === 'expanded', setControlSectionExpanded] as const; -} - interface SpanTabProps { datePageFilterProps: DatePageFilterProps; } +const SPANS_TOOLBAR_STORAGE_KEY = 'explore-spans-toolbar'; + export function SpansTabContent({datePageFilterProps}: SpanTabProps) { useVisitExplore(); - const [controlSectionExpanded, setControlSectionExpanded] = useControlSectionExpanded(); + const [controlSectionExpanded, setControlSectionExpanded] = useControlSectionExpanded( + SPANS_TOOLBAR_STORAGE_KEY + ); return ( @@ -365,7 +353,7 @@ const OnboardingContentSection = styled('section')` grid-column: 1/3; `; -const ChevronButton = styled(Button)<{expanded: boolean}>` +export const ChevronButton = styled(Button)<{expanded: boolean}>` display: none; @media (min-width: ${p => p.theme.breakpoints.md}) {