projectToolbar.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import styled from '@emotion/styled';
  2. import Access from 'sentry/components/acl/access';
  3. import Feature from 'sentry/components/acl/feature';
  4. import Alert from 'sentry/components/alert';
  5. import {LinkButton} from 'sentry/components/button';
  6. import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
  7. import Form from 'sentry/components/forms/form';
  8. import JsonForm from 'sentry/components/forms/jsonForm';
  9. import type {JsonFormObject} from 'sentry/components/forms/types';
  10. import {NoAccess} from 'sentry/components/noAccess';
  11. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  12. import {t, tct} from 'sentry/locale';
  13. import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
  14. import type {Organization} from 'sentry/types/organization';
  15. import type {Project} from 'sentry/types/project';
  16. import {decodeScalar} from 'sentry/utils/queryString';
  17. import {useLocation} from 'sentry/utils/useLocation';
  18. import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
  19. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  20. import PermissionAlert from 'sentry/views/settings/project/permissionAlert';
  21. type RouteParams = {
  22. projectId: string;
  23. };
  24. type Props = RouteComponentProps<RouteParams, {}> & {
  25. organization: Organization;
  26. project: Project;
  27. };
  28. export default function ProjectToolbarSettings({
  29. organization,
  30. project,
  31. params: {projectId},
  32. }: Props) {
  33. const location = useLocation();
  34. const domain = decodeScalar(location.query.domain);
  35. const formGroups: JsonFormObject[] = [
  36. {
  37. title: 'Settings',
  38. fields: [
  39. {
  40. name: 'sentry:toolbar_allowed_origins',
  41. type: 'textarea',
  42. rows: 3,
  43. autosize: true,
  44. formatMessageValue: false,
  45. // additional data/props that is related to rendering of form field rather than data
  46. label: t('Allowed Origins'),
  47. help: (
  48. <div>
  49. <Important>
  50. {t('Only add trusted domains, that you control, to this list.')}
  51. </Important>
  52. <br />
  53. {t('Domains where the dev toolbar is allowed to access your data.')}
  54. <br />
  55. {t(
  56. 'Protocol and port are optional; wildcard subdomains (*) are are supported.'
  57. )}
  58. <br />
  59. {tct(
  60. 'Example: [code:localhost] is equivalent to [code:http://localhost] or [code:localhost:80]',
  61. {code: <code />}
  62. )}
  63. </div>
  64. ),
  65. getData: data => ({options: data}),
  66. },
  67. ],
  68. },
  69. ];
  70. return (
  71. <SentryDocumentTitle title={t('Toolbar Settings')} projectSlug={project.slug}>
  72. <SettingsPageHeader
  73. title={t('Dev Toolbar')}
  74. action={
  75. <LinkButton href="https://docs.sentry.io/product/dev-toolbar/" external>
  76. {t('Read the Docs')}
  77. </LinkButton>
  78. }
  79. />
  80. <Feature
  81. features="dev-toolbar-ui"
  82. organization={organization}
  83. renderDisabled={NoAccess}
  84. >
  85. <TextBlock>
  86. {t(
  87. `Bring critical Sentry insights and tools directly into your web app for easier troubleshooting with the Dev Toolbar.`
  88. )}
  89. </TextBlock>
  90. <PermissionAlert project={project} />
  91. {domain && (
  92. <Alert type="info" showIcon>
  93. {tct(
  94. 'To enable the Dev Toolbar, copy and paste your domain into the Allowed Origins text box below: [domain] ',
  95. {domain: <strong>{domain}</strong>}
  96. )}
  97. <CopyToClipboardButton borderless iconSize="xs" size="zero" text={domain} />
  98. </Alert>
  99. )}
  100. <Form
  101. apiMethod="PUT"
  102. apiEndpoint={`/projects/${organization.slug}/${projectId}/`}
  103. initialData={project.options}
  104. saveOnBlur
  105. >
  106. <Access access={['project:write']} project={project}>
  107. {({hasAccess}) => (
  108. <JsonForm
  109. disabled={!hasAccess}
  110. features={new Set(organization.features)}
  111. forms={formGroups}
  112. />
  113. )}
  114. </Access>
  115. </Form>
  116. </Feature>
  117. </SentryDocumentTitle>
  118. );
  119. }
  120. const Important = styled('strong')`
  121. color: ${p => p.theme.red400};
  122. `;