Skip to content

Commit a162c3d

Browse files
authored
chore(seer): Setup new, blank, page for Seer settings to live (#103990)
This is all behind a feature flag called "seer-settings-gtm". I tested things by enabling the flag with the toolbar and I can see that urls like /settings/seer/ and /settings/seer/projects/ and /settings/seer/repositories/ show the basic html that is defined. When I toggle the flag off (again, via the toolbar) I can see the "You dont have access to this feature " message as expected. By setting up the flag and the blank pages like this it should be easier to do work in parallel against all three pages, and the original settings page is not affected. This change has frontend and backend changes because it's adding a new flag. The default for the flag is 'off' so these changes are safe to be merged together, and be deployed at any time in any order. Look at these screenshots to see the testing in action: | | Flag Disabled | Flag Enabled | | --- | --- | --- | | Main Page | <img width="936" height="340" alt="SCR-20251125-jmdx" src="https://github.com/user-attachments/assets/de1602d6-8157-4870-a87b-f119622803e2" /> | <img width="960" height="351" alt="SCR-20251125-jmbn" src="https://github.com/user-attachments/assets/6b1eed13-a1fd-4e9c-997d-5a2e75c231b9" /> | Projects Page | <img width="970" height="352" alt="SCR-20251125-jlxo" src="https://github.com/user-attachments/assets/1d657814-3f1c-4671-899b-0d15484d86ec" /> | <img width="987" height="350" alt="SCR-20251125-jlzr" src="https://github.com/user-attachments/assets/42da955b-f644-4830-a18f-33b880ff137e" />
1 parent 6ab39b7 commit a162c3d

File tree

10 files changed

+134
-55
lines changed

10 files changed

+134
-55
lines changed

src/sentry/features/temporary.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ def register_temporary_features(manager: FeatureManager) -> None:
380380
manager.add("organizations:seer-coding-agent-integrations", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
381381
# Enable Seer Explorer panel for AI-powered data exploration
382382
manager.add("organizations:seer-explorer", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
383+
# Enable Seer GTM Settings page designs
384+
manager.add("organizations:seer-settings-gtm", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
383385
# Enable search query builder boolean operator select feature
384386
manager.add("organizations:search-query-builder-add-boolean-operator-select", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
385387
# Enable search query builder case insensitivity features

static/app/router/routes.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,10 +1214,21 @@ function buildRoutes(): RouteObject[] {
12141214
{
12151215
path: 'seer/',
12161216
name: t('Seer Automation'),
1217+
component: make(() => import('getsentry/views/seerAutomation/index')),
12171218
children: [
12181219
{
12191220
index: true,
1220-
component: make(() => import('getsentry/views/seerAutomation')),
1221+
component: make(() => import('getsentry/views/seerAutomation/seerAutomation')),
1222+
},
1223+
{
1224+
path: 'projects/',
1225+
name: t('Seer'),
1226+
component: make(() => import('getsentry/views/seerAutomation/projects')),
1227+
},
1228+
{
1229+
path: 'repositories/',
1230+
name: t('Seer'),
1231+
component: make(() => import('getsentry/views/seerAutomation/repositories')),
12211232
},
12221233
{
12231234
path: 'onboarding/',

static/gsApp/views/seerAutomation/index.spec.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingL
55

66
import ProjectsStore from 'sentry/stores/projectsStore';
77

8-
import SeerAutomationRoot from './index';
8+
import SeerAutomation from 'getsentry/views/seerAutomation/seerAutomation';
99

1010
describe('SeerAutomation', () => {
1111
beforeEach(() => {
@@ -61,7 +61,7 @@ describe('SeerAutomation', () => {
6161
},
6262
});
6363

64-
render(<SeerAutomationRoot />, {organization});
64+
render(<SeerAutomation />, {organization});
6565

6666
// Project details populate the project list
6767
const projectItem = await screen.findByText(project.slug);
@@ -124,7 +124,7 @@ describe('SeerAutomation', () => {
124124
},
125125
});
126126

127-
render(<SeerAutomationRoot />, {organization});
127+
render(<SeerAutomation />, {organization});
128128

129129
// Find the toggle for Default for Issue Scans
130130
const toggle = await screen.findByRole('checkbox', {
Lines changed: 8 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
import {Fragment} from 'react';
2+
import {Outlet} from 'react-router-dom';
3+
4+
import {Stack} from '@sentry/scraps/layout/stack';
25

3-
import {LinkButton} from 'sentry/components/core/button/linkButton';
46
import {useOrganizationSeerSetup} from 'sentry/components/events/autofix/useOrganizationSeerSetup';
5-
import ExternalLink from 'sentry/components/links/externalLink';
67
import {NoAccess} from 'sentry/components/noAccess';
7-
import NoProjectMessage from 'sentry/components/noProjectMessage';
88
import Placeholder from 'sentry/components/placeholder';
99
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
10-
import {t, tct} from 'sentry/locale';
11-
import {DataCategoryExact} from 'sentry/types/core';
10+
import {t} from 'sentry/locale';
1211
import useOrganization from 'sentry/utils/useOrganization';
13-
import {getPricingDocsLinkForEventType} from 'sentry/views/settings/account/notifications/utils';
14-
import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
1512

1613
import AiSetupDataConsent from 'getsentry/components/ai/AiSetupDataConsent';
1714

18-
import {SeerAutomationDefault} from './seerAutomationDefault';
19-
import {SeerAutomationProjectList} from './seerAutomationProjectList';
20-
21-
function SeerAutomationRoot() {
15+
export default function SeerAutomationRoot() {
2216
const organization = useOrganization();
2317
const {isLoading, billing, setupAcknowledgement} = useOrganizationSeerSetup();
2418

@@ -29,14 +23,12 @@ function SeerAutomationRoot() {
2923
// Show loading placeholders while checking setup
3024
if (isLoading) {
3125
return (
32-
<Fragment>
26+
<Stack gap="lg">
3327
<SentryDocumentTitle title={t('Seer Automation')} orgSlug={organization.slug} />
3428
<Placeholder height="60px" />
35-
<br />
3629
<Placeholder height="200px" />
37-
<br />
3830
<Placeholder height="200px" />
39-
</Fragment>
31+
</Stack>
4032
);
4133
}
4234

@@ -57,40 +49,5 @@ function SeerAutomationRoot() {
5749
);
5850
}
5951

60-
// Show the regular settings page
61-
return (
62-
<Fragment>
63-
<SentryDocumentTitle title={t('Seer Automation')} orgSlug={organization.slug} />
64-
<SettingsPageHeader
65-
title={t('Seer Automation')}
66-
subtitle={tct(
67-
"Choose how Seer automatically triages and diagnoses incoming issues, before you even notice them. This analysis is billed at the [link:standard rates] for Seer's Issue Scan and Issue Fix. See [spendlink:docs] on how to manage your Seer spend.",
68-
{
69-
link: <ExternalLink href="https://docs.sentry.io/pricing/#seer-pricing" />,
70-
spendlink: (
71-
<ExternalLink
72-
href={getPricingDocsLinkForEventType(DataCategoryExact.SEER_AUTOFIX)}
73-
/>
74-
),
75-
}
76-
)}
77-
action={
78-
<LinkButton
79-
href="https://docs.sentry.io/product/ai-in-sentry/seer/#seer-capabilities"
80-
external
81-
>
82-
{t('Read the docs')}
83-
</LinkButton>
84-
}
85-
/>
86-
87-
<NoProjectMessage organization={organization}>
88-
<SeerAutomationProjectList />
89-
<br />
90-
<SeerAutomationDefault />
91-
</NoProjectMessage>
92-
</Fragment>
93-
);
52+
return <Outlet />;
9453
}
95-
96-
export default SeerAutomationRoot;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Feature from 'sentry/components/acl/feature';
2+
import {NoAccess} from 'sentry/components/noAccess';
3+
import useOrganization from 'sentry/utils/useOrganization';
4+
5+
export default function SeerAutomationProjects() {
6+
const organization = useOrganization();
7+
8+
return (
9+
<Feature
10+
features={['seer-settings-gtm']}
11+
organization={organization}
12+
renderDisabled={NoAccess}
13+
>
14+
<div>SeerAutomationProjects</div>
15+
</Feature>
16+
);
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Feature from 'sentry/components/acl/feature';
2+
import {NoAccess} from 'sentry/components/noAccess';
3+
import useOrganization from 'sentry/utils/useOrganization';
4+
5+
export default function SeerAutomationRepositories() {
6+
const organization = useOrganization();
7+
8+
return (
9+
<Feature
10+
features={['seer-settings-gtm']}
11+
organization={organization}
12+
renderDisabled={NoAccess}
13+
>
14+
<div>SeerAutomationRepositories</div>
15+
</Feature>
16+
);
17+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {Fragment} from 'react';
2+
3+
import {LinkButton} from 'sentry/components/core/button/linkButton';
4+
import ExternalLink from 'sentry/components/links/externalLink';
5+
import NoProjectMessage from 'sentry/components/noProjectMessage';
6+
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
7+
import {t, tct} from 'sentry/locale';
8+
import {DataCategoryExact} from 'sentry/types/core';
9+
import useOrganization from 'sentry/utils/useOrganization';
10+
import {getPricingDocsLinkForEventType} from 'sentry/views/settings/account/notifications/utils';
11+
import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
12+
13+
import {SeerAutomationDefault} from 'getsentry/views/seerAutomation/components/seerAutomationDefault';
14+
import {SeerAutomationProjectList} from 'getsentry/views/seerAutomation/components/seerAutomationProjectList';
15+
import Settings from 'getsentry/views/seerAutomation/settings';
16+
17+
export default function SeerAutomation() {
18+
const organization = useOrganization();
19+
20+
if (organization.features.includes('seer-settings-gtm')) {
21+
return <Settings />;
22+
}
23+
24+
// Show the regular settings page
25+
return (
26+
<Fragment>
27+
<SentryDocumentTitle title={t('Seer Automation')} orgSlug={organization.slug} />
28+
<SettingsPageHeader
29+
title={t('Seer Automation')}
30+
subtitle={tct(
31+
"Choose how Seer automatically triages and diagnoses incoming issues, before you even notice them. This analysis is billed at the [link:standard rates] for Seer's Issue Scan and Issue Fix. See [spendlink:docs] on how to manage your Seer spend.",
32+
{
33+
link: <ExternalLink href="https://docs.sentry.io/pricing/#seer-pricing" />,
34+
spendlink: (
35+
<ExternalLink
36+
href={getPricingDocsLinkForEventType(DataCategoryExact.SEER_AUTOFIX)}
37+
/>
38+
),
39+
}
40+
)}
41+
action={
42+
<LinkButton
43+
href="https://docs.sentry.io/product/ai-in-sentry/seer/#seer-capabilities"
44+
external
45+
>
46+
{t('Read the docs')}
47+
</LinkButton>
48+
}
49+
/>
50+
51+
<NoProjectMessage organization={organization}>
52+
<SeerAutomationProjectList />
53+
<br />
54+
<SeerAutomationDefault />
55+
</NoProjectMessage>
56+
</Fragment>
57+
);
58+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Feature from 'sentry/components/acl/feature';
2+
import {NoAccess} from 'sentry/components/noAccess';
3+
import useOrganization from 'sentry/utils/useOrganization';
4+
5+
export default function SeerAutomationSettings() {
6+
const organization = useOrganization();
7+
8+
return (
9+
<Feature
10+
features={['seer-settings-gtm']}
11+
organization={organization}
12+
renderDisabled={NoAccess}
13+
>
14+
<div>SeerAutomationSettings</div>
15+
</Feature>
16+
);
17+
}

0 commit comments

Comments
 (0)