|
@@ -1,4 +1,4 @@
|
|
|
-import {Fragment, useState} from 'react';
|
|
|
+import {Fragment} from 'react';
|
|
|
import {css} from '@emotion/react';
|
|
|
import styled from '@emotion/styled';
|
|
|
import {Location} from 'history';
|
|
@@ -9,7 +9,7 @@ import {DateTimeObject} from 'sentry/components/charts/utils';
|
|
|
import Link from 'sentry/components/links/link';
|
|
|
import LoadingError from 'sentry/components/loadingError';
|
|
|
import PanelTable from 'sentry/components/panels/panelTable';
|
|
|
-import {IconChevron, IconList, IconStar} from 'sentry/icons';
|
|
|
+import {IconStar} from 'sentry/icons';
|
|
|
import {t, tct} from 'sentry/locale';
|
|
|
import overflowEllipsis from 'sentry/styles/overflowEllipsis';
|
|
|
import space from 'sentry/styles/space';
|
|
@@ -23,6 +23,7 @@ import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
|
|
|
import type {Color} from 'sentry/utils/theme';
|
|
|
import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils';
|
|
|
|
|
|
+import CollapsePanel, {COLLAPSE_COUNT} from './collapsePanel';
|
|
|
import {ProjectBadge, ProjectBadgeContainer} from './styles';
|
|
|
import {groupByTrend} from './utils';
|
|
|
|
|
@@ -37,9 +38,6 @@ type TeamMiseryProps = {
|
|
|
period?: string | null;
|
|
|
};
|
|
|
|
|
|
-/** The number of elements to display before collapsing */
|
|
|
-const COLLAPSE_COUNT = 5;
|
|
|
-
|
|
|
function TeamMisery({
|
|
|
organization,
|
|
|
location,
|
|
@@ -50,14 +48,9 @@ function TeamMisery({
|
|
|
period,
|
|
|
error,
|
|
|
}: TeamMiseryProps) {
|
|
|
- const [isExpanded, setIsExpanded] = useState(false);
|
|
|
const miseryRenderer =
|
|
|
periodTableData?.meta && getFieldRenderer('user_misery', periodTableData.meta);
|
|
|
|
|
|
- function expandResults() {
|
|
|
- setIsExpanded(true);
|
|
|
- }
|
|
|
-
|
|
|
// Calculate trend, so we can sort based on it
|
|
|
const sortedTableData = (periodTableData?.data ?? [])
|
|
|
.map(dataRow => {
|
|
@@ -84,104 +77,99 @@ function TeamMisery({
|
|
|
}
|
|
|
|
|
|
return (
|
|
|
- <Fragment>
|
|
|
- <StyledPanelTable
|
|
|
- isEmpty={projects.length === 0 || periodTableData?.data.length === 0}
|
|
|
- emptyMessage={t('No key transactions starred by this team')}
|
|
|
- emptyAction={
|
|
|
- <Button
|
|
|
- size="small"
|
|
|
- external
|
|
|
- href="https://docs.sentry.io/product/performance/transaction-summary/#starring-key-transactions"
|
|
|
+ <CollapsePanel items={groupedData.length}>
|
|
|
+ {({isExpanded, showMoreButton}) => (
|
|
|
+ <Fragment>
|
|
|
+ <StyledPanelTable
|
|
|
+ isEmpty={projects.length === 0 || periodTableData?.data.length === 0}
|
|
|
+ emptyMessage={t('No key transactions starred by this team')}
|
|
|
+ emptyAction={
|
|
|
+ <Button
|
|
|
+ size="small"
|
|
|
+ external
|
|
|
+ href="https://docs.sentry.io/product/performance/transaction-summary/#starring-key-transactions"
|
|
|
+ >
|
|
|
+ {t('Learn More')}
|
|
|
+ </Button>
|
|
|
+ }
|
|
|
+ headers={[
|
|
|
+ <FlexCenter key="transaction">
|
|
|
+ <StyledIconStar isSolid color="yellow300" /> {t('Key transaction')}
|
|
|
+ </FlexCenter>,
|
|
|
+ t('Project'),
|
|
|
+ tct('Last [period]', {period}),
|
|
|
+ t('Last 7 Days'),
|
|
|
+ <RightAligned key="change">{t('Change')}</RightAligned>,
|
|
|
+ ]}
|
|
|
+ isLoading={isLoading}
|
|
|
>
|
|
|
- {t('Learn More')}
|
|
|
- </Button>
|
|
|
- }
|
|
|
- headers={[
|
|
|
- <FlexCenter key="transaction">
|
|
|
- <StyledIconStar isSolid color="yellow300" /> {t('Key transaction')}
|
|
|
- </FlexCenter>,
|
|
|
- t('Project'),
|
|
|
- tct('Last [period]', {period}),
|
|
|
- t('Last 7 Days'),
|
|
|
- <RightAligned key="change">{t('Change')}</RightAligned>,
|
|
|
- ]}
|
|
|
- isLoading={isLoading}
|
|
|
- >
|
|
|
- {groupedData.map((dataRow, idx) => {
|
|
|
- const project = projects.find(({slug}) => dataRow.project === slug);
|
|
|
- const {trend, project: projectId, transaction} = dataRow;
|
|
|
-
|
|
|
- const weekRow = weekTableData?.data.find(
|
|
|
- row => row.project === projectId && row.transaction === transaction
|
|
|
- );
|
|
|
- if (!weekRow || trend === null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- const periodMisery = miseryRenderer?.(dataRow, {organization, location});
|
|
|
- const weekMisery =
|
|
|
- weekRow && miseryRenderer?.(weekRow, {organization, location});
|
|
|
- const trendValue = Math.round(Math.abs(trend));
|
|
|
-
|
|
|
- if (idx >= COLLAPSE_COUNT && !isExpanded) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- return (
|
|
|
- <Fragment key={idx}>
|
|
|
- <KeyTransactionTitleWrapper>
|
|
|
- <div>
|
|
|
- <StyledIconStar isSolid color="yellow300" />
|
|
|
- </div>
|
|
|
- <TransactionWrapper>
|
|
|
- <Link
|
|
|
- to={transactionSummaryRouteWithQuery({
|
|
|
- orgSlug: organization.slug,
|
|
|
- transaction: dataRow.transaction as string,
|
|
|
- projectID: project?.id,
|
|
|
- query: {query: 'transaction.duration:<15m'},
|
|
|
- })}
|
|
|
- >
|
|
|
- {dataRow.transaction}
|
|
|
- </Link>
|
|
|
- </TransactionWrapper>
|
|
|
- </KeyTransactionTitleWrapper>
|
|
|
- <FlexCenter>
|
|
|
- <ProjectBadgeContainer>
|
|
|
- {project && <ProjectBadge avatarSize={18} project={project} />}
|
|
|
- </ProjectBadgeContainer>
|
|
|
- </FlexCenter>
|
|
|
- <FlexCenter>{periodMisery}</FlexCenter>
|
|
|
- <FlexCenter>{weekMisery ?? '\u2014'}</FlexCenter>
|
|
|
- <ScoreWrapper>
|
|
|
- {trendValue === 0 ? (
|
|
|
- <SubText>
|
|
|
- {`0\u0025 `}
|
|
|
- {t('change')}
|
|
|
- </SubText>
|
|
|
- ) : (
|
|
|
- <TrendText color={trend >= 0 ? 'green300' : 'red300'}>
|
|
|
- {`${trendValue}\u0025 `}
|
|
|
- {trend >= 0 ? t('better') : t('worse')}
|
|
|
- </TrendText>
|
|
|
- )}
|
|
|
- </ScoreWrapper>
|
|
|
- </Fragment>
|
|
|
- );
|
|
|
- })}
|
|
|
- </StyledPanelTable>
|
|
|
- {groupedData.length >= COLLAPSE_COUNT && !isExpanded && !isLoading && (
|
|
|
- <ShowMore onClick={expandResults}>
|
|
|
- <ShowMoreText>
|
|
|
- <StyledIconList color="gray300" />
|
|
|
- {tct('Show [count] More', {count: groupedData.length - 1 - COLLAPSE_COUNT})}
|
|
|
- </ShowMoreText>
|
|
|
-
|
|
|
- <IconChevron color="gray300" direction="down" />
|
|
|
- </ShowMore>
|
|
|
+ {groupedData.map((dataRow, idx) => {
|
|
|
+ const project = projects.find(({slug}) => dataRow.project === slug);
|
|
|
+ const {trend, project: projectId, transaction} = dataRow;
|
|
|
+
|
|
|
+ const weekRow = weekTableData?.data.find(
|
|
|
+ row => row.project === projectId && row.transaction === transaction
|
|
|
+ );
|
|
|
+ if (!weekRow || trend === null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const periodMisery = miseryRenderer?.(dataRow, {organization, location});
|
|
|
+ const weekMisery =
|
|
|
+ weekRow && miseryRenderer?.(weekRow, {organization, location});
|
|
|
+ const trendValue = Math.round(Math.abs(trend));
|
|
|
+
|
|
|
+ if (idx >= COLLAPSE_COUNT && !isExpanded) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Fragment key={idx}>
|
|
|
+ <KeyTransactionTitleWrapper>
|
|
|
+ <div>
|
|
|
+ <StyledIconStar isSolid color="yellow300" />
|
|
|
+ </div>
|
|
|
+ <TransactionWrapper>
|
|
|
+ <Link
|
|
|
+ to={transactionSummaryRouteWithQuery({
|
|
|
+ orgSlug: organization.slug,
|
|
|
+ transaction: dataRow.transaction as string,
|
|
|
+ projectID: project?.id,
|
|
|
+ query: {query: 'transaction.duration:<15m'},
|
|
|
+ })}
|
|
|
+ >
|
|
|
+ {dataRow.transaction}
|
|
|
+ </Link>
|
|
|
+ </TransactionWrapper>
|
|
|
+ </KeyTransactionTitleWrapper>
|
|
|
+ <FlexCenter>
|
|
|
+ <ProjectBadgeContainer>
|
|
|
+ {project && <ProjectBadge avatarSize={18} project={project} />}
|
|
|
+ </ProjectBadgeContainer>
|
|
|
+ </FlexCenter>
|
|
|
+ <FlexCenter>{periodMisery}</FlexCenter>
|
|
|
+ <FlexCenter>{weekMisery ?? '\u2014'}</FlexCenter>
|
|
|
+ <ScoreWrapper>
|
|
|
+ {trendValue === 0 ? (
|
|
|
+ <SubText>
|
|
|
+ {`0\u0025 `}
|
|
|
+ {t('change')}
|
|
|
+ </SubText>
|
|
|
+ ) : (
|
|
|
+ <TrendText color={trend >= 0 ? 'green300' : 'red300'}>
|
|
|
+ {`${trendValue}\u0025 `}
|
|
|
+ {trend >= 0 ? t('better') : t('worse')}
|
|
|
+ </TrendText>
|
|
|
+ )}
|
|
|
+ </ScoreWrapper>
|
|
|
+ </Fragment>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </StyledPanelTable>
|
|
|
+ {!isLoading && showMoreButton}
|
|
|
+ </Fragment>
|
|
|
)}
|
|
|
- </Fragment>
|
|
|
+ </CollapsePanel>
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -340,23 +328,3 @@ const SubText = styled('div')`
|
|
|
const TrendText = styled('div')<{color: Color}>`
|
|
|
color: ${p => p.theme[p.color]};
|
|
|
`;
|
|
|
-
|
|
|
-const ShowMore = styled('div')`
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: ${space(1)} ${space(2)};
|
|
|
- font-size: ${p => p.theme.fontSizeMedium};
|
|
|
- color: ${p => p.theme.subText};
|
|
|
- cursor: pointer;
|
|
|
- border-top: 1px solid ${p => p.theme.border};
|
|
|
-`;
|
|
|
-
|
|
|
-const StyledIconList = styled(IconList)`
|
|
|
- margin-right: ${space(1)};
|
|
|
-`;
|
|
|
-
|
|
|
-const ShowMoreText = styled('div')`
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-grow: 1;
|
|
|
-`;
|