-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
ref(seer): Rewrite AutofixRepositories using the new /seer/repos/ endpoints #117740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
97160fd
a3d8313
f0050e8
dfef839
b067ee1
d295dbc
900ea1a
9a44a29
6965a3f
432ffa3
f054409
d2fd488
212cdc2
5e6d47d
ad8b2b3
3c4adec
074c94e
8a15aa9
7674acf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,12 @@ | ||
| import {Fragment, useCallback, useMemo, useRef, useState, type ChangeEvent} from 'react'; | ||
| import { | ||
| Fragment, | ||
| useCallback, | ||
| useEffect, | ||
| useMemo, | ||
| useRef, | ||
| useState, | ||
| type ChangeEvent, | ||
| } from 'react'; | ||
| import styled from '@emotion/styled'; | ||
| import {useInfiniteQuery} from '@tanstack/react-query'; | ||
| import {useVirtualizer} from '@tanstack/react-virtual'; | ||
|
|
@@ -12,7 +20,6 @@ import {Link} from '@sentry/scraps/link'; | |
| import type {ModalRenderProps} from 'sentry/actionCreators/modal'; | ||
| import {LoadingIndicator} from 'sentry/components/loadingIndicator'; | ||
| import {MAX_REPOS_LIMIT} from 'sentry/components/seer/legacy/constants'; | ||
| import {SelectableRepoItem} from 'sentry/components/seer/legacy/selectableRepoItem'; | ||
| import {IconSearch} from 'sentry/icons'; | ||
| import {t, tct, tn} from 'sentry/locale'; | ||
| import {useFetchAllPages} from 'sentry/utils/api/apiFetch'; | ||
|
|
@@ -22,19 +29,28 @@ import { | |
| } from 'sentry/utils/repositories/repoQueryOptions'; | ||
| import {useOrganization} from 'sentry/utils/useOrganization'; | ||
|
|
||
| import {SelectableRepoItem} from './selectableRepoItem'; | ||
|
|
||
| type Props = ModalRenderProps & { | ||
| /** | ||
| * Callback function triggered when the modal is saved. | ||
| * Repositories currently selected for Autofix in the parent component. | ||
| */ | ||
| onSave: (repoIds: string[]) => void; | ||
| hiddenExternalIds: string[]; | ||
|
|
||
| /** | ||
| * Repositories currently selected for Autofix in the parent component. | ||
| * Callback function triggered when the modal is saved. | ||
| */ | ||
| selectedRepoIds: string[]; | ||
| onSave: ({ | ||
| selectedExternalIds, | ||
| selectedRepoIds, | ||
| }: { | ||
| selectedExternalIds: string[]; | ||
| selectedRepoIds: string[]; | ||
| }) => void; | ||
| }; | ||
|
|
||
| export function AddAutofixRepoModal({ | ||
| selectedRepoIds, | ||
| hiddenExternalIds, | ||
| onSave, | ||
| Header, | ||
| Body, | ||
|
|
@@ -49,53 +65,44 @@ export function AddAutofixRepoModal({ | |
| }); | ||
| useFetchAllPages({result: repositoriesQuery}); | ||
| const {data: repositories, isFetching: isFetchingRepositories} = repositoriesQuery; | ||
|
|
||
| const [modalSearchQuery, setModalSearchQuery] = useState(''); | ||
| const [selectedExternalIds, setSelectedExternalIds] = useState<string[]>([]); | ||
| const [showMaxLimitAlert, setShowMaxLimitAlert] = useState(false); | ||
| const [modalSelectedRepoIds, setModalSelectedRepoIds] = useState(selectedRepoIds); | ||
|
|
||
| const newModalSelectedRepoIds = modalSelectedRepoIds.filter( | ||
| id => !selectedRepoIds.includes(id) | ||
| ); | ||
|
|
||
| const unselectedRepositories = useMemo(() => { | ||
| const filteredRepositories = useMemo(() => { | ||
| if (!repositories) { | ||
| return []; | ||
| } | ||
| return repositories.filter(repo => !selectedRepoIds.includes(repo.externalId)); | ||
| }, [repositories, selectedRepoIds]); | ||
|
|
||
| const filteredModalRepositories = useMemo(() => { | ||
| let filtered = unselectedRepositories; | ||
| if (modalSearchQuery.trim()) { | ||
| const query = modalSearchQuery.toLowerCase(); | ||
| filtered = unselectedRepositories.filter(repo => | ||
| repo.name.toLowerCase().includes(query) | ||
| ); | ||
| } | ||
|
|
||
| return filtered.filter(repo => repo.provider?.id && repo.provider.id !== 'unknown'); | ||
| }, [unselectedRepositories, modalSearchQuery]); | ||
|
|
||
| const handleToggleRepository = useCallback((repoId: string) => { | ||
| setModalSelectedRepoIds(prev => { | ||
| if (prev.includes(repoId)) { | ||
| setShowMaxLimitAlert(false); | ||
| return prev.filter(id => id !== repoId); | ||
| const query = modalSearchQuery.trim().toLowerCase(); | ||
| return repositories.filter(repo => { | ||
| if (hiddenExternalIds.includes(repo.externalId)) { | ||
| return false; | ||
| } | ||
| if (prev.length >= MAX_REPOS_LIMIT) { | ||
| setShowMaxLimitAlert(true); | ||
| return prev; | ||
| if (query && !repo.name.toLowerCase().includes(query)) { | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| }, [repositories, hiddenExternalIds, modalSearchQuery]); | ||
|
|
||
| const handleToggleRepository = useCallback((externalId: string) => { | ||
| setSelectedExternalIds(prev => { | ||
| if (prev.includes(externalId)) { | ||
| return prev.filter(id => id !== externalId); | ||
|
sentry[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
| setShowMaxLimitAlert(false); | ||
| return [...prev, repoId]; | ||
| return prev.length >= MAX_REPOS_LIMIT ? prev : [...prev, externalId]; | ||
|
sentry[bot] marked this conversation as resolved.
Outdated
|
||
| }); | ||
| }, []); | ||
|
|
||
| // Virtualizer setup (simplified based on docs) | ||
| useEffect(() => { | ||
| setShowMaxLimitAlert(selectedExternalIds.length >= MAX_REPOS_LIMIT); | ||
| }, [selectedExternalIds.length]); | ||
|
cursor[bot] marked this conversation as resolved.
Comment on lines
+103
to
+105
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: The repository limit alert does not account for existing repositories, causing silent UI blocking when the total limit is reached. Suggested FixUpdate the Prompt for AI Agent |
||
|
|
||
| const parentRef = useRef<HTMLDivElement>(null); | ||
|
|
||
| const rowVirtualizer = useVirtualizer({ | ||
| count: filteredModalRepositories.length, | ||
| count: filteredRepositories.length, | ||
| getScrollElement: () => parentRef.current, | ||
| estimateSize: () => 36, | ||
| overscan: 20, | ||
|
|
@@ -135,9 +142,9 @@ export function AddAutofixRepoModal({ | |
| <StyledLoadingIndicator size={36} /> | ||
| <LoadingMessage>{t('Loading repositories...')}</LoadingMessage> | ||
| </Stack> | ||
| ) : filteredModalRepositories.length === 0 ? ( | ||
| ) : filteredRepositories.length === 0 ? ( | ||
| <EmptyMessage> | ||
| {modalSearchQuery.trim() && unselectedRepositories.length > 0 | ||
| {modalSearchQuery.trim() | ||
| ? t('No matching repositories found.') | ||
| : t('All available repositories have been added.')} | ||
|
ryan953 marked this conversation as resolved.
|
||
| </EmptyMessage> | ||
|
|
@@ -151,7 +158,7 @@ export function AddAutofixRepoModal({ | |
| }} | ||
| > | ||
| {rowVirtualizer.getVirtualItems().map(virtualItem => { | ||
| const repo = filteredModalRepositories[virtualItem.index]!; | ||
| const repo = filteredRepositories[virtualItem.index]!; | ||
| return ( | ||
| <div | ||
| key={virtualItem.key} | ||
|
|
@@ -166,7 +173,7 @@ export function AddAutofixRepoModal({ | |
| > | ||
| <SelectableRepoItem | ||
| repo={repo} | ||
| isSelected={modalSelectedRepoIds.includes(repo.externalId)} | ||
| isSelected={selectedExternalIds.includes(repo.externalId)} | ||
| onToggle={handleToggleRepository} | ||
| /> | ||
| </div> | ||
|
|
@@ -191,16 +198,19 @@ export function AddAutofixRepoModal({ | |
| <Button | ||
| variant="primary" | ||
| onClick={() => { | ||
| onSave(modalSelectedRepoIds); | ||
| const selectedRepoIds = selectedExternalIds | ||
| .map( | ||
| externalId => | ||
| repositories?.find(repo => repo.externalId === externalId)?.id | ||
| ) | ||
| .filter<string>(value => value !== undefined); | ||
|
sentry[bot] marked this conversation as resolved.
|
||
|
|
||
| onSave({selectedExternalIds, selectedRepoIds}); | ||
|
ryan953 marked this conversation as resolved.
|
||
| closeModal(); | ||
| }} | ||
| > | ||
| {newModalSelectedRepoIds.length > 0 | ||
| ? tn( | ||
| 'Add %s Repository', | ||
| 'Add %s Repositories', | ||
| newModalSelectedRepoIds.length | ||
| ) | ||
| {selectedExternalIds.length > 0 | ||
| ? tn('Add %s Repository', 'Add %s Repositories', selectedExternalIds.length) | ||
| : t('Done')} | ||
| </Button> | ||
| </Flex> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.