apiTokenRow.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 {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. };
  15. // TODO: After the BE portion of code changes have been released, remove the conditional rendering of the token.
  16. // We are currently doing the conditional logic to do safe blue/green deploys and handle contract changes.
  17. function ApiTokenRow({token, onRemove}: Props) {
  18. return (
  19. <StyledPanelItem>
  20. <Controls>
  21. <TokenPreview aria-label={t('Token preview')}>
  22. {tokenPreview(
  23. getDynamicText({
  24. value: token.tokenLastCharacters,
  25. fixed: 'ABCD',
  26. })
  27. )}
  28. </TokenPreview>
  29. <ButtonWrapper>
  30. <Button
  31. onClick={() => onRemove(token)}
  32. icon={<IconSubtract isCircled size="xs" />}
  33. >
  34. {t('Remove')}
  35. </Button>
  36. </ButtonWrapper>
  37. </Controls>
  38. <Details>
  39. <ScopesWrapper>
  40. <Heading>{t('Scopes')}</Heading>
  41. <ScopeList>{token.scopes.join(', ')}</ScopeList>
  42. </ScopesWrapper>
  43. <div>
  44. <Heading>{t('Created')}</Heading>
  45. <Time>
  46. <DateTime
  47. date={getDynamicText({
  48. value: token.dateCreated,
  49. fixed: new Date(1508208080000), // National Pasta Day
  50. })}
  51. />
  52. </Time>
  53. </div>
  54. </Details>
  55. </StyledPanelItem>
  56. );
  57. }
  58. const StyledPanelItem = styled(PanelItem)`
  59. flex-direction: column;
  60. padding: ${space(2)};
  61. `;
  62. const Controls = styled('div')`
  63. display: flex;
  64. align-items: center;
  65. margin-bottom: ${space(1)};
  66. `;
  67. const Details = styled('div')`
  68. display: flex;
  69. margin-top: ${space(1)};
  70. `;
  71. const ScopesWrapper = styled('div')`
  72. flex: 1;
  73. `;
  74. const ScopeList = styled('div')`
  75. font-size: ${p => p.theme.fontSizeRelativeSmall};
  76. line-height: 1.4;
  77. `;
  78. const Time = styled('time')`
  79. font-size: ${p => p.theme.fontSizeRelativeSmall};
  80. line-height: 1.4;
  81. `;
  82. const Heading = styled('div')`
  83. font-size: ${p => p.theme.fontSizeMedium};
  84. text-transform: uppercase;
  85. color: ${p => p.theme.subText};
  86. margin-bottom: ${space(1)};
  87. `;
  88. const TokenPreview = styled('div')`
  89. color: ${p => p.theme.gray300};
  90. `;
  91. const ButtonWrapper = styled('div')`
  92. margin-left: auto;
  93. display: flex;
  94. flex-direction: column;
  95. align-items: flex-end;
  96. justify-content: flex-end;
  97. font-size: ${p => p.theme.fontSizeSmall};
  98. gap: ${space(1)};
  99. `;
  100. export default ApiTokenRow;