keySettings.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import {Component, Fragment} from 'react';
  2. import {
  3. addErrorMessage,
  4. addLoadingMessage,
  5. addSuccessMessage,
  6. } from 'sentry/actionCreators/indicator';
  7. import {Client} from 'sentry/api';
  8. import Access from 'sentry/components/acl/access';
  9. import {Button} from 'sentry/components/button';
  10. import Confirm from 'sentry/components/confirm';
  11. import DateTime from 'sentry/components/dateTime';
  12. import FieldGroup from 'sentry/components/forms/fieldGroup';
  13. import BooleanField from 'sentry/components/forms/fields/booleanField';
  14. import SelectField from 'sentry/components/forms/fields/selectField';
  15. import TextField from 'sentry/components/forms/fields/textField';
  16. import Form from 'sentry/components/forms/form';
  17. import ExternalLink from 'sentry/components/links/externalLink';
  18. import {Panel, PanelAlert, PanelBody, PanelHeader} from 'sentry/components/panels';
  19. import TextCopyInput from 'sentry/components/textCopyInput';
  20. import {t, tct} from 'sentry/locale';
  21. import {Organization} from 'sentry/types';
  22. import getDynamicText from 'sentry/utils/getDynamicText';
  23. import KeyRateLimitsForm from 'sentry/views/settings/project/projectKeys/details/keyRateLimitsForm';
  24. import ProjectKeyCredentials from 'sentry/views/settings/project/projectKeys/projectKeyCredentials';
  25. import {ProjectKey} from 'sentry/views/settings/project/projectKeys/types';
  26. type Props = {
  27. api: Client;
  28. data: ProjectKey;
  29. onRemove: () => void;
  30. organization: Organization;
  31. params: {
  32. keyId: string;
  33. projectId: string;
  34. };
  35. };
  36. type State = {
  37. error: boolean;
  38. loading: boolean;
  39. };
  40. class KeySettings extends Component<Props, State> {
  41. state: State = {
  42. loading: false,
  43. error: false,
  44. };
  45. handleRemove = async () => {
  46. if (this.state.loading) {
  47. return;
  48. }
  49. addLoadingMessage(t('Revoking key\u2026'));
  50. const {api, organization, onRemove, params} = this.props;
  51. const {keyId, projectId} = params;
  52. try {
  53. await api.requestPromise(
  54. `/projects/${organization.slug}/${projectId}/keys/${keyId}/`,
  55. {
  56. method: 'DELETE',
  57. }
  58. );
  59. onRemove();
  60. addSuccessMessage(t('Revoked key'));
  61. } catch (_err) {
  62. this.setState({
  63. error: true,
  64. loading: false,
  65. });
  66. addErrorMessage(t('Unable to revoke key'));
  67. }
  68. };
  69. render() {
  70. const {keyId, projectId} = this.props.params;
  71. const {data, organization} = this.props;
  72. const apiEndpoint = `/projects/${organization.slug}/${projectId}/keys/${keyId}/`;
  73. const loaderLink = getDynamicText({
  74. value: data.dsn.cdn,
  75. fixed: '__JS_SDK_LOADER_URL__',
  76. });
  77. return (
  78. <Access access={['project:write']}>
  79. {({hasAccess}) => (
  80. <Fragment>
  81. <Form
  82. saveOnBlur
  83. allowUndo
  84. apiEndpoint={apiEndpoint}
  85. apiMethod="PUT"
  86. initialData={data}
  87. >
  88. <Panel>
  89. <PanelHeader>{t('Details')}</PanelHeader>
  90. <PanelBody>
  91. <TextField
  92. name="name"
  93. label={t('Name')}
  94. disabled={!hasAccess}
  95. required={false}
  96. maxLength={64}
  97. />
  98. <BooleanField
  99. name="isActive"
  100. label={t('Enabled')}
  101. required={false}
  102. disabled={!hasAccess}
  103. help="Accept events from this key? This may be used to temporarily suspend a key."
  104. />
  105. <FieldGroup label={t('Created')}>
  106. <div className="controls">
  107. <DateTime date={data.dateCreated} />
  108. </div>
  109. </FieldGroup>
  110. </PanelBody>
  111. </Panel>
  112. </Form>
  113. <KeyRateLimitsForm
  114. organization={organization}
  115. params={this.props.params}
  116. data={data}
  117. disabled={!hasAccess}
  118. />
  119. <Form saveOnBlur apiEndpoint={apiEndpoint} apiMethod="PUT" initialData={data}>
  120. <Panel>
  121. <PanelHeader>{t('JavaScript Loader')}</PanelHeader>
  122. <PanelBody>
  123. <FieldGroup
  124. help={tct(
  125. 'Copy this script into your website to setup your JavaScript SDK without any additional configuration. [link]',
  126. {
  127. link: (
  128. <ExternalLink href="https://docs.sentry.io/platforms/javascript/install/lazy-load-sentry/">
  129. What does the script provide?
  130. </ExternalLink>
  131. ),
  132. }
  133. )}
  134. inline={false}
  135. flexibleControlStateSize
  136. >
  137. <TextCopyInput>
  138. {`<script src='${loaderLink}' crossorigin="anonymous"></script>`}
  139. </TextCopyInput>
  140. </FieldGroup>
  141. <SelectField
  142. name="browserSdkVersion"
  143. options={
  144. data.browserSdk
  145. ? data.browserSdk.choices.map(([value, label]) => ({
  146. value,
  147. label,
  148. }))
  149. : []
  150. }
  151. placeholder={t('4.x')}
  152. allowClear={false}
  153. disabled={!hasAccess}
  154. help={t(
  155. 'Select the version of the SDK that should be loaded. Note that it can take a few minutes until this change is live.'
  156. )}
  157. />
  158. </PanelBody>
  159. </Panel>
  160. </Form>
  161. <Panel>
  162. <PanelHeader>{t('Credentials')}</PanelHeader>
  163. <PanelBody>
  164. <PanelAlert type="info" showIcon>
  165. {t(
  166. 'Your credentials are coupled to a public and secret key. Different clients will require different credentials, so make sure you check the documentation before plugging things in.'
  167. )}
  168. </PanelAlert>
  169. <ProjectKeyCredentials
  170. projectId={`${data.projectId}`}
  171. data={data}
  172. showPublicKey
  173. showSecretKey
  174. showProjectId
  175. />
  176. </PanelBody>
  177. </Panel>
  178. <Access access={['project:admin']}>
  179. <Panel>
  180. <PanelHeader>{t('Revoke Key')}</PanelHeader>
  181. <PanelBody>
  182. <FieldGroup
  183. label={t('Revoke Key')}
  184. help={t(
  185. 'Revoking this key will immediately remove and suspend the credentials. This action is irreversible.'
  186. )}
  187. >
  188. <div>
  189. <Confirm
  190. priority="danger"
  191. message={t(
  192. 'Are you sure you want to revoke this key? This will immediately remove and suspend the credentials.'
  193. )}
  194. onConfirm={this.handleRemove}
  195. confirmText={t('Revoke Key')}
  196. >
  197. <Button priority="danger">{t('Revoke Key')}</Button>
  198. </Confirm>
  199. </div>
  200. </FieldGroup>
  201. </PanelBody>
  202. </Panel>
  203. </Access>
  204. </Fragment>
  205. )}
  206. </Access>
  207. );
  208. }
  209. }
  210. export default KeySettings;