Files
2024-02-15 17:01:50 +00:00

220 lines
5.9 KiB
TypeScript

import {Fragment} from 'react';
import styled from '@emotion/styled';
import Access from 'sentry/components/acl/access';
import {Role} from 'sentry/components/acl/role';
import {Button} from 'sentry/components/button';
import ButtonBar from 'sentry/components/buttonBar';
import Confirm from 'sentry/components/confirm';
import FileSize from 'sentry/components/fileSize';
import Link from 'sentry/components/links/link';
import Tag from 'sentry/components/tag';
import TimeSince from 'sentry/components/timeSince';
import {Tooltip} from 'sentry/components/tooltip';
import {IconClock, IconDelete, IconDownload} from 'sentry/icons';
import {t, tct} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Project} from 'sentry/types';
import type {DebugFile} from 'sentry/types/debugFiles';
import {getFeatureTooltip, getPrettyFileType} from './utils';
type Props = {
debugFile: DebugFile;
downloadRole: string;
downloadUrl: string;
onDelete: (id: string) => void;
orgSlug: string;
project: Project;
showDetails: boolean;
};
function DebugFileRow({
debugFile,
showDetails,
downloadUrl,
downloadRole,
onDelete,
orgSlug,
project,
}: Props) {
const {id, data, debugId, uuid, size, dateCreated, objectName, symbolType, codeId} =
debugFile;
const {features} = data || {};
return (
<Fragment>
<Column>
<div>
<DebugId>{debugId || uuid}</DebugId>
</div>
<TimeAndSizeWrapper>
<StyledFileSize bytes={size} />
<TimeWrapper>
<IconClock size="xs" />
<TimeSince date={dateCreated} />
</TimeWrapper>
</TimeAndSizeWrapper>
</Column>
<Column>
<Name>
{symbolType === 'proguard' && objectName === 'proguard-mapping'
? '\u2015'
: objectName}
</Name>
<Description>
<DescriptionText>{getPrettyFileType(debugFile)}</DescriptionText>
{features && (
<FeatureTags>
{features.map(feature => (
<StyledTag key={feature} tooltipText={getFeatureTooltip(feature)}>
{feature}
</StyledTag>
))}
</FeatureTags>
)}
{showDetails && (
<div>
{/* there will be more stuff here in the future */}
{codeId && (
<DetailsItem>
{t('Code ID')}: {codeId}
</DetailsItem>
)}
</div>
)}
</Description>
</Column>
<RightColumn>
<ButtonBar gap={0.5}>
<Role role={downloadRole}>
{({hasRole}) => (
<Tooltip
disabled={hasRole}
title={tct(
'Debug files can only be downloaded by users with organization [downloadRole] role[orHigher]. This can be changed in [settingsLink:Debug Files Access] settings.',
{
downloadRole,
orHigher: downloadRole !== 'owner' ? ` ${t('or higher')}` : '',
settingsLink: <Link to={`/settings/${orgSlug}/#debugFilesRole`} />,
}
)}
isHoverable
>
<Button
size="xs"
icon={<IconDownload />}
href={downloadUrl}
disabled={!hasRole}
>
{t('Download')}
</Button>
</Tooltip>
)}
</Role>
<Access access={['project:write']} project={project}>
{({hasAccess}) => (
<Tooltip
disabled={hasAccess}
title={t('You do not have permission to delete debug files.')}
>
<Confirm
confirmText={t('Delete')}
message={t('Are you sure you wish to delete this file?')}
onConfirm={() => onDelete(id)}
disabled={!hasAccess}
>
<Button
priority="danger"
icon={<IconDelete />}
size="xs"
disabled={!hasAccess}
data-test-id="delete-dif"
aria-label={t('Delete')}
/>
</Confirm>
</Tooltip>
)}
</Access>
</ButtonBar>
</RightColumn>
</Fragment>
);
}
const DescriptionText = styled('span')`
display: inline-flex;
margin: 0 ${space(1)} ${space(1)} 0;
`;
const FeatureTags = styled('div')`
display: inline-flex;
flex-wrap: wrap;
margin: -${space(0.5)};
`;
const StyledTag = styled(Tag)`
padding: ${space(0.5)};
`;
const Column = styled('div')`
display: flex;
flex-direction: column;
align-items: flex-start;
`;
const RightColumn = styled('div')`
display: flex;
justify-content: flex-end;
align-items: flex-start;
margin-top: ${space(1)};
`;
const DebugId = styled('code')`
font-size: ${p => p.theme.fontSizeSmall};
`;
const TimeAndSizeWrapper = styled('div')`
width: 100%;
display: flex;
font-size: ${p => p.theme.fontSizeSmall};
margin-top: ${space(1)};
color: ${p => p.theme.subText};
align-items: center;
`;
const StyledFileSize = styled(FileSize)`
flex: 1;
padding-left: ${space(0.5)};
`;
const TimeWrapper = styled('div')`
display: grid;
gap: ${space(0.5)};
grid-template-columns: min-content 1fr;
flex: 2;
align-items: center;
padding-left: ${space(0.5)};
`;
const Name = styled('div')`
font-size: ${p => p.theme.fontSizeMedium};
margin-bottom: ${space(1)};
`;
const Description = styled('div')`
font-size: ${p => p.theme.fontSizeSmall};
color: ${p => p.theme.subText};
@media (max-width: ${p => p.theme.breakpoints.large}) {
line-height: 1.7;
}
`;
const DetailsItem = styled('div')`
${p => p.theme.overflowEllipsis}
margin-top: ${space(1)}
`;
export default DebugFileRow;