@@ -8,25 +8,35 @@ import {addLoadingMessage, addSuccessMessage} from 'sentry/actionCreators/indica
88import { openInviteMembersModal } from 'sentry/actionCreators/modal' ;
99import { useCommandPaletteActionsRegister } from 'sentry/components/commandPalette/context' ;
1010import type {
11+ CMDKQueryOptions ,
1112 CommandPaletteAction ,
1213 CommandPaletteAsyncResult ,
1314} from 'sentry/components/commandPalette/types' ;
15+ import {
16+ DSN_PATTERN ,
17+ getDsnNavTargets ,
18+ } from 'sentry/components/search/sources/dsnLookupUtils' ;
19+ import type { DsnLookupResponse } from 'sentry/components/search/sources/dsnLookupUtils' ;
1420import {
1521 IconAdd ,
1622 IconCompass ,
1723 IconDashboard ,
1824 IconDiscord ,
1925 IconDocs ,
26+ IconSearch ,
2027 IconGithub ,
2128 IconGraph ,
2229 IconIssues ,
30+ IconList ,
2331 IconOpen ,
2432 IconSettings ,
2533 IconStar ,
2634 IconUser ,
2735 IconPanel ,
36+ IconLock ,
2837} from 'sentry/icons' ;
2938import { t } from 'sentry/locale' ;
39+ import { apiOptions } from 'sentry/utils/api/apiOptions' ;
3040import { queryOptions } from 'sentry/utils/queryClient' ;
3141import { useMutateUserOptions } from 'sentry/utils/useMutateUserOptions' ;
3242import { useOrganization } from 'sentry/utils/useOrganization' ;
@@ -42,6 +52,12 @@ import {useStarredIssueViews} from 'sentry/views/navigation/secondary/sections/i
4252import { useSecondaryNavigation } from 'sentry/views/navigation/secondaryNavigationContext' ;
4353import { getUserOrgNavigationConfiguration } from 'sentry/views/settings/organization/userOrgNavigationConfiguration' ;
4454
55+ const DSN_ICONS : React . ReactElement [ ] = [
56+ < IconIssues key = "issues" /> ,
57+ < IconSettings key = "settings" /> ,
58+ < IconList key = "list" /> ,
59+ ] ;
60+
4561// This hook generates actions for all pages in the primary and secondary navigation.
4662// TODO: Consider refactoring the navigation so that this can read from the same source
4763// of truth and avoid divergence.
@@ -304,6 +320,8 @@ function useNavigationToggleCollapsed(): CommandPaletteAction {
304320 */
305321export function useGlobalCommandPaletteActions ( ) {
306322 const organization = useOrganization ( ) ;
323+ const hasDsnLookup = organization . features . includes ( 'cmd-k-dsn-lookup' ) ;
324+ const { projects} = useProjects ( ) ;
307325 const navigateActions = useNavigationActions ( ) ;
308326 const { mutateAsync : mutateUserOptions } = useMutateUserOptions ( ) ;
309327 const navigationToggleAction = useNavigationToggleCollapsed ( ) ;
@@ -325,32 +343,94 @@ export function useGlobalCommandPaletteActions() {
325343 label : t ( 'Create Dashboard' ) ,
326344 icon : < IconAdd /> ,
327345 } ,
346+ keywords : [ t ( 'add dashboard' ) ] ,
328347 to : `${ navPrefix } /dashboards/new/` ,
329348 } ,
330349 {
331350 display : {
332351 label : t ( 'Create Alert' ) ,
333352 icon : < IconAdd /> ,
334353 } ,
354+ keywords : [ t ( 'add alert' ) ] ,
335355 to : `${ navPrefix } /issues/alerts/wizard/` ,
336356 } ,
337357 {
338358 display : {
339359 label : t ( 'Create Project' ) ,
340360 icon : < IconAdd /> ,
341361 } ,
362+ keywords : [ t ( 'add project' ) ] ,
342363 to : `${ navPrefix } /projects/new/` ,
343364 } ,
344365 {
345366 display : {
346367 label : t ( 'Invite Members' ) ,
347368 icon : < IconUser /> ,
348369 } ,
370+ keywords : [ t ( 'team invite' ) ] ,
349371 onAction : openInviteMembersModal ,
350372 } ,
351373 ] ,
352374 } ,
353375 // END ADD
376+ // BEGIN DSN LOOKUP
377+ {
378+ display : { label : t ( 'DSN' ) } ,
379+ keywords : [ t ( 'client keys' ) ] ,
380+ actions : [
381+ {
382+ display : {
383+ label : t ( 'Project DSN Keys' ) ,
384+ icon : < IconLock locked /> ,
385+ } ,
386+ keywords : [ t ( 'client keys' ) , t ( 'dsn keys' ) ] ,
387+ actions : projects . map ( project => ( {
388+ display : {
389+ label : project . name ,
390+ icon : < ProjectAvatar project = { project } size = { 16 } /> ,
391+ } ,
392+ keywords : [ `dsn ${ project . name } ` , `dsn ${ project . slug } ` ] ,
393+ to : `/settings/${ organization . slug } /projects/${ project . slug } /keys/` ,
394+ } ) ) ,
395+ } ,
396+ hasDsnLookup
397+ ? {
398+ display : {
399+ label : t ( 'Reverse DSN lookup' ) ,
400+ details : t (
401+ 'Paste a DSN into the search bar to find the project it belongs to.'
402+ ) ,
403+ icon : < IconSearch /> ,
404+ } ,
405+ actions : [ ] ,
406+ resource : ( query : string ) : CMDKQueryOptions => {
407+ return queryOptions ( {
408+ ...apiOptions . as < DsnLookupResponse > ( ) (
409+ '/organizations/$organizationIdOrSlug/dsn-lookup/' ,
410+ {
411+ path : { organizationIdOrSlug : organization . slug } ,
412+ query : { dsn : query } ,
413+ staleTime : 30_000 ,
414+ }
415+ ) ,
416+ enabled : DSN_PATTERN . test ( query ) ,
417+ select : data =>
418+ getDsnNavTargets ( data . json ) . map ( ( target , i ) => ( {
419+ to : target . to ,
420+ display : {
421+ label : target . label ,
422+ details : target . description ,
423+ icon : DSN_ICONS [ i ] ,
424+ } ,
425+ keywords : [ query ] ,
426+ } ) ) ,
427+ } ) ;
428+ } ,
429+ }
430+ : undefined ,
431+ ] . filter ( action => action !== undefined ) ,
432+ } ,
433+ // END DSN LOOKUP
354434 // BEGIN HELP ACTIONS
355435 {
356436 display : {
0 commit comments