1
+ import { Fragment } from 'react' ;
1
2
import styled from '@emotion/styled' ;
2
3
4
+ import { Button } from 'sentry/components/core/button' ;
3
5
import GlobalEventProcessingAlert from 'sentry/components/globalEventProcessingAlert' ;
4
6
import * as Layout from 'sentry/components/layouts/thirds' ;
7
+ import { IconStar } from 'sentry/icons' ;
5
8
import { t } from 'sentry/locale' ;
6
9
import { space } from 'sentry/styles/space' ;
10
+ import { setApiQueryData , useQueryClient } from 'sentry/utils/queryClient' ;
11
+ import useOrganization from 'sentry/utils/useOrganization' ;
7
12
import useProjects from 'sentry/utils/useProjects' ;
8
13
import { useSelectedGroupSearchView } from 'sentry/views/issueList/issueViews/useSelectedGroupSeachView' ;
14
+ import { useUpdateGroupSearchViewStarred } from 'sentry/views/issueList/mutations/useUpdateGroupSearchViewStarred' ;
15
+ import { makeFetchGroupSearchViewKey } from 'sentry/views/issueList/queries/useFetchGroupSearchView' ;
16
+ import type { GroupSearchView } from 'sentry/views/issueList/types' ;
9
17
import { usePrefersStackedNav } from 'sentry/views/nav/prefersStackedNav' ;
10
18
11
19
type LeftNavViewsHeaderProps = {
12
20
selectedProjectIds : number [ ] ;
13
21
} ;
14
22
15
23
function LeftNavViewsHeader ( { selectedProjectIds} : LeftNavViewsHeaderProps ) {
24
+ const organization = useOrganization ( ) ;
16
25
const { projects} = useProjects ( ) ;
17
26
const prefersStackedNav = usePrefersStackedNav ( ) ;
27
+ const queryClient = useQueryClient ( ) ;
18
28
19
29
const selectedProjects = projects . filter ( ( { id} ) =>
20
30
selectedProjectIds . includes ( Number ( id ) )
21
31
) ;
22
32
23
33
const { data : groupSearchView } = useSelectedGroupSearchView ( ) ;
34
+ const { mutate : mutateViewStarred } = useUpdateGroupSearchViewStarred ( {
35
+ onMutate : variables => {
36
+ setApiQueryData < GroupSearchView > (
37
+ queryClient ,
38
+ makeFetchGroupSearchViewKey ( {
39
+ orgSlug : organization . slug ,
40
+ id : variables . id ,
41
+ } ) ,
42
+ oldGroupSearchView =>
43
+ oldGroupSearchView
44
+ ? { ...oldGroupSearchView , starred : variables . starred }
45
+ : oldGroupSearchView
46
+ ) ;
47
+ } ,
48
+ onError : ( _error , variables ) => {
49
+ setApiQueryData < GroupSearchView > (
50
+ queryClient ,
51
+ makeFetchGroupSearchViewKey ( {
52
+ orgSlug : organization . slug ,
53
+ id : variables . id ,
54
+ } ) ,
55
+ oldGroupSearchView =>
56
+ oldGroupSearchView
57
+ ? { ...oldGroupSearchView , starred : ! variables . starred }
58
+ : oldGroupSearchView
59
+ ) ;
60
+ } ,
61
+ } ) ;
24
62
25
63
return (
26
64
< Layout . Header noActionWrap unified = { prefersStackedNav } >
27
65
< Layout . HeaderContent unified = { prefersStackedNav } >
28
- < Layout . Title > { groupSearchView ?. name ?? t ( 'Issues' ) } </ Layout . Title >
66
+ < StyledLayoutTitle >
67
+ { groupSearchView ? (
68
+ < Fragment >
69
+ { groupSearchView . name }
70
+ { organization . features . includes ( 'issue-view-sharing' ) ? (
71
+ < Button
72
+ onClick = { ( ) => {
73
+ mutateViewStarred ( {
74
+ id : groupSearchView . id ,
75
+ starred : ! groupSearchView ?. starred ,
76
+ view : groupSearchView ,
77
+ } ) ;
78
+ } }
79
+ aria-label = {
80
+ groupSearchView ?. starred ? t ( 'Unstar view' ) : t ( 'Star view' )
81
+ }
82
+ icon = {
83
+ < IconStar
84
+ isSolid = { groupSearchView ?. starred }
85
+ color = { groupSearchView ?. starred ? 'yellow300' : 'subText' }
86
+ />
87
+ }
88
+ />
89
+ ) : null }
90
+ </ Fragment >
91
+ ) : (
92
+ t ( 'Issues' )
93
+ ) }
94
+ </ StyledLayoutTitle >
29
95
</ Layout . HeaderContent >
30
96
< Layout . HeaderActions />
31
97
< StyledGlobalEventProcessingAlert projects = { selectedProjects } />
@@ -45,3 +111,8 @@ const StyledGlobalEventProcessingAlert = styled(GlobalEventProcessingAlert)`
45
111
margin-bottom: 0;
46
112
}
47
113
` ;
114
+
115
+ const StyledLayoutTitle = styled ( Layout . Title ) `
116
+ display: flex;
117
+ justify-content: space-between;
118
+ ` ;
0 commit comments