debugFileRow.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import Access from 'app/components/acl/access';
  4. import Role from 'app/components/acl/role';
  5. import Button from 'app/components/button';
  6. import ButtonBar from 'app/components/buttonBar';
  7. import Confirm from 'app/components/confirm';
  8. import FileSize from 'app/components/fileSize';
  9. import Tag from 'app/components/tag';
  10. import TimeSince from 'app/components/timeSince';
  11. import Tooltip from 'app/components/tooltip';
  12. import {IconClock, IconDelete, IconDownload} from 'app/icons';
  13. import {t} from 'app/locale';
  14. import overflowEllipsis from 'app/styles/overflowEllipsis';
  15. import space from 'app/styles/space';
  16. import {DebugFile} from 'app/types/debugFiles';
  17. import {getFeatureTooltip, getFileType} from './utils';
  18. type Props = {
  19. debugFile: DebugFile;
  20. showDetails: boolean;
  21. downloadUrl: string;
  22. downloadRole: string;
  23. onDelete: (id: string) => void;
  24. };
  25. const DebugFileRow = ({
  26. debugFile,
  27. showDetails,
  28. downloadUrl,
  29. downloadRole,
  30. onDelete,
  31. }: Props) => {
  32. const {
  33. id,
  34. data,
  35. debugId,
  36. uuid,
  37. size,
  38. dateCreated,
  39. objectName,
  40. cpuName,
  41. symbolType,
  42. codeId,
  43. } = debugFile;
  44. const fileType = getFileType(debugFile);
  45. const {features} = data || {};
  46. return (
  47. <Fragment>
  48. <Column>
  49. <div>
  50. <DebugId>{debugId || uuid}</DebugId>
  51. </div>
  52. <TimeAndSizeWrapper>
  53. <StyledFileSize bytes={size} />
  54. <TimeWrapper>
  55. <IconClock size="xs" />
  56. <TimeSince date={dateCreated} />
  57. </TimeWrapper>
  58. </TimeAndSizeWrapper>
  59. </Column>
  60. <Column>
  61. <Name>
  62. {symbolType === 'proguard' && objectName === 'proguard-mapping'
  63. ? '\u2015'
  64. : objectName}
  65. </Name>
  66. <Description>
  67. <DescriptionText>
  68. {symbolType === 'proguard' && cpuName === 'any'
  69. ? t('proguard mapping')
  70. : `${cpuName} (${symbolType}${fileType ? ` ${fileType}` : ''})`}
  71. </DescriptionText>
  72. {features && (
  73. <FeatureTags>
  74. {features.map(feature => (
  75. <StyledTag key={feature} tooltipText={getFeatureTooltip(feature)}>
  76. {feature}
  77. </StyledTag>
  78. ))}
  79. </FeatureTags>
  80. )}
  81. {showDetails && (
  82. <div>
  83. {/* there will be more stuff here in the future */}
  84. {codeId && (
  85. <DetailsItem>
  86. {t('Code ID')}: {codeId}
  87. </DetailsItem>
  88. )}
  89. </div>
  90. )}
  91. </Description>
  92. </Column>
  93. <RightColumn>
  94. <ButtonBar gap={0.5}>
  95. <Role role={downloadRole}>
  96. {({hasRole}) => (
  97. <Tooltip
  98. disabled={hasRole}
  99. title={t('You do not have permission to download debug files.')}
  100. >
  101. <Button
  102. size="xsmall"
  103. icon={<IconDownload size="xs" />}
  104. href={downloadUrl}
  105. disabled={!hasRole}
  106. >
  107. {t('Download')}
  108. </Button>
  109. </Tooltip>
  110. )}
  111. </Role>
  112. <Access access={['project:write']}>
  113. {({hasAccess}) => (
  114. <Tooltip
  115. disabled={hasAccess}
  116. title={t('You do not have permission to delete debug files.')}
  117. >
  118. <Confirm
  119. confirmText={t('Delete')}
  120. message={t('Are you sure you wish to delete this file?')}
  121. onConfirm={() => onDelete(id)}
  122. disabled={!hasAccess}
  123. >
  124. <Button
  125. priority="danger"
  126. icon={<IconDelete size="xs" />}
  127. size="xsmall"
  128. disabled={!hasAccess}
  129. data-test-id="delete-dif"
  130. />
  131. </Confirm>
  132. </Tooltip>
  133. )}
  134. </Access>
  135. </ButtonBar>
  136. </RightColumn>
  137. </Fragment>
  138. );
  139. };
  140. const DescriptionText = styled('span')`
  141. display: inline-flex;
  142. margin: 0 ${space(1)} ${space(1)} 0;
  143. `;
  144. const FeatureTags = styled('div')`
  145. display: inline-flex;
  146. flex-wrap: wrap;
  147. margin: -${space(0.5)};
  148. `;
  149. const StyledTag = styled(Tag)`
  150. padding: ${space(0.5)};
  151. `;
  152. const Column = styled('div')`
  153. display: flex;
  154. flex-direction: column;
  155. align-items: flex-start;
  156. `;
  157. const RightColumn = styled('div')`
  158. display: flex;
  159. justify-content: flex-end;
  160. align-items: flex-start;
  161. margin-top: ${space(1)};
  162. `;
  163. const DebugId = styled('code')`
  164. font-size: ${p => p.theme.fontSizeSmall};
  165. `;
  166. const TimeAndSizeWrapper = styled('div')`
  167. width: 100%;
  168. display: flex;
  169. font-size: ${p => p.theme.fontSizeSmall};
  170. margin-top: ${space(1)};
  171. color: ${p => p.theme.subText};
  172. align-items: center;
  173. `;
  174. const StyledFileSize = styled(FileSize)`
  175. flex: 1;
  176. padding-left: ${space(0.5)};
  177. `;
  178. const TimeWrapper = styled('div')`
  179. display: grid;
  180. grid-gap: ${space(0.5)};
  181. grid-template-columns: min-content 1fr;
  182. flex: 2;
  183. align-items: center;
  184. padding-left: ${space(0.5)};
  185. `;
  186. const Name = styled('div')`
  187. font-size: ${p => p.theme.fontSizeMedium};
  188. margin-bottom: ${space(1)};
  189. `;
  190. const Description = styled('div')`
  191. font-size: ${p => p.theme.fontSizeSmall};
  192. color: ${p => p.theme.subText};
  193. @media (max-width: ${p => p.theme.breakpoints[2]}) {
  194. line-height: 1.7;
  195. }
  196. `;
  197. const DetailsItem = styled('div')`
  198. ${overflowEllipsis}
  199. margin-top: ${space(1)}
  200. `;
  201. export default DebugFileRow;