Skip to content

Commit e27bec5

Browse files
committed
streamline rendering into one component
1 parent f1ab72a commit e27bec5

File tree

2 files changed

+108
-171
lines changed

2 files changed

+108
-171
lines changed

static/gsApp/views/seerAutomation/components/repoTable/seerRepoTable.tsx

Lines changed: 86 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {IconAdd} from 'sentry/icons';
1616
import {IconSearch} from 'sentry/icons/iconSearch';
1717
import {t, tct} from 'sentry/locale';
1818
import type {RepositoryWithSettings} from 'sentry/types/integrations';
19-
import type {Sort} from 'sentry/utils/discover/fields';
2019
import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState';
2120
import {useInfiniteQuery, useQueryClient} from 'sentry/utils/queryClient';
2221
import parseAsSort from 'sentry/utils/url/parseAsSort';
@@ -115,166 +114,99 @@ export default function SeerRepoTable() {
115114
},
116115
});
117116

118-
if (isPending) {
119-
return (
120-
<RepoTable
121-
mutateRepositorySettings={mutateRepositorySettings}
122-
onSortClick={setSort}
123-
isLoading={isPending || isFetchingNextPage}
124-
isLoadingMore={false /* prevent redundant spinners */}
125-
repositories={[]}
126-
searchTerm={searchTerm}
127-
setSearchTerm={setSearchTerm}
128-
sort={sort}
129-
>
130-
<SimpleTable.Empty>
131-
<LoadingIndicator />
132-
</SimpleTable.Empty>
133-
</RepoTable>
134-
);
135-
}
136-
137-
if (isError) {
138-
return (
139-
<RepoTable
140-
mutateRepositorySettings={mutateRepositorySettings}
141-
onSortClick={setSort}
142-
isLoading={isPending || isFetchingNextPage}
143-
isLoadingMore={hasNextPage || isFetchingNextPage}
144-
repositories={[]}
145-
searchTerm={searchTerm}
146-
setSearchTerm={setSearchTerm}
147-
sort={sort}
148-
>
149-
<SimpleTable.Empty>
150-
<LoadingError />
151-
</SimpleTable.Empty>
152-
</RepoTable>
153-
);
154-
}
117+
const hits = repositories?.length ?? 0;
118+
const hasData = hits > 0;
155119

