apiTokens.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import {
  2. addErrorMessage,
  3. addLoadingMessage,
  4. addSuccessMessage,
  5. } from 'sentry/actionCreators/indicator';
  6. import AlertLink from 'sentry/components/alertLink';
  7. import {Button} from 'sentry/components/button';
  8. import EmptyMessage from 'sentry/components/emptyMessage';
  9. import ExternalLink from 'sentry/components/links/externalLink';
  10. import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels';
  11. import {t, tct} from 'sentry/locale';
  12. import {InternalAppApiToken, Organization} from 'sentry/types';
  13. import withOrganization from 'sentry/utils/withOrganization';
  14. import AsyncView from 'sentry/views/asyncView';
  15. import ApiTokenRow from 'sentry/views/settings/account/apiTokenRow';
  16. import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
  17. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  18. type Props = {
  19. organization: Organization;
  20. } & AsyncView['props'];
  21. type State = {
  22. tokenList: InternalAppApiToken[] | null;
  23. } & AsyncView['state'];
  24. export class ApiTokens extends AsyncView<Props, State> {
  25. getTitle() {
  26. return t('API Tokens');
  27. }
  28. getDefaultState() {
  29. return {
  30. ...super.getDefaultState(),
  31. tokenList: [],
  32. };
  33. }
  34. getEndpoints(): ReturnType<AsyncView['getEndpoints']> {
  35. return [['tokenList', '/api-tokens/']];
  36. }
  37. handleRemoveToken = (token: InternalAppApiToken) => {
  38. addLoadingMessage();
  39. const oldTokenList = this.state.tokenList;
  40. this.setState(
  41. state => ({
  42. tokenList: state.tokenList?.filter(tk => tk.token !== token.token) ?? [],
  43. }),
  44. async () => {
  45. try {
  46. await this.api.requestPromise('/api-tokens/', {
  47. method: 'DELETE',
  48. data: {token: token.token},
  49. });
  50. addSuccessMessage(t('Removed token'));
  51. } catch (_err) {
  52. addErrorMessage(t('Unable to remove token. Please try again.'));
  53. this.setState({
  54. tokenList: oldTokenList,
  55. });
  56. }
  57. }
  58. );
  59. };
  60. renderBody() {
  61. const {organization} = this.props;
  62. const {tokenList} = this.state;
  63. const isEmpty = !Array.isArray(tokenList) || tokenList.length === 0;
  64. const action = (
  65. <Button
  66. priority="primary"
  67. size="sm"
  68. to="/settings/account/api/auth-tokens/new-token/"
  69. data-test-id="create-token"
  70. >
  71. {t('Create New Token')}
  72. </Button>
  73. );
  74. return (
  75. <div>
  76. <SettingsPageHeader title="Auth Tokens" action={action} />
  77. <AlertLink
  78. to={`/settings/${organization?.slug ?? ''}/developer-settings/new-internal`}
  79. >
  80. {t(
  81. "Auth Tokens are tied to the logged in user, meaning they'll stop working if the user leaves the organization! We suggest using internal integrations to create/manage tokens tied to the organization instead."
  82. )}
  83. </AlertLink>
  84. <TextBlock>
  85. {t(
  86. "Authentication tokens allow you to perform actions against the Sentry API on behalf of your account. They're the easiest way to get started using the API."
  87. )}
  88. </TextBlock>
  89. <TextBlock>
  90. {tct(
  91. 'For more information on how to use the web API, see our [link:documentation].',
  92. {
  93. link: <ExternalLink href="https://docs.sentry.io/api/" />,
  94. }
  95. )}
  96. </TextBlock>
  97. <Panel>
  98. <PanelHeader>{t('Auth Token')}</PanelHeader>
  99. <PanelBody>
  100. {isEmpty && (
  101. <EmptyMessage>
  102. {t("You haven't created any authentication tokens yet.")}
  103. </EmptyMessage>
  104. )}
  105. {tokenList?.map(token => (
  106. <ApiTokenRow
  107. key={token.token}
  108. token={token}
  109. onRemove={this.handleRemoveToken}
  110. />
  111. ))}
  112. </PanelBody>
  113. </Panel>
  114. </div>
  115. );
  116. }
  117. }
  118. export default withOrganization(ApiTokens);