|
@@ -13,6 +13,7 @@ import Feature from 'app/components/acl/feature';
|
|
|
import GlobalSelectionHeader from 'app/components/organizations/globalSelectionHeader';
|
|
|
import AsyncView from 'app/views/asyncView';
|
|
|
import withOrganization from 'app/utils/withOrganization';
|
|
|
+import withGlobalSelection from 'app/utils/withGlobalSelection';
|
|
|
|
|
|
import {PageContent, PageHeader} from 'app/styles/organization';
|
|
|
import PageHeading from 'app/components/pageHeading';
|
|
@@ -20,11 +21,13 @@ import PageHeading from 'app/components/pageHeading';
|
|
|
import ReleaseList from '../shared/releaseList';
|
|
|
import ReleaseListHeader from '../shared/releaseListHeader';
|
|
|
import ReleaseLanding from '../shared/releaseLanding';
|
|
|
+import ReleaseProgress from '../shared/releaseProgress';
|
|
|
import {getQuery} from '../shared/utils';
|
|
|
|
|
|
class OrganizationReleasesContainer extends React.Component {
|
|
|
static propTypes = {
|
|
|
- organization: SentryTypes.Organization,
|
|
|
+ organization: SentryTypes.Organization.isRequired,
|
|
|
+ selection: SentryTypes.GlobalSelection.isRequired,
|
|
|
};
|
|
|
|
|
|
renderNoAccess() {
|
|
@@ -81,19 +84,14 @@ class OrganizationReleases extends AsyncView {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- hasFilters() {
|
|
|
- const {location} = this.props;
|
|
|
-
|
|
|
- const hasQueryFilter = !!location.query.query;
|
|
|
- const hasEnvironmentFilter = !!location.query.environment;
|
|
|
-
|
|
|
- // If all or one project is selected show the setup screen
|
|
|
- // We check the type since a single project value is represented as a
|
|
|
- // string when deserialized and multiple values as an array.
|
|
|
- const hasProjectFilter =
|
|
|
- !location.query.project || Array.isArray(location.query.project);
|
|
|
-
|
|
|
- return hasQueryFilter || hasProjectFilter || hasEnvironmentFilter;
|
|
|
+ // Returns true if there has been a release in any selected project, otherwise false
|
|
|
+ hasAnyRelease() {
|
|
|
+ const {organization: {projects}, selection} = this.props;
|
|
|
+ const projectIds = new Set(selection.projects);
|
|
|
+ const activeProjects = projects.filter(project =>
|
|
|
+ projectIds.has(parseInt(project.id, 10))
|
|
|
+ );
|
|
|
+ return activeProjects.some(project => !!project.latestRelease);
|
|
|
}
|
|
|
|
|
|
renderStreamBody() {
|
|
@@ -105,21 +103,52 @@ class OrganizationReleases extends AsyncView {
|
|
|
}
|
|
|
|
|
|
if (releaseList.length === 0) {
|
|
|
- return this.hasFilters() ? this.renderNoQueryResults() : this.renderEmpty();
|
|
|
+ return this.hasAnyRelease() ? this.renderNoQueryResults() : this.renderLanding();
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <React.Fragment>
|
|
|
+ {this.renderReleaseProgress()}
|
|
|
+ <ReleaseList releaseList={releaseList} orgId={organization.slug} />
|
|
|
+ </React.Fragment>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ renderReleaseProgress() {
|
|
|
+ const {organization, selection} = this.props;
|
|
|
+ const allAccessibleProjects = organization.projects.filter(
|
|
|
+ project => project.isMember
|
|
|
+ );
|
|
|
+
|
|
|
+ const hasSingleProject =
|
|
|
+ selection.projects.length === 1 ||
|
|
|
+ (selection.projects === 0 && allAccessibleProjects.length === 1);
|
|
|
+
|
|
|
+ if (!hasSingleProject) {
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
- return <ReleaseList releaseList={releaseList} orgId={organization.slug} />;
|
|
|
+ const releaseProject = selection.projects.length
|
|
|
+ ? allAccessibleProjects.find(
|
|
|
+ project => parseInt(project.id, 10) === selection.projects[0]
|
|
|
+ )
|
|
|
+ : allAccessibleProjects[0];
|
|
|
+
|
|
|
+ return <ReleaseProgress project={releaseProject} />;
|
|
|
}
|
|
|
|
|
|
renderNoQueryResults() {
|
|
|
return (
|
|
|
- <EmptyStateWarning>
|
|
|
- <p>{t('Sorry, no releases match your filters.')}</p>
|
|
|
- </EmptyStateWarning>
|
|
|
+ <React.Fragment>
|
|
|
+ {this.renderReleaseProgress()}
|
|
|
+ <EmptyStateWarning>
|
|
|
+ <p>{t('Sorry, no releases match your filters.')}</p>
|
|
|
+ </EmptyStateWarning>
|
|
|
+ </React.Fragment>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- renderEmpty() {
|
|
|
+ renderLanding() {
|
|
|
return <ReleaseLanding />;
|
|
|
}
|
|
|
|
|
@@ -155,4 +184,4 @@ class OrganizationReleases extends AsyncView {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export default withOrganization(OrganizationReleasesContainer);
|
|
|
+export default withOrganization(withGlobalSelection(OrganizationReleasesContainer));
|