keySettings.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import {Fragment, useCallback} from 'react';
  2. import {
  3. addErrorMessage,
  4. addLoadingMessage,
  5. addSuccessMessage,
  6. } from 'sentry/actionCreators/indicator';
  7. import Access from 'sentry/components/acl/access';
  8. import {Button} from 'sentry/components/button';
  9. import Confirm from 'sentry/components/confirm';
  10. import {DateTime} from 'sentry/components/dateTime';
  11. import FieldGroup from 'sentry/components/forms/fieldGroup';
  12. import BooleanField from 'sentry/components/forms/fields/booleanField';
  13. import TextField from 'sentry/components/forms/fields/textField';
  14. import Form from 'sentry/components/forms/form';
  15. import Panel from 'sentry/components/panels/panel';
  16. import PanelAlert from 'sentry/components/panels/panelAlert';
  17. import PanelBody from 'sentry/components/panels/panelBody';
  18. import PanelHeader from 'sentry/components/panels/panelHeader';
  19. import {t} from 'sentry/locale';
  20. import type {Organization} from 'sentry/types/organization';
  21. import type {Project, ProjectKey} from 'sentry/types/project';
  22. import useApi from 'sentry/utils/useApi';
  23. import KeyRateLimitsForm from 'sentry/views/settings/project/projectKeys/details/keyRateLimitsForm';
  24. import {LoaderSettings} from 'sentry/views/settings/project/projectKeys/details/loaderSettings';
  25. import ProjectKeyCredentials from 'sentry/views/settings/project/projectKeys/projectKeyCredentials';
  26. type Props = {
  27. data: ProjectKey;
  28. onRemove: () => void;
  29. organization: Organization;
  30. params: {
  31. keyId: string;
  32. projectId: string;
  33. };
  34. project: Project;
  35. updateData: (data: ProjectKey) => void;
  36. };
  37. export function KeySettings({
  38. onRemove,
  39. organization,
  40. project,
  41. params,
  42. data,
  43. updateData,
  44. }: Props) {
  45. const api = useApi();
  46. const {keyId, projectId} = params;
  47. const apiEndpoint = `/projects/${organization.slug}/${projectId}/keys/${keyId}/`;
  48. const handleRemove = useCallback(async () => {
  49. addLoadingMessage(t('Revoking key\u2026'));
  50. try {
  51. await api.requestPromise(
  52. `/projects/${organization.slug}/${projectId}/keys/${keyId}/`,
  53. {
  54. method: 'DELETE',
  55. }
  56. );
  57. onRemove();
  58. addSuccessMessage(t('Revoked key'));
  59. } catch (_err) {
  60. addErrorMessage(t('Unable to revoke key'));
  61. }
  62. }, [organization, api, onRemove, keyId, projectId]);
  63. return (
  64. <Fragment>
  65. <Access access={['project:write']} project={project}>
  66. {({hasAccess}) => (
  67. <Fragment>
  68. <Form
  69. saveOnBlur
  70. allowUndo
  71. apiEndpoint={apiEndpoint}
  72. apiMethod="PUT"
  73. initialData={data}
  74. >
  75. <Panel>
  76. <PanelHeader>{t('Details')}</PanelHeader>
  77. <PanelBody>
  78. <TextField
  79. name="name"
  80. label={t('Name')}
  81. disabled={!hasAccess}
  82. required={false}
  83. maxLength={64}
  84. />
  85. <BooleanField
  86. name="isActive"
  87. label={t('Enabled')}
  88. required={false}
  89. disabled={!hasAccess}
  90. help="Accept events from this key? This may be used to temporarily suspend a key."
  91. />
  92. <FieldGroup label={t('Created')}>
  93. <div className="controls">
  94. <DateTime date={data.dateCreated} />
  95. </div>
  96. </FieldGroup>
  97. </PanelBody>
  98. </Panel>
  99. </Form>
  100. <KeyRateLimitsForm
  101. organization={organization}
  102. params={params}
  103. data={data}
  104. disabled={!hasAccess}
  105. />
  106. <Panel>
  107. <PanelHeader>{t('JavaScript Loader Script')}</PanelHeader>
  108. <PanelBody>
  109. <PanelAlert type="info" showIcon>
  110. {t(
  111. 'Note that it can take a few minutes until changed options are live.'
  112. )}
  113. </PanelAlert>
  114. <LoaderSettings
  115. orgSlug={organization.slug}
  116. keyId={params.keyId}
  117. project={project}
  118. data={data}
  119. updateData={updateData}
  120. />
  121. </PanelBody>
  122. </Panel>
  123. <Panel>
  124. <PanelHeader>{t('Credentials')}</PanelHeader>
  125. <PanelBody>
  126. <PanelAlert type="info" showIcon>
  127. {t(
  128. '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.'
  129. )}
  130. </PanelAlert>
  131. <ProjectKeyCredentials
  132. projectId={`${data.projectId}`}
  133. data={data}
  134. showPublicKey
  135. showSecretKey
  136. showProjectId
  137. />
  138. </PanelBody>
  139. </Panel>
  140. </Fragment>
  141. )}
  142. </Access>
  143. <Access access={['project:admin']} project={project}>
  144. {({hasAccess}) => (
  145. <Panel>
  146. <PanelHeader>{t('Revoke Key')}</PanelHeader>
  147. <PanelBody>
  148. <FieldGroup
  149. label={t('Revoke Key')}
  150. help={t(
  151. 'Revoking this key will immediately remove and suspend the credentials. This action is irreversible.'
  152. )}
  153. >
  154. <div>
  155. <Confirm
  156. priority="danger"
  157. message={t(
  158. 'Are you sure you want to revoke this key? This will immediately remove and suspend the credentials.'
  159. )}
  160. onConfirm={handleRemove}
  161. confirmText={t('Revoke Key')}
  162. disabled={!hasAccess}
  163. >
  164. <Button priority="danger">{t('Revoke Key')}</Button>
  165. </Confirm>
  166. </div>
  167. </FieldGroup>
  168. </PanelBody>
  169. </Panel>
  170. )}
  171. </Access>
  172. </Fragment>
  173. );
  174. }