|
| 1 | +import {useEffect, useState} from 'react'; |
| 2 | + |
| 3 | +import {Flex} from 'sentry/components/container/flex'; |
1 | 4 | import {Button} from 'sentry/components/core/button';
|
| 5 | +import {ButtonBar} from 'sentry/components/core/button/buttonBar'; |
| 6 | +import LoadingError from 'sentry/components/loadingError'; |
| 7 | +import LoadingIndicator from 'sentry/components/loadingIndicator'; |
2 | 8 | import {ActionCell} from 'sentry/components/workflowEngine/gridCell/actionCell';
|
3 | 9 | import AutomationTitleCell from 'sentry/components/workflowEngine/gridCell/automationTitleCell';
|
4 | 10 | import {TimeAgoCell} from 'sentry/components/workflowEngine/gridCell/timeAgoCell';
|
5 | 11 | import {defineColumns, SimpleTable} from 'sentry/components/workflowEngine/simpleTable';
|
| 12 | +import {IconChevron} from 'sentry/icons'; |
6 | 13 | import {t} from 'sentry/locale';
|
7 | 14 | import type {Automation} from 'sentry/types/workflowEngine/automations';
|
| 15 | +import type {Detector} from 'sentry/types/workflowEngine/detectors'; |
| 16 | +import {defined} from 'sentry/utils'; |
8 | 17 | import useOrganization from 'sentry/utils/useOrganization';
|
| 18 | +import {useDetectorQueriesByIds} from 'sentry/views/automations/hooks'; |
9 | 19 | import {useAutomationActions} from 'sentry/views/automations/hooks/utils';
|
10 | 20 | import {makeAutomationDetailsPathname} from 'sentry/views/automations/pathnames';
|
11 | 21 |
|
| 22 | +const AUTOMATIONS_PER_PAGE = 10; |
| 23 | + |
12 | 24 | type Props = {
|
13 |
| - automations: Automation[]; |
| 25 | + automationIds: Detector['workflowIds']; |
14 | 26 | connectedAutomationIds?: Set<string>;
|
15 | 27 | toggleConnected?: (id: string) => void;
|
16 | 28 | };
|
17 | 29 |
|
18 | 30 | export function ConnectedAutomationsList({
|
19 |
| - automations, |
| 31 | + automationIds, |
20 | 32 | connectedAutomationIds,
|
21 | 33 | toggleConnected,
|
22 | 34 | }: Props) {
|
23 | 35 | const organization = useOrganization();
|
24 | 36 | const canEdit = connectedAutomationIds && !!toggleConnected;
|
| 37 | + // TODO: There will eventually be a single api call to fetch a page of automations |
| 38 | + const queries = useDetectorQueriesByIds(automationIds); |
| 39 | + const [currentPage, setCurrentPage] = useState(0); |
| 40 | + const totalPages = Math.ceil(queries.length / AUTOMATIONS_PER_PAGE); |
| 41 | + |
| 42 | + // Reset the page when the automationIds change |
| 43 | + useEffect(() => { |
| 44 | + setCurrentPage(0); |
| 45 | + }, [automationIds]); |
| 46 | + |
| 47 | + const data = queries |
| 48 | + .map((query): ConnectedAutomationsData | undefined => { |
| 49 | + if (!query.data) { |
| 50 | + return undefined; |
| 51 | + } |
| 52 | + return { |
| 53 | + ...query.data, |
| 54 | + link: makeAutomationDetailsPathname(organization.slug, query.data.id), |
| 55 | + connected: canEdit |
| 56 | + ? { |
| 57 | + isConnected: connectedAutomationIds?.has(query.data.id), |
| 58 | + toggleConnected: () => toggleConnected?.(query.data.id), |
| 59 | + } |
| 60 | + : undefined, |
| 61 | + }; |
| 62 | + }) |
| 63 | + .filter(defined); |
| 64 | + |
| 65 | + const isLoading = queries.some(query => query.isPending); |
| 66 | + const isError = queries.some(query => query.isError); |
| 67 | + |
| 68 | + if (isError) { |
| 69 | + return <LoadingError />; |
| 70 | + } |
25 | 71 |
|
26 |
| - const data = automations.map(automation => ({ |
27 |
| - ...automation, |
28 |
| - link: makeAutomationDetailsPathname(organization.slug, automation.id), |
29 |
| - connected: canEdit |
30 |
| - ? { |
31 |
| - isConnected: connectedAutomationIds?.has(automation.id), |
32 |
| - toggleConnected: () => toggleConnected?.(automation.id), |
33 |
| - } |
34 |
| - : undefined, |
35 |
| - })); |
| 72 | + if (isLoading) { |
| 73 | + return <LoadingIndicator />; |
| 74 | + } |
| 75 | + |
| 76 | + const handlePreviousPage = () => { |
| 77 | + setCurrentPage(prev => Math.max(0, prev - 1)); |
| 78 | + }; |
| 79 | + const handleNextPage = () => { |
| 80 | + setCurrentPage(prev => Math.min(totalPages - 1, prev + 1)); |
| 81 | + }; |
| 82 | + |
| 83 | + const pagination = ( |
| 84 | + <Flex justify="flex-end"> |
| 85 | + <ButtonBar merged> |
| 86 | + <Button |
| 87 | + onClick={handlePreviousPage} |
| 88 | + disabled={currentPage === 0} |
| 89 | + aria-label={t('Previous page')} |
| 90 | + icon={<IconChevron direction="left" />} |
| 91 | + size="sm" |
| 92 | + /> |
| 93 | + <Button |
| 94 | + onClick={handleNextPage} |
| 95 | + disabled={currentPage === totalPages - 1} |
| 96 | + aria-label={t('Next page')} |
| 97 | + icon={<IconChevron direction="right" />} |
| 98 | + size="sm" |
| 99 | + /> |
| 100 | + </ButtonBar> |
| 101 | + </Flex> |
| 102 | + ); |
36 | 103 |
|
37 | 104 | if (canEdit) {
|
38 |
| - return <SimpleTable columns={connectedColumns} data={data} />; |
| 105 | + return ( |
| 106 | + <Flex column> |
| 107 | + <SimpleTable columns={connectedColumns} data={data} /> |
| 108 | + {pagination} |
| 109 | + </Flex> |
| 110 | + ); |
39 | 111 | }
|
40 | 112 |
|
41 | 113 | return (
|
42 |
| - <SimpleTable |
43 |
| - columns={baseColumns} |
44 |
| - data={data} |
45 |
| - fallback={t('No automations connected')} |
46 |
| - /> |
| 114 | + <Flex column> |
| 115 | + <SimpleTable |
| 116 | + columns={baseColumns} |
| 117 | + data={data} |
| 118 | + fallback={t('No automations connected')} |
| 119 | + /> |
| 120 | + {pagination} |
| 121 | + </Flex> |
47 | 122 | );
|
48 | 123 | }
|
49 | 124 |
|
|
0 commit comments