Browse Source

feat(toolbar): add project settings page w/allowed_origins form (#77675)

Depends on https://github.com/getsentry/sentry/pull/77674, closes
https://github.com/getsentry/sentry/issues/77213

Notice the route on top + in the sidebar. Users need to manually click
"Save Changes", which is only enabled if there were changes since the
last save.
![Screenshot 2024-09-17 at 5 19
40 PM](https://github.com/user-attachments/assets/043667cc-33d5-463f-8c50-38bca6842264)

TODO: format and validate before submission. Can use regex or whatever
we use for similar forms, [inbound
filters](https://sentry.sentry.io/settings/projects/javascript/filters/data-filters/#filters-react-hydration-errors_help)
is one
Questions:
- yes or no to trailing `/`'s?
- require protocol or fill in one by default? E.g. `https://`

https://github.com/getsentry/sentry/pull/77674 sets `["*"]` (allow all)
as the default. Whatever it is, we should probably show a default value
in the form to be consistent.
Andrew Liu 5 months ago
parent
commit
c1ebcc18b4

+ 5 - 0
static/app/routes.tsx

@@ -557,6 +557,11 @@ function buildRoutes() {
         name={t('Replays')}
         component={make(() => import('sentry/views/settings/project/projectReplays'))}
       />
+      <Route
+        path="toolbar/"
+        name={t('Developer Toolbar')}
+        component={make(() => import('sentry/views/settings/project/toolbar'))}
+      />
       <Route path="source-maps/" name={t('Source Maps')}>
         <IndexRoute
           component={make(() => import('sentry/views/settings/projectSourceMaps'))}

+ 5 - 0
static/app/views/settings/project/navigationConfiguration.tsx

@@ -64,6 +64,11 @@ export default function getConfiguration({
           title: t('User Feedback'),
           show: () => !isSelfHostedErrorsOnly,
         },
+        {
+          path: `${pathPrefix}/toolbar/`,
+          title: t('Developer Toolbar'),
+          show: () => !!organization?.features?.includes('dev-toolbar-ui'),
+        },
       ],
     },
     {

+ 68 - 0
static/app/views/settings/project/toolbar.tsx

@@ -0,0 +1,68 @@
+import Access from 'sentry/components/acl/access';
+import Form from 'sentry/components/forms/form';
+import JsonForm from 'sentry/components/forms/jsonForm';
+import type {JsonFormObject} from 'sentry/components/forms/types';
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
+import {t} from 'sentry/locale';
+import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
+import type {Organization} from 'sentry/types/organization';
+import type {Project} from 'sentry/types/project';
+import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
+import PermissionAlert from 'sentry/views/settings/project/permissionAlert';
+
+type RouteParams = {
+  projectId: string;
+};
+type Props = RouteComponentProps<RouteParams, {}> & {
+  organization: Organization;
+  project: Project;
+};
+
+function ProjectToolbarSettings({organization, project, params: {projectId}}: Props) {
+  const formGroups: JsonFormObject[] = [
+    {
+      title: 'Settings',
+      fields: [
+        {
+          name: 'sentry:toolbar_allowed_origins',
+          type: 'textarea',
+          rows: 3,
+          autosize: true,
+
+          // additional data/props that is related to rendering of form field rather than data
+          label: t('Allowed Origins'),
+          help: t(
+            'Domain URLs where the dev toolbar can be installed and access your data. Wildcards (*) are supported. Please separate multiple entries with a newline.'
+          ),
+          getData: data => ({options: data}),
+        },
+      ],
+    },
+  ];
+
+  return (
+    <SentryDocumentTitle title={t('Toolbar Settings')} projectSlug={project.slug}>
+      <SettingsPageHeader title={t('Developer Toolbar')} />
+      <PermissionAlert project={project} />
+
+      <Form
+        apiMethod="PUT"
+        apiEndpoint={`/projects/${organization.slug}/${projectId}/`}
+        initialData={project.options}
+        requireChanges
+      >
+        <Access access={['project:write']} project={project}>
+          {({hasAccess}) => (
+            <JsonForm
+              disabled={!hasAccess}
+              features={new Set(organization.features)}
+              forms={formGroups}
+            />
+          )}
+        </Access>
+      </Form>
+    </SentryDocumentTitle>
+  );
+}
+
+export default ProjectToolbarSettings;