Browse Source

fix(toolbar): fix allowed origins form saving (#78718)

Closes https://github.com/getsentry/sentry/issues/78689

Also adds a jest test and renames file/class to match other project
settings (`project` prefix)
Andrew Liu 5 months ago
parent
commit
df00153373

+ 1 - 1
static/app/routes.tsx

@@ -559,7 +559,7 @@ function buildRoutes() {
       <Route
         path="toolbar/"
         name={t('Developer Toolbar')}
-        component={make(() => import('sentry/views/settings/project/toolbar'))}
+        component={make(() => import('sentry/views/settings/project/projectToolbar'))}
       />
       <Route path="source-maps/" name={t('Source Maps')}>
         <IndexRoute

+ 4 - 0
static/app/views/settings/project/projectReplays.tsx

@@ -7,6 +7,7 @@ import Link from 'sentry/components/links/link';
 import ReplaySettingsAlert from 'sentry/components/replays/alerts/replaySettingsAlert';
 import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
 import {t, tct} from 'sentry/locale';
+import ProjectsStore from 'sentry/stores/projectsStore';
 import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
 import type {Organization} from 'sentry/types/organization';
 import type {Project} from 'sentry/types/project';
@@ -80,6 +81,9 @@ function ProjectReplaySettings({organization, project, params: {projectId}}: Pro
         apiMethod="PUT"
         apiEndpoint={`/projects/${organization.slug}/${projectId}/`}
         initialData={project.options}
+        onSubmitSuccess={(
+          response // This will update our project context
+        ) => ProjectsStore.onUpdateSuccess(response)}
       >
         <Access access={['project:write']} project={project}>
           {({hasAccess}) => (

+ 95 - 0
static/app/views/settings/project/projectToolbar.spec.tsx

@@ -0,0 +1,95 @@
+import {initializeOrg} from 'sentry-test/initializeOrg';
+import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
+
+import ProjectToolbarSettings from 'sentry/views/settings/project/projectToolbar';
+
+describe('ProjectToolbarSettings', function () {
+  const {routerProps, organization, project, router} = initializeOrg();
+  const url = `/projects/${organization.slug}/${project.slug}/`;
+
+  beforeEach(function () {
+    MockApiClient.clearMockResponses();
+  });
+
+  it('displays previously saved setting', function () {
+    const initialOptionValue = 'sentry.io';
+    project.options = {'sentry:toolbar_allowed_origins': initialOptionValue};
+    render(
+      <ProjectToolbarSettings
+        {...routerProps}
+        organization={organization}
+        project={project}
+      />,
+      {
+        router,
+      }
+    );
+    expect(screen.getByRole('textbox')).toHaveValue(initialOptionValue);
+  });
+
+  it('can submit new allowed origins', async function () {
+    render(
+      <ProjectToolbarSettings
+        {...routerProps}
+        organization={organization}
+        project={project}
+      />,
+      {
+        router,
+      }
+    );
+
+    const mockPut = MockApiClient.addMockResponse({
+      url,
+      method: 'PUT',
+    });
+
+    const textarea = screen.getByRole('textbox');
+    expect(textarea).toBeEnabled();
+
+    const mockInput = 'test.io\n*.example.com';
+    await userEvent.clear(textarea);
+    await userEvent.type(textarea, mockInput);
+    await userEvent.tab(); // unfocus ("blur") the input
+
+    expect(mockPut).toHaveBeenCalledWith(
+      url,
+      expect.objectContaining({
+        method: 'PUT',
+        data: {
+          options: {'sentry:toolbar_allowed_origins': mockInput},
+        },
+      })
+    );
+  });
+
+  it('displays nothing when project options are undefined', function () {
+    project.options = undefined;
+    render(
+      <ProjectToolbarSettings
+        {...routerProps}
+        organization={organization}
+        project={project}
+      />,
+      {
+        router,
+      }
+    );
+    expect(screen.getByRole('textbox')).toHaveValue('');
+  });
+
+  it('displays nothing when project options are empty', function () {
+    project.options = {};
+    render(
+      <ProjectToolbarSettings
+        {...routerProps}
+        organization={organization}
+        project={project}
+      />,
+      {
+        router,
+      }
+    );
+    expect(screen.getByRole('textbox')).toHaveValue('');
+  });
+});

+ 1 - 1
static/app/views/settings/project/toolbar.tsx → static/app/views/settings/project/projectToolbar.tsx

@@ -49,7 +49,7 @@ function ProjectToolbarSettings({organization, project, params: {projectId}}: Pr
         apiMethod="PUT"
         apiEndpoint={`/projects/${organization.slug}/${projectId}/`}
         initialData={project.options}
-        requireChanges
+        saveOnBlur
       >
         <Access access={['project:write']} project={project}>
           {({hasAccess}) => (