apiTokenRow.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import styled from '@emotion/styled';
  2. import {Button} from 'sentry/components/button';
  3. import DateTime from 'sentry/components/dateTime';
  4. import PanelItem from 'sentry/components/panels/panelItem';
  5. import {IconSubtract} from 'sentry/icons';
  6. import {t} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import type {InternalAppApiToken} from 'sentry/types';
  9. import getDynamicText from 'sentry/utils/getDynamicText';
  10. import {tokenPreview} from 'sentry/views/settings/organizationAuthTokens';
  11. type Props = {
  12. onRemove: (token: InternalAppApiToken) => void;
  13. token: InternalAppApiToken;
  14. tokenPrefix?: string;
  15. };
  16. function ApiTokenRow({token, onRemove, tokenPrefix = ''}: Props) {
  17. return (
  18. <StyledPanelItem>
  19. <Controls>
  20. <TokenPreview aria-label={t('Token preview')}>
  21. {tokenPreview(
  22. getDynamicText({
  23. value: token.tokenLastCharacters,
  24. fixed: 'ABCD',
  25. }),
  26. tokenPrefix
  27. )}
  28. </TokenPreview>
  29. <ButtonWrapper>
  30. <Button
  31. data-test-id="token-delete"
  32. onClick={() => onRemove(token)}
  33. icon={<IconSubtract isCircled size="xs" />}
  34. >
  35. {t('Remove')}
  36. </Button>
  37. </ButtonWrapper>
  38. </Controls>
  39. <Details>
  40. <ScopesWrapper>
  41. <Heading>{t('Scopes')}</Heading>
  42. <ScopeList>{token.scopes.join(', ')}</ScopeList>
  43. </ScopesWrapper>
  44. <div>
  45. <Heading>{t('Created')}</Heading>
  46. <Time>
  47. <DateTime
  48. date={getDynamicText({
  49. value: token.dateCreated,
  50. fixed: new Date(1508208080000), // National Pasta Day
  51. })}
  52. />
  53. </Time>
  54. </div>
  55. </Details>
  56. </StyledPanelItem>
  57. );
  58. }
  59. const StyledPanelItem = styled(PanelItem)`
  60. flex-direction: column;
  61. padding: ${space(2)};
  62. `;
  63. const Controls = styled('div')`
  64. display: flex;
  65. align-items: center;
  66. margin-bottom: ${space(1)};
  67. `;
  68. const Details = styled('div')`
  69. display: flex;
  70. margin-top: ${space(1)};
  71. `;
  72. const ScopesWrapper = styled('div')`
  73. flex: 1;
  74. `;
  75. const ScopeList = styled('div')`
  76. font-size: ${p => p.theme.fontSizeRelativeSmall};
  77. line-height: 1.4;
  78. `;
  79. const Time = styled('time')`
  80. font-size: ${p => p.theme.fontSizeRelativeSmall};
  81. line-height: 1.4;
  82. `;
  83. const Heading = styled('div')`
  84. font-size: ${p => p.theme.fontSizeMedium};
  85. text-transform: uppercase;
  86. color: ${p => p.theme.subText};
  87. margin-bottom: ${space(1)};
  88. `;
  89. const TokenPreview = styled('div')`
  90. color: ${p => p.theme.gray300};
  91. `;
  92. const ButtonWrapper = styled('div')`
  93. margin-left: auto;
  94. display: flex;
  95. flex-direction: column;
  96. align-items: flex-end;
  97. justify-content: flex-end;
  98. font-size: ${p => p.theme.fontSizeSmall};
  99. gap: ${space(1)};
  100. `;
  101. export default ApiTokenRow;