import {Component, Fragment} from 'react'; import {withRouter, WithRouterProps} from 'react-router'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import capitalize from 'lodash/capitalize'; import EventOrGroupTitle from 'app/components/eventOrGroupTitle'; import GlobalSelectionLink from 'app/components/globalSelectionLink'; import Tooltip from 'app/components/tooltip'; import {IconMute, IconStar} from 'app/icons'; import {tct} from 'app/locale'; import {Group, GroupTombstone, Level, Organization} from 'app/types'; import {Event} from 'app/types/event'; import {getLocation, getMessage} from 'app/utils/events'; import withOrganization from 'app/utils/withOrganization'; import UnhandledTag, { TagAndMessageWrapper, } from 'app/views/organizationGroupDetails/unhandledTag'; type DefaultProps = { includeLink: boolean; size: 'small' | 'normal'; }; type Props = WithRouterProps<{orgId: string}> & { organization: Organization; data: Event | Group | GroupTombstone; hideIcons?: boolean; hideLevel?: boolean; query?: string; className?: string; /** Group link clicked */ onClick?: () => void; index?: number; } & Partial; /** * Displays an event or group/issue title (i.e. in Stream) */ class EventOrGroupHeader extends Component { static defaultProps: DefaultProps = { includeLink: true, size: 'normal', }; getTitleChildren() { const {hideIcons, hideLevel, data, index} = this.props; const {level, status, isBookmarked, hasSeen} = data as Group; return ( {!hideLevel && level && ( )} {!hideIcons && status === 'ignored' && ( )} {!hideIcons && isBookmarked && ( )} ); } getTitle() { const {includeLink, data, params, location, onClick} = this.props; const orgId = params?.orgId; const {id, status} = data as Group; const {eventID, groupID} = data as Event; const props = { 'data-test-id': status === 'resolved' ? 'resolved-issue' : null, style: status === 'resolved' ? {textDecoration: 'line-through'} : undefined, }; if (includeLink) { return ( {this.getTitleChildren()} ); } else { return {this.getTitleChildren()}; } } render() { const {className, size, data, organization} = this.props; const location = getLocation(data); const message = getMessage(data); const {isUnhandled} = data as Group; const showUnhandled = isUnhandled && !organization.features.includes('inbox'); return (
{this.getTitle()} {location && {location}} {(message || showUnhandled) && ( {showUnhandled && } {message && {message}} )}
); } } const truncateStyles = css` overflow: hidden; max-width: 100%; text-overflow: ellipsis; white-space: nowrap; `; const getMargin = ({size}) => { if (size === 'small') { return 'margin: 0;'; } return 'margin: 0 0 5px'; }; const Title = styled('div')` ${truncateStyles}; line-height: 1; ${getMargin}; & em { font-size: ${p => p.theme.fontSizeMedium}; font-style: normal; font-weight: 300; color: ${p => p.theme.subText}; } `; const LocationWrapper = styled('div')` ${truncateStyles}; ${getMargin}; direction: rtl; text-align: left; font-size: ${p => p.theme.fontSizeMedium}; color: ${p => p.theme.subText}; span { direction: ltr; } `; function Location(props) { const {children, ...rest} = props; return ( {tct('in [location]', { location: {children}, })} ); } const StyledTagAndMessageWrapper = styled(TagAndMessageWrapper)` ${getMargin}; `; const Message = styled('div')` ${truncateStyles}; font-size: ${p => p.theme.fontSizeMedium}; `; const IconWrapper = styled('span')` position: relative; top: 2px; margin-right: 5px; `; const GroupLevel = styled('div')<{level: Level}>` position: absolute; left: -1px; width: 9px; height: 15px; border-radius: 0 3px 3px 0; background-color: ${p => p.theme.level[p.level] ?? p.theme.level.default}; & span { display: block; width: 9px; height: 15px; } `; export default withRouter(withOrganization(EventOrGroupHeader));