diff --git a/static/app/components/replays/releaseDropdownFilter.tsx b/static/app/components/replays/releaseDropdownFilter.tsx new file mode 100644 index 00000000000000..9b217f1faa5f58 --- /dev/null +++ b/static/app/components/replays/releaseDropdownFilter.tsx @@ -0,0 +1,72 @@ +import styled from '@emotion/styled'; + +import {Button} from 'sentry/components/core/button'; +import {DropdownMenu} from 'sentry/components/dropdownMenu'; +import {IconEllipsis} from 'sentry/icons'; +import {t} from 'sentry/locale'; +import {space} from 'sentry/styles/space'; +import {useLocation} from 'sentry/utils/useLocation'; +import {useNavigate} from 'sentry/utils/useNavigate'; +import useOrganization from 'sentry/utils/useOrganization'; +import {makeReleasesPathname} from 'sentry/views/releases/utils/pathnames'; +import {makeReplaysPathname} from 'sentry/views/replays/pathnames'; +import type {ReplayListLocationQuery} from 'sentry/views/replays/types'; + +export default function ReleaseDropdownFilter({val}: {val: string}) { + const location = useLocation(); + const navigate = useNavigate(); + const organization = useOrganization(); + + return ( + + navigate({ + pathname: makeReplaysPathname({ + path: '/', + organization, + }), + query: { + ...location.query, + query: `release:"${val}"`, + }, + }), + }, + { + key: 'details', + label: t('Go to release details'), + onAction: () => + navigate( + makeReleasesPathname({ + organization, + path: `/${encodeURIComponent(val)}/`, + }) + ), + }, + ]} + usePortal + size="xs" + offset={4} + position="bottom" + preventOverflowOptions={{padding: 4}} + flipOptions={{ + fallbackPlacements: ['top', 'right-start', 'right-end', 'left-start', 'left-end'], + }} + trigger={triggerProps => ( + } + size="zero" + /> + )} + /> + ); +} + +const TriggerButton = styled(Button)` + padding: ${space(0.5)}; +`; diff --git a/static/app/components/replays/replayTagsTableRow.tsx b/static/app/components/replays/replayTagsTableRow.tsx index 766b99d57b9ecb..41ad7b19ddfdb5 100644 --- a/static/app/components/replays/replayTagsTableRow.tsx +++ b/static/app/components/replays/replayTagsTableRow.tsx @@ -7,9 +7,13 @@ import {Tooltip} from 'sentry/components/core/tooltip'; import {AnnotatedText} from 'sentry/components/events/meta/annotatedText'; import {KeyValueTableRow} from 'sentry/components/keyValueTable'; import Link from 'sentry/components/links/link'; +import ReleaseDropdownFilter from 'sentry/components/replays/releaseDropdownFilter'; import {CollapsibleValue} from 'sentry/components/structuredEventData/collapsibleValue'; import Version from 'sentry/components/version'; import {space} from 'sentry/styles/space'; +import useOrganization from 'sentry/utils/useOrganization'; +import {QuickContextHoverWrapper} from 'sentry/views/discover/table/quickContext/quickContextWrapper'; +import {ContextType} from 'sentry/views/discover/table/quickContext/utils'; interface Props { name: string; @@ -25,6 +29,8 @@ const expandedViewKeys = [ 'sdk.replay.maskingRules', ]; +const releaseKeys = ['release', 'releases']; + function renderValueList(values: ReactNode[]) { if (typeof values[0] === 'string') { return values[0]; @@ -44,15 +50,32 @@ function renderValueList(values: ReactNode[]) { } function ReplayTagsTableRow({name, values, generateUrl}: Props) { + const organization = useOrganization(); + const renderTagValue = useMemo(() => { - if (name === 'release') { + if (releaseKeys.includes(name)) { return values.map((value, index) => ( {index > 0 && ', '} - + + + + + + )); } + if ( expandedViewKeys.includes(name) && renderValueList(values) && @@ -75,7 +98,7 @@ function ReplayTagsTableRow({name, values, generateUrl}: Props) { ); }); - }, [name, values, generateUrl]); + }, [name, values, generateUrl, organization]); return ( p.theme.overflowEllipsis}; `; + +const StyledVersionContainer = styled('div')` + display: flex; + justify-content: flex-end; + gap: ${space(0.75)}; +`; diff --git a/static/app/views/replays/replayTable/tableCell.tsx b/static/app/views/replays/replayTable/tableCell.tsx index 45a865cb75370f..761a9163a89646 100644 --- a/static/app/views/replays/replayTable/tableCell.tsx +++ b/static/app/views/replays/replayTable/tableCell.tsx @@ -26,7 +26,6 @@ import type {ValidSize} from 'sentry/styles/space'; import {space} from 'sentry/styles/space'; import type {Organization} from 'sentry/types/organization'; import {trackAnalytics} from 'sentry/utils/analytics'; -import {browserHistory} from 'sentry/utils/browserHistory'; import type EventView from 'sentry/utils/discover/eventView'; import {spanOperationRelativeBreakdownRenderer} from 'sentry/utils/discover/fieldRenderers'; import {getShortEventId} from 'sentry/utils/events'; @@ -34,6 +33,7 @@ import {decodeScalar} from 'sentry/utils/queryString'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useMedia from 'sentry/utils/useMedia'; +import {useNavigate} from 'sentry/utils/useNavigate'; import useProjects from 'sentry/utils/useProjects'; import type {ReplayListRecordWithTx} from 'sentry/views/performance/transactionSummary/transactionReplays/useReplaysWithTxData'; import {makeReplaysPathname} from 'sentry/views/replays/pathnames'; @@ -53,10 +53,12 @@ function generateAction({ value, edit, location, + navigate, }: { edit: EditType; key: string; location: Location; + navigate: ReturnType; value: string; }) { const search = new MutableSearch(decodeScalar(location.query.query) || ''); @@ -65,7 +67,7 @@ function generateAction({ edit === 'set' ? search.setFilterValues(key, [value]) : search.removeFilter(key); const onAction = () => { - browserHistory.push({ + navigate({ pathname: location.pathname, query: { ...location.query, @@ -87,6 +89,8 @@ function OSBrowserDropdownFilter({ version: string | null; }) { const location = useLocation(); + const navigate = useNavigate(); + return ( (); + const navigate = useNavigate(); + return ( ' + formatter(val), edit: 'set', location, + navigate, }), }, { @@ -223,6 +235,7 @@ function NumericDropdownFilter({ value: '<' + formatter(val), edit: 'set', location, + navigate, }), }, { @@ -233,6 +246,7 @@ function NumericDropdownFilter({ value: formatter(val), edit: 'remove', location, + navigate, }), }, ]}