156120
return (
157121
<ListItemCheckboxProvider
158-
hits={repositories.length}
159-
knownIds={repositories.map(repository => repository.id)}
122+
hits={repositories?.length ?? 0}
123+
knownIds={repositories?.map(repository => repository.id) ?? []}
160124
queryKey={queryOptions.queryKey}
161125
>
162-
<RepoTable
163-
mutateRepositorySettings={mutateRepositorySettings}
164-
onSortClick={setSort}
165-
isLoading={isPending || isFetchingNextPage}
166-
isLoadingMore={hasNextPage || isFetchingNextPage}
167-
repositories={repositories}
168-
searchTerm={searchTerm}
169-
setSearchTerm={setSearchTerm}
170-
sort={sort}
171-
>
172-
{repositories.length === 0 ? (
173-
<SimpleTable.Empty>
174-
{searchTerm
175-
? tct('No repositories found matching [searchTerm]', {
176-
searchTerm: <code>{searchTerm}</code>,
177-
})
178-
: t('No repositories found')}
179-
</SimpleTable.Empty>
180-
) : (
181-
repositories.map(repository => (
182-
<SeerRepoTableRow
183-
key={repository.id}
184-
mutateRepositorySettings={mutateRepositorySettings}
185-
mutationData={mutationData}
186-
repository={repository}
126+
<Stack gap="lg">
127+
<Grid
128+
minWidth="0"
129+
gap="md"
130+
columns={hasData ? '1fr max-content' : '1fr max-content max-content'}
131+
>
132+
<InputGroup>
133+
<InputGroup.LeadingItems disablePointerEvents>
134+
<IconSearch />
135+
</InputGroup.LeadingItems>
136+
<InputGroup.Input
137+
size="md"
138+
disabled={!hasData}
139+
placeholder={t('Search')}
140+
value={searchTerm ?? ''}
141+
onChange={e =>
142+
setSearchTerm(e.target.value, {limitUrlUpdates: debounce(125)})
143+
}
187144
/>
188-
))
189-
)}
190-
</RepoTable>
191-
</ListItemCheckboxProvider>
192-
);
193-
}
194-
195-
function RepoTable({
196-
children,
197-
isLoading,
198-
isLoadingMore,
199-
mutateRepositorySettings,
200-
onSortClick,
201-
repositories,
202-
searchTerm,
203-
setSearchTerm,
204-
sort,
205-
}: {
206-
children: React.ReactNode;
207-
isLoading: boolean;
208-
isLoadingMore: boolean;
209-
mutateRepositorySettings: ReturnType<typeof useBulkUpdateRepositorySettings>['mutate'];
210-
onSortClick: (sort: Sort) => void;
211-
repositories: RepositoryWithSettings[];
212-
searchTerm: string;
213-
setSearchTerm: ReturnType<typeof useQueryState<string>>[1];
214-
sort: Sort;
215-
}) {
216-
const organization = useOrganization();
217-
const hasData = repositories.length > 0;
218-
return (
219-
<Stack gap="lg">
220-
<Grid
221-
minWidth="0"
222-
gap="md"
223-
columns={hasData ? '1fr max-content' : '1fr max-content max-content'}
224-
>
225-
<InputGroup>
226-
<InputGroup.LeadingItems disablePointerEvents>
227-
<IconSearch />
228-
</InputGroup.LeadingItems>
229-
<InputGroup.Input
230-
size="md"
231-
disabled={!hasData}
232-
placeholder={t('Search')}
233-
value={searchTerm ?? ''}
234-
onChange={e =>
235-
setSearchTerm(e.target.value, {limitUrlUpdates: debounce(125)})
236-
}
145+
</InputGroup>
146+
147+
{hits > 0 ? null : <LoadingIndicator mini />}
148+
149+
<LinkButton
150+
priority="primary"
151+
icon={<IconAdd />}
152+
to={{
153+
pathname: `/settings/${organization.slug}/integrations/`,
154+
query: {
155+
category: 'source code management',
156+
},
157+
}}
158+
>
159+
{t('Add Repository')}
160+
</LinkButton>
161+
</Grid>
162+
<SimpleTableWithColumns>
163+
<SeerRepoTableHeader
164+
mutateRepositorySettings={mutateRepositorySettings}
165+
onSortClick={setSort}
166+
disabled={isPending || isFetchingNextPage}
167+
hits={hits}
168+
sort={sort}
237169
/>
238-
</InputGroup>
239-
240-
{hasData ? null : <LoadingIndicator mini />}
241-
242-
<LinkButton
243-
priority="primary"
244-
icon={<IconAdd />}
245-
to={{
246-
pathname: `/settings/${organization.slug}/integrations/`,
247-
query: {
248-
category: 'source code management',
249-
},
250-
}}
251-
>
252-
{t('Add Repository')}
253-
</LinkButton>
254-
</Grid>
255-
256-
<SimpleTableWithColumns>
257-
<SeerRepoTableHeader
258-
mutateRepositorySettings={mutateRepositorySettings}
259-
onSortClick={onSortClick}
260-
disabled={isLoading}
261-
repositories={repositories}
262-
sort={sort}
263-
/>
264-
{children}
265-
{isLoadingMore ? (
266-
<SimpleTable.Row key="loading-row">
267-
<SimpleTable.RowCell
268-
align="center"
269-
justify="center"
270-
style={{gridColumn: '1 / -1'}}
271-
>
272-
<LoadingIndicator mini />
273-
</SimpleTable.RowCell>
274-
</SimpleTable.Row>
275-
) : null}
276-
</SimpleTableWithColumns>
277-
</Stack>
170+
{isPending ? (
171+
<SimpleTable.Empty>
172+
<LoadingIndicator />
173+
</SimpleTable.Empty>
174+
) : isError ? (
175+
<SimpleTable.Empty>
176+
<LoadingError />
177+
</SimpleTable.Empty>
178+
) : repositories.length === 0 ? (
179+
<SimpleTable.Empty>
180+
{searchTerm
181+
? tct('No repositories found matching [searchTerm]', {
182+
searchTerm: <code>{searchTerm}</code>,
183+
})
184+
: t('No repositories found')}
185+
</SimpleTable.Empty>
186+
) : (
187+
repositories.map(repository => (
188+
<SeerRepoTableRow
189+
key={repository.id}
190+
mutateRepositorySettings={mutateRepositorySettings}
191+
mutationData={mutationData}
192+
repository={repository}
193+
/>
194+
))
195+
)}
196+
{hasNextPage || isFetchingNextPage ? (
197+
<SimpleTable.Row key="loading-row">
198+
<SimpleTable.RowCell
199+
align="center"
200+
justify="center"
201+
style={{gridColumn: '1 / -1'}}
202+
>
203+
<LoadingIndicator mini />
204+
</SimpleTable.RowCell>
205+
</SimpleTable.Row>
206+
) : null}
207+
</SimpleTableWithColumns>
208+
</Stack>
209+
</ListItemCheckboxProvider>
278210
);
279211
}
280212

