Skip to content

Commit f1a1a06

Browse files
JonasBaclaude
andcommitted
fix(cmdk): Address bugbot findings — admin actions, DSN icon, String coercion
- Restore admin/superuser action group (Open _admin, Open org in _admin, Open Superuser Modal, Exit Superuser) for staff users; these existed in the old useGlobalCommandPaletteActions hook but were not ported to the new GlobalCommandPaletteActions component - Add missing IconList to DSN_ICONS so the third getDsnNavTargets result (Client Keys/DSN) renders with an icon - Remove String(action.to) coercion in modal.tsx and the test helper; both normalizeUrl and navigate already accept LocationDescriptor, and String() would corrupt object-form descriptors to "[object Object]" - Remove redundant CommandPaletteSlot.Provider from the test helper since CommandPaletteProvider already wraps children in one Co-Authored-By: Claude <noreply@anthropic.com>
1 parent dd0b8b9 commit f1a1a06

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

static/app/components/commandPalette/ui/commandPalette.spec.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function GlobalActionsComponent({
8686
const handleAction = useCallback(
8787
(action: CollectionTreeNode<CMDKActionData>) => {
8888
if ('to' in action) {
89-
navigate(String(action.to));
89+
navigate(action.to);
9090
} else if ('onAction' in action) {
9191
action.onAction();
9292
}
@@ -97,10 +97,8 @@ function GlobalActionsComponent({
9797

9898
return (
9999
<CommandPaletteProvider>
100-
<CommandPaletteSlot.Provider>
101-
<ActionsToJSX actions={actions} />
102-
<CommandPalette onAction={handleAction}>{children}</CommandPalette>
103-
</CommandPaletteSlot.Provider>
100+
<ActionsToJSX actions={actions} />
101+
<CommandPalette onAction={handleAction}>{children}</CommandPalette>
104102
</CommandPaletteProvider>
105103
);
106104
}

static/app/components/commandPalette/ui/commandPaletteGlobalActions.tsx

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {ProjectAvatar} from '@sentry/scraps/avatar';
55

66
import {addLoadingMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
77
import {openInviteMembersModal} from 'sentry/actionCreators/modal';
8+
import {openSudo} from 'sentry/actionCreators/sudoModal';
89
import type {
910
CMDKQueryOptions,
1011
CommandPaletteAsyncResult,
@@ -23,6 +24,7 @@ import {
2324
IconGithub,
2425
IconGraph,
2526
IconIssues,
27+
IconList,
2628
IconLock,
2729
IconOpen,
2830
IconSearch,
@@ -32,10 +34,12 @@ import {
3234
} from 'sentry/icons';
3335
import {t} from 'sentry/locale';
3436
import {apiOptions} from 'sentry/utils/api/apiOptions';
35-
import {queryOptions} from 'sentry/utils/queryClient';
37+
import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
38+
import {QUERY_API_CLIENT, queryOptions, useMutation} from 'sentry/utils/queryClient';
3639
import {useMutateUserOptions} from 'sentry/utils/useMutateUserOptions';
3740
import {useOrganization} from 'sentry/utils/useOrganization';
3841
import {useProjects} from 'sentry/utils/useProjects';
42+
import {useUser} from 'sentry/utils/useUser';
3943
import {useGetStarredDashboards} from 'sentry/views/dashboards/hooks/useGetStarredDashboards';
4044
import {AGENTS_LANDING_SUB_PATH} from 'sentry/views/insights/pages/agents/settings';
4145
import {BACKEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/backend/settings';
@@ -52,6 +56,7 @@ import {CommandPaletteSlot} from './commandPaletteSlot';
5256
const DSN_ICONS: React.ReactElement[] = [
5357
<IconIssues key="issues" />,
5458
<IconSettings key="settings" />,
59+
<IconList key="list" />,
5560
];
5661

5762
const helpSearch = new SentryGlobalSearch(['docs', 'develop']);
@@ -72,11 +77,17 @@ function renderAsyncResult(item: CommandPaletteAsyncResult, index: number) {
7277
*/
7378
export function GlobalCommandPaletteActions() {
7479
const organization = useOrganization();
80+
const user = useUser();
7581
const hasDsnLookup = organization.features.includes('cmd-k-dsn-lookup');
7682
const {projects} = useProjects();
7783
const {mutateAsync: mutateUserOptions} = useMutateUserOptions();
7884
const {starredViews} = useStarredIssueViews();
7985
const {data: starredDashboards = []} = useGetStarredDashboards();
86+
const {mutate: exitSuperuser} = useMutation({
87+
mutationFn: () =>
88+
QUERY_API_CLIENT.requestPromise('/auth/superuser/', {method: 'DELETE'}),
89+
onSuccess: () => window.location.reload(),
90+
});
8091

8192
const prefix = `/organizations/${organization.slug}`;
8293

@@ -384,6 +395,44 @@ export function GlobalCommandPaletteActions() {
384395
/>
385396
</CMDKAction>
386397
</CMDKAction>
398+
399+
{user.isStaff && (
400+
<CMDKAction display={{label: t('Admin')}}>
401+
<CMDKAction
402+
display={{label: t('Open _admin'), icon: <IconOpen />}}
403+
keywords={[t('superuser')]}
404+
onAction={() => window.open('/_admin/', '_blank', 'noreferrer')}
405+
/>
406+
<CMDKAction
407+
display={{
408+
label: t('Open %s in _admin', organization.name),
409+
icon: <IconOpen />,
410+
}}
411+
keywords={[t('superuser')]}
412+
onAction={() =>
413+
window.open(
414+
`/_admin/customers/${organization.slug}/`,
415+
'_blank',
416+
'noreferrer'
417+
)
418+
}
419+
/>
420+
{!isActiveSuperuser() && (
421+
<CMDKAction
422+
display={{label: t('Open Superuser Modal'), icon: <IconLock locked />}}
423+
keywords={[t('superuser')]}
424+
onAction={() => openSudo({isSuperuser: true, needsReload: true})}
425+
/>
426+
)}
427+
{isActiveSuperuser() && (
428+
<CMDKAction
429+
display={{label: t('Exit Superuser'), icon: <IconLock locked={false} />}}
430+
keywords={[t('superuser')]}
431+
onAction={() => exitSuperuser()}
432+
/>
433+
)}
434+
</CMDKAction>
435+
)}
387436
</CommandPaletteSlot>
388437
);
389438
}

static/app/components/commandPalette/ui/modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function CommandPaletteModal({Body, closeModal}: ModalRenderProps
1616
const handleSelect = useCallback(
1717
(action: CollectionTreeNode<CMDKActionData>) => {
1818
if ('to' in action) {
19-
navigate(normalizeUrl(String(action.to)));
19+
navigate(normalizeUrl(action.to));
2020
} else if ('onAction' in action) {
2121
action.onAction();
2222
// When the action has children, the palette will push into them so the

0 commit comments

Comments
 (0)