import {Component} from 'react';
import type {RouteComponentProps} from 'react-router';
import * as Sentry from '@sentry/react';
import {addErrorMessage} from 'sentry/actionCreators/indicator';
import type {Client} from 'sentry/api';
import {LinkButton} from 'sentry/components/button';
import EmptyMessage from 'sentry/components/emptyMessage';
import {Body, Main} from 'sentry/components/layouts/thirds';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Panel from 'sentry/components/panels/panel';
import {IconCommit} from 'sentry/icons';
import {t} from 'sentry/locale';
import type {Repository} from 'sentry/types/integrations';
import type {Organization} from 'sentry/types/organization';
import getDisplayName from 'sentry/utils/getDisplayName';
import withApi from 'sentry/utils/withApi';
import withOrganization from 'sentry/utils/withOrganization';
import withRepositories from 'sentry/utils/withRepositories';
import {ReleaseContext} from '..';
// These props are required when using this HoC
type DependentProps = RouteComponentProps<{release: string}, {}>;
type HoCsProps = {
api: Client;
organization: Organization;
repositories?: Repository[];
repositoriesError?: Error;
repositoriesLoading?: boolean;
};
type State = {
isLoading: boolean;
releaseRepos: Repository[];
activeReleaseRepo?: Repository;
};
function withReleaseRepos
(
WrappedComponent: React.ComponentType
) {
class WithReleaseRepos extends Component
{
static displayName = `withReleaseRepos(${getDisplayName(WrappedComponent)})`;
state: State = {
releaseRepos: [],
isLoading: true,
};
componentDidMount() {
this.fetchReleaseRepos();
}
componentDidUpdate(prevProps: P & HoCsProps, prevState: State) {
if (
this.props.params.release !== prevProps.params.release ||
(!!prevProps.repositoriesLoading && !this.props.repositoriesLoading)
) {
this.fetchReleaseRepos();
return;
}
if (
prevState.releaseRepos.length !== this.state.releaseRepos.length ||
prevProps.location.query?.activeRepo !== this.props.location.query?.activeRepo
) {
this.setActiveReleaseRepo(this.props);
}
}
declare context: React.ContextType;
static contextType = ReleaseContext;
setActiveReleaseRepo(props: P & HoCsProps) {
const {releaseRepos, activeReleaseRepo} = this.state;
if (!releaseRepos.length) {
return;
}
const activeCommitRepo = props.location.query?.activeRepo;
if (!activeCommitRepo) {
this.setState({
activeReleaseRepo: releaseRepos[0] ?? null,
});
return;
}
if (activeCommitRepo === activeReleaseRepo?.name) {
return;
}
const matchedRepository = releaseRepos.find(
commitRepo => commitRepo.name === activeCommitRepo
);
if (matchedRepository) {
this.setState({
activeReleaseRepo: matchedRepository,
});
return;
}
addErrorMessage(t('The repository you were looking for was not found.'));
}
async fetchReleaseRepos() {
const {params, api, organization, repositories, repositoriesLoading} = this.props;
if (repositoriesLoading === undefined || repositoriesLoading === true) {
return;
}
if (!repositories?.length) {
this.setState({isLoading: false});
return;
}
const {release} = params;
const {project} = this.context;
this.setState({isLoading: true});
try {
const releasePath = encodeURIComponent(release);
const releaseRepos = await api.requestPromise(
`/projects/${organization.slug}/${project.slug}/releases/${releasePath}/repositories/`
);
this.setState({releaseRepos, isLoading: false});
this.setActiveReleaseRepo(this.props);
} catch (error) {
Sentry.captureException(error);
addErrorMessage(
t(
'An error occurred while trying to fetch the repositories of the release: %s',
release
)
);
}
}
render() {
const {isLoading, activeReleaseRepo, releaseRepos} = this.state;
const {repositoriesLoading, repositories, params, router, location, organization} =
this.props;
if (isLoading || repositoriesLoading) {
return ;
}
const noRepositoryOrgRelatedFound = !repositories?.length;
if (noRepositoryOrgRelatedFound) {
return (
}
title={t('Releases are better with commit data!')}
description={t(
'Connect a repository to see commit info, files changed, and authors involved in future releases.'
)}
action={
{t('Connect a repository')}
}
/>
);
}
const noReleaseReposFound = !releaseRepos.length;
if (noReleaseReposFound) {
return (
}
title={t('Releases are better with commit data!')}
description={t(
'No commits associated with this release have been found.'
)}
/>
);
}
if (activeReleaseRepo === undefined) {
return ;
}
const {release} = params;
const orgSlug = organization.slug;
return (
);
}
}
return withApi(withOrganization(withRepositories(WithReleaseRepos)));
}
export default withReleaseRepos;