123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- import {Fragment, useCallback, useEffect, useMemo, useState} from 'react';
- // eslint-disable-next-line no-restricted-imports
- import {withRouter, WithRouterProps} from 'react-router';
- import CompactIssue from 'sentry/components/issues/compactIssue';
- import LoadingError from 'sentry/components/loadingError';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import Pagination from 'sentry/components/pagination';
- import {Panel, PanelBody} from 'sentry/components/panels';
- import {IconSearch} from 'sentry/icons';
- import {t} from 'sentry/locale';
- import space from 'sentry/styles/space';
- import {Group} from 'sentry/types';
- import useApi from 'sentry/utils/useApi';
- import EmptyMessage from 'sentry/views/settings/components/emptyMessage';
- interface IssueListProps extends WithRouterProps {
- endpoint: string;
- emptyText?: string;
- noBorder?: boolean;
- noMargin?: boolean;
- pagination?: boolean;
- query?: Record<string, any>;
- renderEmpty?: () => React.ReactElement;
- }
- interface IssueListState {
- data: Array<Group>;
- issueIds: Array<string>;
- pageLinks: string | null;
- status: 'loading' | 'error' | 'success';
- }
- function IssueList({
- endpoint,
- emptyText,
- query,
- location,
- pagination,
- renderEmpty,
- noBorder,
- noMargin,
- }: IssueListProps): React.ReactElement {
- const api = useApi();
- const [state, setState] = useState<IssueListState>({
- issueIds: [],
- status: 'loading',
- pageLinks: null,
- data: [],
- });
- const fetchIssueListData = useCallback(() => {
- api.clear();
- api.request(endpoint, {
- method: 'GET',
- query: {
- ...query,
- ...(location?.query?.cursor ? {cursor: location.query.cursor} : {}),
- },
- success: (data, _, resp) => {
- setState({
- data,
- status: 'success',
- issueIds: data.map(item => item.id),
- pageLinks: resp?.getResponseHeader('Link') ?? null,
- });
- },
- error: () => {
- setState(prevState => ({...prevState, status: 'error'}));
- },
- });
- }, [query, endpoint, location.query, api]);
- // TODO: location should always be passed as a prop, check why we have this
- const hasLocation = !!location;
- useEffect(() => {
- if (!hasLocation) {
- return;
- }
- setState({issueIds: [], status: 'loading', pageLinks: null, data: []});
- fetchIssueListData();
- }, [fetchIssueListData, hasLocation]);
- const panelStyles = useMemo(() => {
- const styles: React.CSSProperties = {
- ...(noBorder ? {border: 0, borderRadius: 0} : {}),
- ...(noMargin ? {marginBottom: 0} : {}),
- };
- return styles;
- }, [noBorder, noMargin]);
- return (
- <Fragment>
- {state.status === 'loading' ? (
- <div style={{margin: '18px 18px 0'}}>
- <LoadingIndicator />
- </div>
- ) : state.status === 'error' ? (
- <div style={{margin: `${space(2)} ${space(2)} 0`}}>
- <LoadingError onRetry={fetchIssueListData} />
- </div>
- ) : state.issueIds.length > 0 ? (
- <Panel style={panelStyles}>
- <PanelBody className="issue-list">
- {state.data.map(issue => (
- <CompactIssue key={issue.id} id={issue.id} data={issue} />
- ))}
- </PanelBody>
- </Panel>
- ) : renderEmpty ? (
- renderEmpty()
- ) : (
- <Panel style={panelStyles}>
- <EmptyMessage icon={<IconSearch size="xl" />}>
- {emptyText ?? t('Nothing to show here, move along.')}
- </EmptyMessage>
- </Panel>
- )}
- {pagination && state.pageLinks && <Pagination pageLinks={state.pageLinks} />}
- </Fragment>
- );
- }
- export {IssueList};
- export default withRouter(IssueList);
|