1+ import { mutationOptions } from '@tanstack/react-query' ;
2+ import { z } from 'zod' ;
3+
14import { Alert } from '@sentry/scraps/alert' ;
2- import { Stack } from '@sentry/scraps/layout' ;
5+ import { AutoSaveForm , FieldGroup } from '@sentry/scraps/form' ;
6+ import { Container , Stack } from '@sentry/scraps/layout' ;
37
4- import { Form } from 'sentry/components/forms/form' ;
5- import JsonForm from 'sentry/components/forms/jsonForm' ;
6- import { type RepositorySettings } from 'sentry/components/repositories/useBulkUpdateRepositorySettings' ;
8+ import { getRepositoryWithSettingsQueryKey } from 'sentry/components/repositories/useRepositoryWithSettings' ;
79import { t , tct } from 'sentry/locale' ;
8- import { type RepositoryWithSettings } from 'sentry/types/integrations' ;
10+ import type { RepositoryWithSettings } from 'sentry/types/integrations' ;
911import type { Organization } from 'sentry/types/organization' ;
12+ import { getSeerOnboardingCheckQueryOptions } from 'sentry/utils/getSeerOnboardingCheckQueryOptions' ;
13+ import { fetchMutation , useQueryClient } from 'sentry/utils/queryClient' ;
1014
1115import { useCanWriteSettings } from 'getsentry/views/seerAutomation/components/useCanWriteSettings' ;
1216
17+ const schema = z . object ( {
18+ enabledCodeReview : z . boolean ( ) ,
19+ codeReviewTriggers : z . array ( z . string ( ) ) ,
20+ } ) ;
21+
1322interface Props {
1423 organization : Organization ;
1524 repoWithSettings : RepositoryWithSettings ;
1625}
1726
1827export function RepoDetailsForm ( { organization, repoWithSettings} : Props ) {
1928 const canWrite = useCanWriteSettings ( ) ;
29+ const queryClient = useQueryClient ( ) ;
30+
31+ const repoQueryKey = getRepositoryWithSettingsQueryKey (
32+ organization ,
33+ repoWithSettings . id
34+ ) ;
35+
36+ const repoMutationOpts = mutationOptions ( {
37+ mutationFn : ( data : { codeReviewTriggers ?: string [ ] ; enabledCodeReview ?: boolean } ) => {
38+ return fetchMutation < RepositoryWithSettings [ ] > ( {
39+ method : 'PUT' ,
40+ url : `/organizations/${ organization . slug } /repos/settings/` ,
41+ data : { ...data , repositoryIds : [ repoWithSettings . id ] } ,
42+ } ) ;
43+ } ,
44+ onMutate : ( data : { codeReviewTriggers ?: string [ ] ; enabledCodeReview ?: boolean } ) => {
45+ const previous =
46+ queryClient . getQueryData <
47+ [ RepositoryWithSettings , string | undefined , Response | undefined ]
48+ > ( repoQueryKey ) ;
49+ if ( previous ) {
50+ const [ repo , statusText , resp ] = previous ;
51+ queryClient . setQueryData ( repoQueryKey , [
52+ {
53+ ...repo ,
54+ settings : {
55+ ...repo . settings ,
56+ ...data ,
57+ } ,
58+ } ,
59+ statusText ,
60+ resp ,
61+ ] ) ;
62+ }
63+ return { previous} ;
64+ } ,
65+ onError : ( _error , _data , context ) => {
66+ if ( context ?. previous ) {
67+ queryClient . setQueryData ( repoQueryKey , context . previous ) ;
68+ }
69+ } ,
70+ onSettled : ( ) => {
71+ queryClient . invalidateQueries ( {
72+ queryKey : [ `/organizations/${ organization . slug } /repos/` ] ,
73+ } ) ;
74+ queryClient . invalidateQueries ( {
75+ queryKey : getSeerOnboardingCheckQueryOptions ( { organization} ) . queryKey ,
76+ } ) ;
77+ queryClient . invalidateQueries ( { queryKey : repoQueryKey } ) ;
78+ } ,
79+ } ) ;
2080
2181 return (
2282 < Stack gap = "lg" >
@@ -27,59 +87,58 @@ export function RepoDetailsForm({organization, repoWithSettings}: Props) {
2787 ) }
2888 </ Alert >
2989 ) }
30- < Form
31- allowUndo
32- saveOnBlur
33- apiMethod = "PUT"
34- apiEndpoint = { `/organizations/${ organization . slug } /repos/settings/` }
35- initialData = {
36- {
37- enabledCodeReview : repoWithSettings ?. settings ?. enabledCodeReview ?? false ,
38- codeReviewTriggers : repoWithSettings ?. settings ?. codeReviewTriggers ?? [ ] ,
39- repositoryIds : [ repoWithSettings . id ] ,
40- } satisfies RepositorySettings
41- }
42- >
43- < JsonForm
44- disabled = { ! canWrite }
45- forms = { [
46- {
47- title : t ( 'AI Code Review' ) ,
48- fields : [
49- {
50- name : 'enabledCodeReview' ,
51- label : t ( 'Enable Code Review' ) ,
52- help : t ( 'Seer will review your PRs and flag potential bugs.' ) ,
53- type : 'boolean' ,
54- getData : data => ( {
55- enabledCodeReview : data . enabledCodeReview ,
56- repositoryIds : [ repoWithSettings . id ] ,
57- } ) ,
58- } ,
59- {
60- name : 'codeReviewTriggers' ,
61- label : t ( 'Code Review Triggers' ) ,
62- help : tct (
63- 'Reviews can always run on demand by calling [code:@sentry review], whenever a PR is opened, or after each commit is pushed to a PR.' ,
64- { code : < code /> }
65- ) ,
66- type : 'choice' ,
67- multiple : true ,
68- choices : [
69- [ 'on_ready_for_review' , t ( 'On Ready for Review' ) ] ,
70- [ 'on_new_commit' , t ( 'On New Commit' ) ] ,
71- ] ,
72- formatMessageValue : false ,
73- getData : data => ( {
74- codeReviewTriggers : data . codeReviewTriggers ,
75- repositoryIds : [ repoWithSettings . id ] ,
76- } ) ,
77- } ,
78- ] ,
79- } ,
80- ] }
81- />
82- </ Form >
90+ < FieldGroup title = { t ( 'AI Code Review' ) } >
91+ < AutoSaveForm
92+ name = "enabledCodeReview"
93+ schema = { schema }
94+ initialValue = { repoWithSettings ?. settings ?. enabledCodeReview ?? false }
95+ mutationOptions = { repoMutationOpts }
96+ >
97+ { field => (
98+ < field . Layout . Row
99+ label = { t ( 'Enable Code Review' ) }
100+ hintText = { t ( 'Seer will review your PRs and flag potential bugs.' ) }
101+ >
102+ < Container flexGrow = { 1 } >
103+ < field . Switch
104+ checked = { field . state . value }
105+ onChange = { field . handleChange }
106+ disabled = { ! canWrite }
107+ />
108+ </ Container >
109+ </ field . Layout . Row >
110+ ) }
111+ </ AutoSaveForm >
112+ < AutoSaveForm
113+ name = "codeReviewTriggers"
114+ schema = { schema }
115+ initialValue = { repoWithSettings ?. settings ?. codeReviewTriggers ?? [ ] }
116+ mutationOptions = { repoMutationOpts }
117+ >
118+ { field => (
119+ < field . Layout . Row
120+ label = { t ( 'Code Review Triggers' ) }
121+ hintText = { tct (
122+ 'Reviews can always run on demand by calling [code:@sentry review], whenever a PR is opened, or after each commit is pushed to a PR.' ,
123+ { code : < code /> }
124+ ) }
125+ >
126+ < Container flexGrow = { 1 } >
127+ < field . Select
128+ multiple
129+ value = { field . state . value }
130+ onChange = { field . handleChange }
131+ disabled = { ! canWrite }
132+ options = { [
133+ { value : 'on_ready_for_review' , label : t ( 'On Ready for Review' ) } ,
134+ { value : 'on_new_commit' , label : t ( 'On New Commit' ) } ,
135+ ] }
136+ />
137+ </ Container >
138+ </ field . Layout . Row >
139+ ) }
140+ </ AutoSaveForm >
141+ </ FieldGroup >
83142 </ Stack >
84143 ) ;
85144}
0 commit comments