@@ -5,6 +5,7 @@ import {ProjectAvatar} from '@sentry/scraps/avatar';
55
66import { CMDKAction } from 'sentry/components/commandPalette/ui/cmdk' ;
77import { CommandPaletteSlot } from 'sentry/components/commandPalette/ui/commandPaletteSlot' ;
8+ import { IconCode , IconProject , IconStack } from 'sentry/icons' ;
89import type { Organization } from 'sentry/types/organization' ;
910import type { Project } from 'sentry/types/project' ;
1011import { replaceRouterParams } from 'sentry/utils/replaceRouterParams' ;
@@ -19,12 +20,66 @@ type ProjectSettingsCommandPaletteAction = {
1920 to : string ;
2021} ;
2122
22- type ProjectSettingsCommandPaletteSection = {
23- icon : ReactNode ;
24- items : ProjectSettingsCommandPaletteAction [ ] ;
23+ type ProjectSettingsCommandPaletteNode = {
24+ items : Array < ProjectSettingsCommandPaletteAction | ProjectSettingsCommandPaletteNode > ;
2525 label : string ;
26+ icon ?: ReactNode ;
2627} ;
2728
29+ function getProjectSettingsSectionLabel ( sectionName : string ) {
30+ switch ( sectionName ) {
31+ case 'Project' :
32+ return 'General' ;
33+ case 'SDK Setup' :
34+ return 'SDK setup' ;
35+ default :
36+ return sectionName ;
37+ }
38+ }
39+
40+ function getProjectSettingsSectionIcon ( sectionLabel : string ) : ReactNode | undefined {
41+ switch ( sectionLabel ) {
42+ case 'General' :
43+ return < IconProject /> ;
44+ case 'Processing' :
45+ return < IconStack /> ;
46+ case 'SDK setup' :
47+ return < IconCode /> ;
48+ default :
49+ return undefined ;
50+ }
51+ }
52+
53+ function flattenSingleItemSection (
54+ section : ProjectSettingsCommandPaletteNode
55+ ) : ProjectSettingsCommandPaletteNode | ProjectSettingsCommandPaletteAction {
56+ if ( section . label === 'Legacy Integrations' && section . items . length > 0 ) {
57+ return section . items [ 0 ] ! ;
58+ }
59+
60+ return section ;
61+ }
62+
63+ function isProjectSettingsCommandPaletteNode (
64+ item : ProjectSettingsCommandPaletteAction | ProjectSettingsCommandPaletteNode
65+ ) : item is ProjectSettingsCommandPaletteNode {
66+ return 'items' in item ;
67+ }
68+
69+ function renderProjectSettingsCommandPaletteNode (
70+ node : ProjectSettingsCommandPaletteNode | ProjectSettingsCommandPaletteAction
71+ ) : React . ReactNode {
72+ if ( ! isProjectSettingsCommandPaletteNode ( node ) ) {
73+ return < CMDKAction key = { node . to } { ...node } /> ;
74+ }
75+
76+ return (
77+ < CMDKAction key = { node . label } display = { { label : node . label , icon : node . icon } } >
78+ { node . items . map ( item => renderProjectSettingsCommandPaletteNode ( item ) ) }
79+ </ CMDKAction >
80+ ) ;
81+ }
82+
2883function shouldShowItem (
2984 item : NavigationItem ,
3085 context : Omit < NavigationGroupProps , 'items' | 'name' | 'id' > ,
@@ -43,36 +98,69 @@ export function getProjectSettingsCommandPaletteSections({
4398} : {
4499 organization : Organization ;
45100 project : Project ;
46- } ) : ProjectSettingsCommandPaletteSection [ ] {
101+ } ) : ProjectSettingsCommandPaletteNode [ ] {
47102 const context = {
48103 access : new Set ( organization . access ) ,
49104 features : new Set ( organization . features ) ,
50105 organization,
51106 project,
52107 } ;
108+ const groupedSectionLabels = new Set ( [
109+ 'General' ,
110+ 'Processing' ,
111+ 'SDK setup' ,
112+ 'Legacy Integrations' ,
113+ ] ) ;
53114
54- return getNavigationConfiguration ( {
115+ const sections = getNavigationConfiguration ( {
55116 debugFilesNeedsReview : false ,
56117 organization,
57118 project,
58119 } )
59- . map ( section => ( {
60- icon : < ProjectAvatar project = { project } size = { 16 } /> ,
61- label : section . name ,
62- items : section . items
63- . filter ( item => shouldShowItem ( item , context , section ) )
64- . map ( item => ( {
65- display : {
66- label : item . title ,
67- } ,
68- keywords : [ section . name , 'project settings' , 'settings' ] ,
69- to : replaceRouterParams ( item . path , {
70- orgId : organization . slug ,
71- projectId : project . slug ,
72- } ) ,
73- } ) ) ,
74- } ) )
120+ . map ( section => {
121+ const label = getProjectSettingsSectionLabel ( section . name ) ;
122+
123+ return {
124+ icon : groupedSectionLabels . has ( label ) ? (
125+ getProjectSettingsSectionIcon ( label )
126+ ) : (
127+ < ProjectAvatar project = { project } size = { 16 } />
128+ ) ,
129+ label,
130+ items : section . items
131+ . filter ( item => shouldShowItem ( item , context , section ) )
132+ . map ( item => ( {
133+ display : {
134+ label : item . title ,
135+ } ,
136+ keywords : [ section . name , 'project settings' , 'settings' ] ,
137+ to : replaceRouterParams ( item . path , {
138+ orgId : organization . slug ,
139+ projectId : project . slug ,
140+ } ) ,
141+ } ) ) ,
142+ } ;
143+ } )
75144 . filter ( section => section . items . length > 0 ) ;
145+ const groupedSections = sections . filter ( section =>
146+ groupedSectionLabels . has ( section . label )
147+ ) ;
148+ const ungroupedSections = sections . filter (
149+ section => ! groupedSectionLabels . has ( section . label )
150+ ) ;
151+
152+ if ( groupedSections . length === 0 ) {
153+ return ungroupedSections ;
154+ }
155+
156+ return [
157+ {
158+ icon : < ProjectAvatar project = { project } size = { 16 } /> ,
159+ label : 'Project Settings' ,
160+ items : groupedSections . map ( flattenSingleItemSection ) ,
161+ } ,
162+ ...ungroupedSections ,
163+ ] ;
76164}
77165
78166export function ProjectSettingsCommandPaletteActions ( {
@@ -88,11 +176,7 @@ export function ProjectSettingsCommandPaletteActions({
88176 < Fragment >
89177 { sections . map ( section => (
90178 < CommandPaletteSlot key = { section . label } name = "page" >
91- < CMDKAction display = { { label : section . label , icon : section . icon } } >
92- { section . items . map ( item => (
93- < CMDKAction key = { item . to } { ...item } />
94- ) ) }
95- </ CMDKAction >
179+ { renderProjectSettingsCommandPaletteNode ( section ) }
96180 </ CommandPaletteSlot >
97181 ) ) }
98182 </ Fragment >
0 commit comments