Browse Source

fix(workflow): Show correct empty message when no releases (#33819)

* fix(workflow): Show correct empty message when no releases

Show the correct empty message when there are no releases based on if you have releases set up for the project.

FIXES WOR-1807

* update to use EmptyMessage component to match other empty state pages

* update tests
Kelly Carino 2 years ago
parent
commit
27ca424356

+ 62 - 33
static/app/views/releases/list/index.tsx

@@ -8,7 +8,6 @@ import {fetchTagValues} from 'sentry/actionCreators/tags';
 import Alert from 'sentry/components/alert';
 import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import DatePageFilter from 'sentry/components/datePageFilter';
-import EmptyStateWarning from 'sentry/components/emptyStateWarning';
 import EnvironmentPageFilter from 'sentry/components/environmentPageFilter';
 import ExternalLink from 'sentry/components/links/externalLink';
 import LoadingIndicator from 'sentry/components/loadingIndicator';
@@ -18,12 +17,14 @@ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/co
 import {getRelativeSummary} from 'sentry/components/organizations/timeRangeSelector/utils';
 import PageHeading from 'sentry/components/pageHeading';
 import Pagination from 'sentry/components/pagination';
+import {Panel} from 'sentry/components/panels';
 import ProjectPageFilter from 'sentry/components/projectPageFilter';
 import SmartSearchBar from 'sentry/components/smartSearchBar';
 import {ItemType} from 'sentry/components/smartSearchBar/types';
 import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
 import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
 import {releaseHealth} from 'sentry/data/platformCategories';
+import {IconSearch} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import ProjectsStore from 'sentry/stores/projectsStore';
 import {PageContent, PageHeader} from 'sentry/styles/organization';
@@ -44,6 +45,7 @@ import withOrganization from 'sentry/utils/withOrganization';
 import withPageFilters from 'sentry/utils/withPageFilters';
 import withProjects from 'sentry/utils/withProjects';
 import AsyncView from 'sentry/views/asyncView';
+import EmptyMessage from 'sentry/views/settings/components/emptyMessage';
 
 import ReleaseArchivedNotice from '../detail/overview/releaseArchivedNotice';
 import {isMobileRelease} from '../utils';
@@ -292,35 +294,48 @@ class ReleasesList extends AsyncView<Props, State> {
   }
 
   renderEmptyMessage() {
-    const {location, organization, selection} = this.props;
-    const {statsPeriod} = location.query;
+    const {location} = this.props;
+    const {statsPeriod, start, end} = location.query;
     const searchQuery = this.getQuery();
     const activeSort = this.getSort();
     const activeStatus = this.getStatus();
 
+    const selectedPeriod =
+      !!start && !!end
+        ? t('time range')
+        : getRelativeSummary(statsPeriod || DEFAULT_STATS_PERIOD).toLowerCase();
+
     if (searchQuery && searchQuery.length) {
       return (
-        <EmptyStateWarning small>{`${t(
-          'There are no releases that match'
-        )}: '${searchQuery}'.`}</EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">{`${t(
+            'There are no releases that match'
+          )}: '${searchQuery}'.`}</EmptyMessage>
+        </Panel>
       );
     }
 
     if (activeSort === ReleasesSortOption.USERS_24_HOURS) {
       return (
-        <EmptyStateWarning small>
-          {t('There are no releases with active user data (users in the last 24 hours).')}
-        </EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+            {t(
+              'There are no releases with active user data (users in the last 24 hours).'
+            )}
+          </EmptyMessage>
+        </Panel>
       );
     }
 
     if (activeSort === ReleasesSortOption.SESSIONS_24_HOURS) {
       return (
-        <EmptyStateWarning small>
-          {t(
-            'There are no releases with active session data (sessions in the last 24 hours).'
-          )}
-        </EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+            {t(
+              'There are no releases with active session data (sessions in the last 24 hours).'
+            )}
+          </EmptyMessage>
+        </Panel>
       );
     }
 
@@ -329,37 +344,40 @@ class ReleasesList extends AsyncView<Props, State> {
       activeSort === ReleasesSortOption.SEMVER
     ) {
       return (
-        <EmptyStateWarning small>
-          {t('There are no releases with semantic versioning.')}
-        </EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+            {t('There are no releases with semantic versioning.')}
+          </EmptyMessage>
+        </Panel>
       );
     }
 
     if (activeSort !== ReleasesSortOption.DATE) {
-      const relativePeriod = getRelativeSummary(
-        statsPeriod || DEFAULT_STATS_PERIOD
-      ).toLowerCase();
-
       return (
-        <EmptyStateWarning small>
-          {`${t('There are no releases with data in the')} ${relativePeriod}.`}
-        </EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+            {`${t('There are no releases with data in the')} ${selectedPeriod}.`}
+          </EmptyMessage>
+        </Panel>
       );
     }
 
     if (activeStatus === ReleasesStatusOption.ARCHIVED) {
       return (
-        <EmptyStateWarning small>
-          {t('There are no archived releases.')}
-        </EmptyStateWarning>
+        <Panel>
+          <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+            {t('There are no archived releases.')}
+          </EmptyMessage>
+        </Panel>
       );
     }
 
     return (
-      <ReleasesPromo
-        organization={organization}
-        projectId={selection.projects.filter(p => p !== ALL_ACCESS_PROJECTS)[0]}
-      />
+      <Panel>
+        <EmptyMessage icon={<IconSearch size="xl" />} size="large">
+          {`${t('There are no releases with data in the')} ${selectedPeriod}.`}
+        </EmptyMessage>
+      </Panel>
     );
   }
 
@@ -413,14 +431,26 @@ class ReleasesList extends AsyncView<Props, State> {
     const {location, selection, organization, router} = this.props;
     const {releases, reloading, releasesPageLinks} = this.state;
 
+    const selectedProject = this.getSelectedProject();
+    const hasReleasesSetup = selectedProject?.features.includes('releases');
+
     if (this.shouldShowLoadingIndicator()) {
       return <LoadingIndicator />;
     }
 
-    if (!releases?.length) {
+    if (!releases?.length && hasReleasesSetup) {
       return this.renderEmptyMessage();
     }
 
+    if (!releases?.length && !hasReleasesSetup) {
+      return (
+        <ReleasesPromo
+          organization={organization}
+          projectId={selection.projects.filter(p => p !== ALL_ACCESS_PROJECTS)[0]}
+        />
+      );
+    }
+
     return (
       <ReleasesRequest
         releases={releases.map(({version}) => version)}
@@ -435,7 +465,6 @@ class ReleasesList extends AsyncView<Props, State> {
           const singleProjectSelected =
             selection.projects?.length === 1 &&
             selection.projects[0] !== ALL_ACCESS_PROJECTS;
-          const selectedProject = this.getSelectedProject();
           const isMobileProject =
             selectedProject?.platform && isMobileRelease(selectedProject.platform);
 

+ 56 - 15
tests/js/spec/views/releases/list/index.spec.jsx

@@ -102,11 +102,21 @@ describe('ReleasesList', function () {
 
   it('displays the right empty state', function () {
     let location;
+    const project = TestStubs.Project({
+      id: '3',
+      slug: 'test-slug',
+      name: 'test-name',
+      features: ['releases'],
+    });
+    const org = TestStubs.Organization({projects: [project]});
+    ProjectsStore.loadInitialData(org.projects);
+
     MockApiClient.addMockResponse({
       url: '/organizations/org-slug/releases/',
       body: [],
     });
 
+    // does not have releases set up and no releases
     location = {query: {}};
     wrapper = createWrapper(
       <ReleasesList {...props} location={location} />,
@@ -123,48 +133,79 @@ describe('ReleasesList', function () {
     expect(wrapper.find('StyledPanel')).toHaveLength(0);
     expect(wrapper.find('ReleasesPromo').text()).toContain('Demystify Releases');
 
+    MockApiClient.addMockResponse({
+      url: `/organizations/${org.slug}/releases/`,
+      body: [],
+    });
+
+    // has releases set up and no releases
     location = {query: {query: 'abc'}};
-    wrapper = createWrapper(
-      <ReleasesList {...props} location={location} />,
+    let container = createWrapper(
+      <ReleasesList
+        {...props}
+        organization={org}
+        location={location}
+        selection={{...props.selection, projects: [3]}}
+      />,
       routerContext
     );
-    expect(wrapper.find('EmptyMessage').text()).toEqual(
+    expect(container.find('EmptyMessage').text()).toEqual(
       "There are no releases that match: 'abc'."
     );
 
     location = {query: {sort: ReleasesSortOption.SESSIONS, statsPeriod: '7d'}};
-    wrapper = createWrapper(
-      <ReleasesList {...props} location={location} />,
+    container = createWrapper(
+      <ReleasesList
+        {...props}
+        organization={org}
+        location={location}
+        selection={{...props.selection, projects: [3]}}
+      />,
       routerContext
     );
-    expect(wrapper.find('EmptyMessage').text()).toEqual(
+    expect(container.find('EmptyMessage').text()).toEqual(
       'There are no releases with data in the last 7 days.'
     );
 
     location = {query: {sort: ReleasesSortOption.USERS_24_HOURS, statsPeriod: '7d'}};
-    wrapper = createWrapper(
-      <ReleasesList {...props} location={location} />,
+    container = createWrapper(
+      <ReleasesList
+        {...props}
+        organization={org}
+        location={location}
+        selection={{...props.selection, projects: [3]}}
+      />,
       routerContext
     );
-    expect(wrapper.find('EmptyMessage').text()).toEqual(
+    expect(container.find('EmptyMessage').text()).toEqual(
       'There are no releases with active user data (users in the last 24 hours).'
     );
 
     location = {query: {sort: ReleasesSortOption.SESSIONS_24_HOURS, statsPeriod: '7d'}};
-    wrapper = createWrapper(
-      <ReleasesList {...props} location={location} />,
+    container = createWrapper(
+      <ReleasesList
+        {...props}
+        organization={org}
+        location={location}
+        selection={{...props.selection, projects: [3]}}
+      />,
       routerContext
     );
-    expect(wrapper.find('EmptyMessage').text()).toEqual(
+    expect(container.find('EmptyMessage').text()).toEqual(
       'There are no releases with active session data (sessions in the last 24 hours).'
     );
 
     location = {query: {sort: ReleasesSortOption.BUILD}};
-    wrapper = createWrapper(
-      <ReleasesList {...props} location={location} />,
+    container = createWrapper(
+      <ReleasesList
+        {...props}
+        organization={org}
+        location={location}
+        selection={{...props.selection, projects: [3]}}
+      />,
       routerContext
     );
-    expect(wrapper.find('EmptyMessage').text()).toEqual(
+    expect(container.find('EmptyMessage').text()).toEqual(
       'There are no releases with semantic versioning.'
     );
   });