static/gsApp/views/seerAutomation/components/repoTable/seerRepoTableHeader.tsx

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {DropdownMenu} from 'sentry/components/dropdownMenu';
1010
import QuestionTooltip from 'sentry/components/questionTooltip';
1111
import {SimpleTable} from 'sentry/components/tables/simpleTable';
1212
import {t, tct, tn} from 'sentry/locale';
13-
import type {RepositoryWithSettings} from 'sentry/types/integrations';
1413
import type {Sort} from 'sentry/utils/discover/fields';
1514
import {useListItemCheckboxContext} from 'sentry/utils/list/useListItemCheckboxState';
1615
import {parseQueryKey} from 'sentry/utils/queryClient';
@@ -20,9 +19,9 @@ import type {useBulkUpdateRepositorySettings} from 'getsentry/views/seerAutomati
2019

2120
interface Props {
2221
disabled: boolean;
22+
hits: number;
2323
mutateRepositorySettings: ReturnType<typeof useBulkUpdateRepositorySettings>['mutate'];
2424
onSortClick: (key: Sort) => void;
25-
repositories: RepositoryWithSettings[];
2625
sort: Sort;
2726
}
2827

@@ -50,19 +49,25 @@ export default function SeerRepoTableHeader({
5049
disabled,
5150
mutateRepositorySettings,
5251
onSortClick,
53-
repositories,
52+
hits,
5453
sort,
5554
}: Props) {
5655
const canWrite = useCanWriteSettings();
5756
const listItemCheckboxState = useListItemCheckboxContext();
58-
const {countSelected, isAllSelected, isAnySelected, queryKey, selectAll, selectedIds} =
59-
listItemCheckboxState;
57+
const {
58+
countSelected,
59+
isAllSelected,
60+
isAnySelected,
61+
queryKey,
62+
selectAll,
63+
selectedIds,
64+
knownIds,
65+
} = listItemCheckboxState;
6066
const queryOptions = queryKey ? parseQueryKey(queryKey).options : undefined;
6167
const queryString = queryOptions?.query?.query;
6268

6369
const handleBulkCodeReview = (enabledCodeReview: boolean) => {
64-
const repositoryIds =
65-
selectedIds === 'all' ? repositories.map(repo => repo.id) : selectedIds;
70+
const repositoryIds = selectedIds === 'all' ? knownIds : selectedIds;
6671
mutateRepositorySettings(
6772
{
6873
enabledCodeReview,
@@ -96,9 +101,9 @@ export default function SeerRepoTableHeader({
96101
<TableHeader>
97102
<SimpleTable.HeaderCell>
98103
<SelectAllCheckbox
99-
listItemCheckboxState={listItemCheckboxState}
100-
repositories={repositories}
101104
disabled={disabled}
105+
hits={hits}
106+
listItemCheckboxState={listItemCheckboxState}
102107
/>
103108
</SimpleTable.HeaderCell>
104109
{COLUMNS.map(({title, key, sortKey}) => (
@@ -129,9 +134,9 @@ export default function SeerRepoTableHeader({
129134
<TableHeader>
130135
<TableCellFirst>
131136
<SelectAllCheckbox
132-
listItemCheckboxState={listItemCheckboxState}
133-
repositories={repositories}
134137
disabled={disabled}
138+
hits={hits}
139+
listItemCheckboxState={listItemCheckboxState}
135140
/>
136141
</TableCellFirst>
137142
<TableCellsRemainingContent align="center" gap="md">
@@ -181,8 +186,8 @@ export default function SeerRepoTableHeader({
181186
count: countSelected,
182187
queryString: <var>{queryString}</var>,
183188
})
184-
: countSelected > repositories.length
185-
? t('Selected all %s+ repositories.', repositories.length)
189+
: countSelected > hits
190+
? t('Selected all %s+ repositories.', hits)
186191
: tn(
187192
'Selected %s repository.',
188193
'Selected all %s repositories.',
@@ -198,20 +203,20 @@ export default function SeerRepoTableHeader({
198203

199204
function SelectAllCheckbox({
200205
listItemCheckboxState: {deselectAll, isAllSelected, selectedIds, selectAll},
201-
repositories,
206+
hits,
202207
disabled,
203208
}: {
204209
disabled: boolean;
210+
hits: number;
205211
listItemCheckboxState: ReturnType<typeof useListItemCheckboxContext>;
206-
repositories: RepositoryWithSettings[];
207212
}) {
208213
return (
209214
<Checkbox
210215
id="repository-table-select-all"
211216
checked={isAllSelected}
212-
disabled={repositories.length === 0 || disabled}
217+
disabled={hits === 0 || disabled}
213218
onChange={() => {
214-
if (isAllSelected === true || selectedIds.length === repositories.length) {
219+
if (isAllSelected === true || selectedIds.length === hits) {
215220
deselectAll();
216221
} else {
217222
selectAll();

0 commit comments

Comments
 (0)