From 4193a566c5e466be53c85cfc588edda918dc533c Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 26 Mar 2026 18:19:00 -0400 Subject: [PATCH 1/7] feat(scraps): add hotkey module (#111444) This PR centralizes the existing hotkey utils into an official `@sentry/scraps/hotkey` module that exposes our custom `useHotkeys()` hook with a `Kbd` and `Hotkey` component. This opens the door to better primitives down the line like global registration, a help menu, and more. [See Hotkey Story](https://sentry-git-scraps-kbd.sentry.dev/stories/core/hotkey) --- .github/codeowners-coverage-baseline.txt | 2 - .../components/alerts/pageBanner.stories.tsx | 5 +- .../ui/commandPaletteStateContext.tsx | 3 +- .../negativeSpaceContainer.stories.tsx | 4 +- .../copyToClipboardButton.stories.tsx | 3 +- static/app/components/core/hotkey/hotkey.mdx | 144 +++++++++++++++++ .../components/core/hotkey/hotkey.spec.tsx | 101 ++++++++++++ static/app/components/core/hotkey/hotkey.tsx | 73 +++++++++ static/app/components/core/hotkey/index.tsx | 3 + .../app/components/core/hotkey/kbd.spec.tsx | 21 +++ static/app/components/core/hotkey/kbd.tsx | 40 +++++ .../app/components/core/hotkey/keyMappings.ts | 145 ++++++++++++++++++ .../core/hotkey}/useHotkeys.spec.tsx | 8 +- .../core/hotkey}/useHotkeys.tsx | 3 +- static/app/components/core/inspector.tsx | 2 +- static/app/components/core/text/prose.tsx | 4 + .../screenshot/modal.tsx | 2 +- static/app/components/globalDrawer/index.tsx | 2 +- static/app/components/hotkeysLabel.spec.tsx | 39 ----- static/app/components/hotkeysLabel.tsx | 95 ------------ .../components/searchBar/searchDropdown.tsx | 4 +- .../tables/gridEditable/index.stories.tsx | 6 +- .../app/components/themeAndStyleProvider.tsx | 3 +- static/app/components/tours/components.tsx | 2 +- .../components/debugNotificationsSearch.tsx | 2 +- static/app/stories/view/storySearch.tsx | 5 +- static/app/stories/view/storyTree.tsx | 6 +- .../api/useFetchSequentialPages.stories.tsx | 5 +- static/app/utils/getKeyCode.ts | 83 ---------- .../hooks/useCopyIssueDetails.spec.tsx | 5 +- .../streamline/hooks/useCopyIssueDetails.tsx | 3 +- .../views/navigation/index.desktop.spec.tsx | 7 +- static/app/views/navigation/index.tsx | 2 +- .../app/views/seerExplorer/explorerPanel.tsx | 19 ++- .../views/seerExplorer/useExplorerPanel.tsx | 3 +- .../components/settingsSearch/index.tsx | 2 +- 36 files changed, 594 insertions(+), 262 deletions(-) create mode 100644 static/app/components/core/hotkey/hotkey.mdx create mode 100644 static/app/components/core/hotkey/hotkey.spec.tsx create mode 100644 static/app/components/core/hotkey/hotkey.tsx create mode 100644 static/app/components/core/hotkey/index.tsx create mode 100644 static/app/components/core/hotkey/kbd.spec.tsx create mode 100644 static/app/components/core/hotkey/kbd.tsx create mode 100644 static/app/components/core/hotkey/keyMappings.ts rename static/app/{utils => components/core/hotkey}/useHotkeys.spec.tsx (95%) rename static/app/{utils => components/core/hotkey}/useHotkeys.tsx (96%) delete mode 100644 static/app/components/hotkeysLabel.spec.tsx delete mode 100644 static/app/components/hotkeysLabel.tsx delete mode 100644 static/app/utils/getKeyCode.ts diff --git a/.github/codeowners-coverage-baseline.txt b/.github/codeowners-coverage-baseline.txt index 3b19ec26e909ba..1d3ee12af227dc 100644 --- a/.github/codeowners-coverage-baseline.txt +++ b/.github/codeowners-coverage-baseline.txt @@ -752,8 +752,6 @@ static/app/components/hook.spec.tsx static/app/components/hook.tsx static/app/components/hookOrDefault.spec.tsx static/app/components/hookOrDefault.tsx -static/app/components/hotkeysLabel.spec.tsx -static/app/components/hotkeysLabel.tsx static/app/components/hovercard.spec.tsx static/app/components/hovercard.tsx static/app/components/iconCircledNumber.tsx diff --git a/static/app/components/alerts/pageBanner.stories.tsx b/static/app/components/alerts/pageBanner.stories.tsx index 445eb0ab1ad42e..6c7d85bf55c492 100644 --- a/static/app/components/alerts/pageBanner.stories.tsx +++ b/static/app/components/alerts/pageBanner.stories.tsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import replaysDeadRageBackground from 'sentry-images/spot/replay-dead-rage-changelog.svg'; import {Button, LinkButton} from '@sentry/scraps/button'; +import {InlineCode} from '@sentry/scraps/code'; import {ExternalLink} from '@sentry/scraps/link'; import {PageBanner} from 'sentry/components/alerts/pageBanner'; @@ -42,7 +43,7 @@ export default Storybook.story('PageBanner', story => {

This example renders an X in the top-right corner. You can wire it up with - something like useDismissAlert(). + something like useDismissAlert().

Is Dismissed? {String(isDismissed)} @@ -72,7 +73,7 @@ export default Storybook.story('PageBanner', story => {

The banner will resize if it's shrunk really narrow. To make it expand inside a - flex parent set flex-grow:1. + flex parent set flex-grow:1.

+ + {field.state.value + ? t( + '%s of %s existing repos have code review enabled', + reposWithCodeReviewCount, + seerReposCount + ) + : t( + '%s of %s existing repos have code review disabled', + seerReposCount - reposWithCodeReviewCount, + seerReposCount + )} + + + + )} + + + + {field => ( + + } + )} + > + + + + + + + + + )} + + + ); +} diff --git a/static/gsApp/views/seerAutomation/components/repoDetails/repoDetailsForm.tsx b/static/gsApp/views/seerAutomation/components/repoDetails/repoDetailsForm.tsx index 36d787f8fba4e1..661b2a7301d171 100644 --- a/static/gsApp/views/seerAutomation/components/repoDetails/repoDetailsForm.tsx +++ b/static/gsApp/views/seerAutomation/components/repoDetails/repoDetailsForm.tsx @@ -3,12 +3,12 @@ import {Stack} from '@sentry/scraps/layout'; import {Form} from 'sentry/components/forms/form'; import JsonForm from 'sentry/components/forms/jsonForm'; +import {type RepositorySettings} from 'sentry/components/repositories/useBulkUpdateRepositorySettings'; import {t, tct} from 'sentry/locale'; import {type RepositoryWithSettings} from 'sentry/types/integrations'; import type {Organization} from 'sentry/types/organization'; import {useCanWriteSettings} from 'getsentry/views/seerAutomation/components/useCanWriteSettings'; -import {type RepositorySettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useBulkUpdateRepositorySettings'; interface Props { organization: Organization; diff --git a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx index 4e065e988b1a4d..87ea64f66ada6d 100644 --- a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx +++ b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx @@ -20,6 +20,8 @@ import {LoadingError} from 'sentry/components/loadingError'; import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {Panel} from 'sentry/components/panels/panel'; import {ScmRepoTreeModal} from 'sentry/components/repositories/scmRepoTreeModal'; +import {useBulkUpdateRepositorySettings} from 'sentry/components/repositories/useBulkUpdateRepositorySettings'; +import {getRepositoryWithSettingsQueryKey} from 'sentry/components/repositories/useRepositoryWithSettings'; import {IconAdd} from 'sentry/icons'; import {IconSearch} from 'sentry/icons/iconSearch'; import {t, tct} from 'sentry/locale'; @@ -35,8 +37,6 @@ import {useOrganization} from 'sentry/utils/useOrganization'; import {SeerRepoTableHeader} from 'getsentry/views/seerAutomation/components/repoTable/seerRepoTableHeader'; import {SeerRepoTableRow} from 'getsentry/views/seerAutomation/components/repoTable/seerRepoTableRow'; -import {useBulkUpdateRepositorySettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useBulkUpdateRepositorySettings'; -import {getRepositoryWithSettingsQueryKey} from 'getsentry/views/seerAutomation/onboarding/hooks/useRepositoryWithSettings'; const GRID_COLUMNS = '40px 1fr 118px 150px'; const SELECTED_ROW_HEIGHT = 44; diff --git a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableHeader.tsx b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableHeader.tsx index 54464c61b68585..2154026373c489 100644 --- a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableHeader.tsx +++ b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableHeader.tsx @@ -8,6 +8,7 @@ import {Flex} from '@sentry/scraps/layout'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import {DropdownMenu} from 'sentry/components/dropdownMenu'; import {QuestionTooltip} from 'sentry/components/questionTooltip'; +import type {useBulkUpdateRepositorySettings} from 'sentry/components/repositories/useBulkUpdateRepositorySettings'; import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {t, tct, tn} from 'sentry/locale'; import {parseQueryKey} from 'sentry/utils/api/apiQueryKey'; @@ -15,7 +16,6 @@ import type {Sort} from 'sentry/utils/discover/fields'; import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState'; import {useCanWriteSettings} from 'getsentry/views/seerAutomation/components/useCanWriteSettings'; -import type {useBulkUpdateRepositorySettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useBulkUpdateRepositorySettings'; interface Props { gridColumns: string; diff --git a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableRow.tsx b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableRow.tsx index ecca8455caf784..0208f6e6de1bd7 100644 --- a/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableRow.tsx +++ b/static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableRow.tsx @@ -12,6 +12,11 @@ import { addSuccessMessage, } from 'sentry/actionCreators/indicator'; import {getRepoStatusLabel} from 'sentry/components/repositories/getRepoStatusLabel'; +import {useBulkUpdateRepositorySettings} from 'sentry/components/repositories/useBulkUpdateRepositorySettings'; +import { + getRepositoryWithSettingsQueryKey, + useRepositoryWithSettings, +} from 'sentry/components/repositories/useRepositoryWithSettings'; import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {IconOpen} from 'sentry/icons/iconOpen'; import {t} from 'sentry/locale'; @@ -26,11 +31,6 @@ import {useQueryClient} from 'sentry/utils/queryClient'; import {useOrganization} from 'sentry/utils/useOrganization'; import {useCanWriteSettings} from 'getsentry/views/seerAutomation/components/useCanWriteSettings'; -import {useBulkUpdateRepositorySettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useBulkUpdateRepositorySettings'; -import { - getRepositoryWithSettingsQueryKey, - useRepositoryWithSettings, -} from 'getsentry/views/seerAutomation/onboarding/hooks/useRepositoryWithSettings'; interface Props { gridColumns: string; diff --git a/static/gsApp/views/seerAutomation/onboarding/configureCodeReviewStep.tsx b/static/gsApp/views/seerAutomation/onboarding/configureCodeReviewStep.tsx index 9aca9f09218163..abd5295a726169 100644 --- a/static/gsApp/views/seerAutomation/onboarding/configureCodeReviewStep.tsx +++ b/static/gsApp/views/seerAutomation/onboarding/configureCodeReviewStep.tsx @@ -16,13 +16,13 @@ import { } from 'sentry/components/guidedSteps/guidedSteps'; import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {PanelBody} from 'sentry/components/panels/panelBody'; +import {useBulkUpdateRepositorySettings} from 'sentry/components/repositories/useBulkUpdateRepositorySettings'; import {t} from 'sentry/locale'; import {DEFAULT_CODE_REVIEW_TRIGGERS} from 'sentry/types/integrations'; import {useOrganization} from 'sentry/utils/useOrganization'; import {trackGetsentryAnalytics} from 'getsentry/utils/trackGetsentryAnalytics'; import {useSeerOnboardingContext} from 'getsentry/views/seerAutomation/onboarding/hooks/seerOnboardingContext'; -import {useBulkUpdateRepositorySettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useBulkUpdateRepositorySettings'; import {MaxWidthPanel, PanelDescription, StepContent} from './common'; import {RepositorySelector} from './repositorySelector'; diff --git a/static/gsApp/views/seerAutomation/repoDetails.tsx b/static/gsApp/views/seerAutomation/repoDetails.tsx index 1afc2c2079e653..c25218d84f9fb9 100644 --- a/static/gsApp/views/seerAutomation/repoDetails.tsx +++ b/static/gsApp/views/seerAutomation/repoDetails.tsx @@ -9,6 +9,7 @@ import {useIsSeerSupportedProvider} from 'sentry/components/events/autofix/utils import {LoadingError} from 'sentry/components/loadingError'; import {LoadingIndicator} from 'sentry/components/loadingIndicator'; import {RepoProviderIcon} from 'sentry/components/repositories/repoProviderIcon'; +import {useRepositoryWithSettings} from 'sentry/components/repositories/useRepositoryWithSettings'; import {SentryDocumentTitle} from 'sentry/components/sentryDocumentTitle'; import {t, tct} from 'sentry/locale'; import {useOrganization} from 'sentry/utils/useOrganization'; @@ -17,7 +18,6 @@ import {SettingsPageHeader} from 'sentry/views/settings/components/settingsPageH import {RepoDetailsForm} from 'getsentry/views/seerAutomation/components/repoDetails/repoDetailsForm'; import {SeerSettingsPageWrapper} from 'getsentry/views/seerAutomation/components/seerSettingsPageWrapper'; -import {useRepositoryWithSettings} from 'getsentry/views/seerAutomation/onboarding/hooks/useRepositoryWithSettings'; export default function SeerRepoDetails() { const {repoId} = useParams<{repoId: string}>(); diff --git a/static/gsApp/views/seerAutomation/settings.tsx b/static/gsApp/views/seerAutomation/settings.tsx index e8c9881fd286f4..d2ba78a3f63d42 100644 --- a/static/gsApp/views/seerAutomation/settings.tsx +++ b/static/gsApp/views/seerAutomation/settings.tsx @@ -15,6 +15,10 @@ import type {Organization} from 'sentry/types/organization'; import {fetchMutation} from 'sentry/utils/queryClient'; import {useOrganization} from 'sentry/utils/useOrganization'; import {SettingsPageHeader} from 'sentry/views/settings/components/settingsPageHeader'; +import { + CodeReviewOverviewSection, + useCodeReviewOverviewSection, +} from 'sentry/views/settings/seer/overview/codeReviewOverviewSection'; import { SCMOverviewSection, useSCMOverviewSection, @@ -37,7 +41,10 @@ export function SeerAutomationSettings() { const organization = useOrganization(); const canWrite = useCanWriteSettings(); + const showSeerOverview = organization.features.includes('seer-overview'); + const scmOverviewData = useSCMOverviewSection(); + const codeReviewOverviewData = useCodeReviewOverviewSection(); const orgEndpoint = `/organizations/${organization.slug}/`; const orgMutationOpts = mutationOptions({ @@ -82,9 +89,9 @@ export function SeerAutomationSettings() { /> - - {t('Default Code Review for New Repos')} - , - } - )} - size="xs" - icon="info" - /> - - } - > - - {field => ( - - + ) : ( + + {t('Default Code Review for New Repos')} + , + } + )} + size="xs" + icon="info" /> - - )} - - } - mutationOptions={orgMutationOpts} > - {field => ( - } - )} - > - - - )} - - + + {field => ( + + + + )} + + + {field => ( + } + )} + > + + + )} + + + )} Date: Thu, 26 Mar 2026 16:01:37 -0700 Subject: [PATCH 6/7] ref(cells): jira frontend uses proper issue urls (#111601) Issues links need to use the proper organization-scoped path, in order to be cell safe. the /issues/ url used currently is deprecated and is marked for brownout starting may 15th --- .../app/plugins/components/issueActions.tsx | 28 ++++--------------- .../plugins/jira/components/issueActions.tsx | 7 +---- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/static/app/plugins/components/issueActions.tsx b/static/app/plugins/components/issueActions.tsx index 8fe70355652437..b8191c366d3ad2 100644 --- a/static/app/plugins/components/issueActions.tsx +++ b/static/app/plugins/components/issueActions.tsx @@ -138,21 +138,15 @@ export class IssueActions extends PluginComponentBase { } getPluginCreateEndpoint() { - return ( - '/issues/' + this.getGroup().id + '/plugins/' + this.props.plugin.slug + '/create/' - ); + return `/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/create/`; } getPluginLinkEndpoint() { - return ( - '/issues/' + this.getGroup().id + '/plugins/' + this.props.plugin.slug + '/link/' - ); + return `/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/link/`; } getPluginUnlinkEndpoint() { - return ( - '/issues/' + this.getGroup().id + '/plugins/' + this.props.plugin.slug + '/unlink/' - ); + return `/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/unlink/`; } setDependentFieldState(fieldName: any, state: any) { @@ -165,7 +159,7 @@ export class IssueActions extends PluginComponentBase { const groupId = this.getGroup().id; const pluginSlug = this.props.plugin.slug; - const url = `/issues/${groupId}/plugins/${pluginSlug}/options/`; + const url = `/organizations/${this.getOrganization().slug}/issues/${groupId}/plugins/${pluginSlug}/options/`; // find the fields that this field is dependent on const dependentFormValues = Object.fromEntries( @@ -407,12 +401,7 @@ export class IssueActions extends PluginComponentBase { if (field.has_autocomplete) { field = Object.assign( { - url: - '/api/0/issues/' + - this.getGroup().id + - '/plugins/' + - this.props.plugin.slug + - '/autocomplete', + url: `/api/0/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/autocomplete`, }, field ); @@ -439,12 +428,7 @@ export class IssueActions extends PluginComponentBase { if (field.has_autocomplete) { field = Object.assign( { - url: - '/api/0/issues/' + - this.getGroup().id + - '/plugins/' + - this.props.plugin.slug + - '/autocomplete', + url: `/api/0/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/autocomplete`, }, field ); diff --git a/static/app/plugins/jira/components/issueActions.tsx b/static/app/plugins/jira/components/issueActions.tsx index 1f35bc5940fb95..a6ba4b7b63ea42 100644 --- a/static/app/plugins/jira/components/issueActions.tsx +++ b/static/app/plugins/jira/components/issueActions.tsx @@ -73,12 +73,7 @@ export class IssueActions extends DefaultIssueActions { if (field.has_autocomplete) { field = Object.assign( { - url: - '/api/0/issues/' + - this.getGroup().id + - '/plugins/' + - this.props.plugin.slug + - '/autocomplete', + url: `/api/0/organizations/${this.getOrganization().slug}/issues/${this.getGroup().id}/plugins/${this.props.plugin.slug}/autocomplete`, }, field ); From 4ea415457ecce40a11fecbe578ce9b023b23cb8e Mon Sep 17 00:00:00 2001 From: Max Topolsky <30879163+mtopo27@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:08:03 -0700 Subject: [PATCH 7/7] chore(monitors): capitalize label (#111694) capitalize label to match "Download Size" ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- static/app/views/settings/project/preprod/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/views/settings/project/preprod/types.ts b/static/app/views/settings/project/preprod/types.ts index 643ce1582141ab..fa3ed53cdd7618 100644 --- a/static/app/views/settings/project/preprod/types.ts +++ b/static/app/views/settings/project/preprod/types.ts @@ -124,10 +124,10 @@ export function getMetricLabelForPlatform( platform: Platform | undefined ): string { if (platform === 'android' && metric === 'install_size') { - return 'Uncompressed size'; + return 'Uncompressed Size'; } if (platform === 'apple' && metric === 'install_size') { - return 'Install size'; + return 'Install Size'; } return getMetricLabel(metric); }