123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- import {Fragment} from 'react';
- import styled from '@emotion/styled';
- import classNames from 'classnames';
- import Count from 'sentry/components/count';
- import EventOrGroupTitle from 'sentry/components/eventOrGroupTitle';
- import EventAnnotation from 'sentry/components/events/eventAnnotation';
- import EventMessage from 'sentry/components/events/eventMessage';
- import {Hovercard} from 'sentry/components/hovercard';
- import Link from 'sentry/components/links/link';
- import TimeSince from 'sentry/components/timeSince';
- import {t} from 'sentry/locale';
- import space from 'sentry/styles/space';
- import {Group} from 'sentry/types';
- import {getMessage} from 'sentry/utils/events';
- type Props = {
- card: boolean;
- children: React.ReactNode;
- issue: Group;
- orgId: string;
- to: string;
- };
- const IssueLink = ({children, orgId, issue, to, card = true}: Props) => {
- if (!card) {
- return <Link to={to}>{children}</Link>;
- }
- const message = getMessage(issue);
- const className = classNames({
- isBookmarked: issue.isBookmarked,
- hasSeen: issue.hasSeen,
- isResolved: issue.status === 'resolved',
- });
- const streamPath = `/organizations/${orgId}/issues/`;
- const hovercardBody = (
- <div className={className}>
- <Section>
- <Title>
- <StyledEventOrGroupTitle data={issue} />
- </Title>
- <HovercardEventMessage
- level={issue.level}
- levelIndicatorSize="9px"
- message={message}
- annotations={
- <Fragment>
- {issue.logger && (
- <EventAnnotation>
- <Link
- to={{
- pathname: streamPath,
- query: {query: `logger:${issue.logger}`, referrer: 'issue-link'},
- }}
- >
- {issue.logger}
- </Link>
- </EventAnnotation>
- )}
- {issue.annotations.map((annotation, i) => (
- <EventAnnotation key={i} dangerouslySetInnerHTML={{__html: annotation}} />
- ))}
- </Fragment>
- }
- />
- </Section>
- <Grid>
- <div>
- <GridHeader>{t('First Seen')}</GridHeader>
- <StyledTimeSince date={issue.firstSeen} />
- </div>
- <div>
- <GridHeader>{t('Last Seen')}</GridHeader>
- <StyledTimeSince date={issue.lastSeen} />
- </div>
- <div>
- <GridHeader>{t('Occurrences')}</GridHeader>
- <Count value={issue.count} />
- </div>
- <div>
- <GridHeader>{t('Users Affected')}</GridHeader>
- <Count value={issue.userCount} />
- </div>
- </Grid>
- </div>
- );
- return (
- <Hovercard body={hovercardBody} header={issue.shortId}>
- <Link to={to}>{children}</Link>
- </Hovercard>
- );
- };
- export default IssueLink;
- const Title = styled('div')`
- ${p => p.theme.overflowEllipsis};
- margin: 0 0 ${space(0.5)};
- `;
- const StyledEventOrGroupTitle = styled(EventOrGroupTitle)`
- font-weight: 600;
- font-size: ${p => p.theme.fontSizeMedium};
- em {
- font-style: normal;
- font-weight: 400;
- font-size: ${p => p.theme.fontSizeSmall};
- }
- `;
- const Section = styled('section')`
- margin-bottom: ${space(2)};
- `;
- const Grid = styled('div')`
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: ${space(2)};
- `;
- const HovercardEventMessage = styled(EventMessage)`
- font-size: 12px;
- `;
- const GridHeader = styled('h5')`
- color: ${p => p.theme.gray300};
- font-size: 11px;
- margin-bottom: ${space(0.5)};
- text-transform: uppercase;
- `;
- const StyledTimeSince = styled(TimeSince)`
- color: inherit;
- `;
|