Browse Source

feat(issues): GA issue actions v2, remove old share button (#43808)

Scott Cooper 2 years ago
parent
commit
9fda8fe013

+ 0 - 66
docs-ui/stories/features/shareIssue.stories.js

@@ -1,66 +0,0 @@
-import {Component} from 'react';
-import {action} from '@storybook/addon-actions';
-
-import ShareIssue from 'sentry/views/issueDetails/actions/shareIssue';
-
-export default {
-  title: 'Features/Issues/Share Issue',
-  component: ShareIssue,
-  args: {
-    shareUrl: 'https://sentry.io/share/issue/thisisanexampleshareurl/',
-  },
-  argTypes: {
-    onReshare: {action: 'onReshare'},
-    loading: {
-      table: {
-        disable: true,
-      },
-    },
-    onToggle: {
-      table: {
-        disable: true,
-      },
-    },
-    isShared: {
-      table: {
-        disable: true,
-      },
-    },
-  },
-};
-
-class ShareSimulator extends Component {
-  state = {isShared: false, loading: false};
-  toggleAction = action('Toggle');
-
-  toggleShare() {
-    this.toggleAction();
-    this.setState({loading: true});
-
-    // Simulate loading
-    setTimeout(() => {
-      this.setState(state => ({loading: false, isShared: !state.isShared}));
-    }, 1000);
-  }
-
-  render() {
-    return this.props.children({...this.state, toggleShare: () => this.toggleShare()});
-  }
-}
-
-export const Default = ({...args}) => {
-  return (
-    <ShareSimulator>
-      {({isShared, loading, toggleShare}) => (
-        <ShareIssue
-          loading={loading}
-          isShared={isShared}
-          onToggle={toggleShare}
-          {...args}
-        />
-      )}
-    </ShareSimulator>
-  );
-};
-
-Default.storyName = 'Share Issue';

+ 2 - 3
static/app/components/group/sidebar.spec.jsx

@@ -193,7 +193,6 @@ describe('GroupSidebar', function () {
         email: 'sohnjmith@example.com',
       }),
     ];
-    const org = {...organization, features: ['issue-actions-v2']};
     render(
       <GroupSidebar
         group={{
@@ -202,11 +201,11 @@ describe('GroupSidebar', function () {
           seenBy: users,
         }}
         project={project}
-        organization={org}
+        organization={organization}
         event={TestStubs.Event()}
         environments={[]}
       />,
-      {organization: org}
+      {organization}
     );
     await act(tick);
 

+ 1 - 13
static/app/components/group/sidebar.tsx

@@ -6,7 +6,6 @@ import isObject from 'lodash/isObject';
 import {Client} from 'sentry/api';
 import AvatarList from 'sentry/components/avatar/avatarList';
 import DateTime from 'sentry/components/dateTime';
-import EnvironmentPageFilter from 'sentry/components/environmentPageFilter';
 import ErrorBoundary from 'sentry/components/errorBoundary';
 import AssignedTo from 'sentry/components/group/assignedTo';
 import ExternalIssueList from 'sentry/components/group/externalIssuesList';
@@ -209,19 +208,12 @@ class BaseGroupSidebar extends Component<Props, State> {
   render() {
     const {event, group, organization, project, environments} = this.props;
     const {allEnvironmentsGroupData, currentRelease} = this.state;
-    const hasIssueActionsV2 = organization.features.includes('issue-actions-v2');
     const hasStreamlineTargetingFeature = organization.features.includes(
       'streamline-targeting-context'
     );
 
     return (
       <Container>
-        {!hasIssueActionsV2 && (
-          <PageFiltersContainer>
-            <EnvironmentPageFilter alignDropdown="right" />
-          </PageFiltersContainer>
-        )}
-
         {!hasStreamlineTargetingFeature && (
           <OwnedBy group={group} project={project} organization={organization} />
         )}
@@ -284,16 +276,12 @@ class BaseGroupSidebar extends Component<Props, State> {
         />
 
         {this.renderParticipantData()}
-        {hasIssueActionsV2 && this.renderSeenByList()}
+        {this.renderSeenByList()}
       </Container>
     );
   }
 }
 
-const PageFiltersContainer = styled('div')`
-  margin-bottom: ${space(2)};
-`;
-
 const Container = styled('div')`
   font-size: ${p => p.theme.fontSizeMedium};
 `;

+ 96 - 100
static/app/views/issueDetails/actions/index.spec.tsx

@@ -39,6 +39,7 @@ describe('GroupActions', function () {
   beforeEach(function () {
     ConfigStore.init();
     jest.spyOn(ConfigStore, 'get').mockImplementation(() => []);
+    MockApiClient.clearMockResponses();
   });
 
   describe('render()', function () {
@@ -168,126 +169,121 @@ describe('GroupActions', function () {
     });
   });
 
-  describe('issue-actions-v2', () => {
+  it('opens share modal from more actions dropdown', async () => {
     const org = {
       ...organization,
-      features: ['issue-actions-v2', 'shared-issues'],
-      access: [...organization.access, 'event:admin'],
+      features: ['shared-issues'],
     };
 
-    beforeEach(() => {
-      MockApiClient.clearMockResponses();
-    });
-
-    it('opens share modal from more actions dropdown', async () => {
-      const updateMock = MockApiClient.addMockResponse({
-        url: `/projects/${org.slug}/${project.slug}/issues/`,
-        method: 'PUT',
-        body: {},
-      });
-      render(
-        <Fragment>
-          <GlobalModal />
-          <GroupActions
-            group={group}
-            project={project}
-            organization={org}
-            disabled={false}
-          />
-        </Fragment>,
-        {organization: org}
-      );
-
-      userEvent.click(screen.getByLabelText('More Actions'));
-      userEvent.click(await screen.findByText('Share'));
-
-      const modal = screen.getByRole('dialog');
-      expect(within(modal).getByText('Share Issue')).toBeInTheDocument();
-      expect(updateMock).toHaveBeenCalled();
-    });
-
-    it('opens delete confirm modal from more actions dropdown', async () => {
-      MockApiClient.addMockResponse({
-        url: `/projects/${org.slug}/${project.slug}/issues/`,
-        method: 'PUT',
-        body: {},
-      });
-      const deleteMock = MockApiClient.addMockResponse({
-        url: `/projects/${org.slug}/${project.slug}/issues/`,
-        method: 'DELETE',
-        body: {},
-      });
-      render(
-        <Fragment>
-          <GlobalModal />
-          <GroupActions
-            group={group}
-            project={project}
-            organization={org}
-            disabled={false}
-          />
-        </Fragment>,
-        {organization: org}
-      );
-
-      userEvent.click(screen.getByLabelText('More Actions'));
-      userEvent.click(await screen.findByTestId('delete-issue'));
-
-      const modal = screen.getByRole('dialog');
-      expect(
-        within(modal).getByText(/Deleting this issue is permanent/)
-      ).toBeInTheDocument();
-
-      userEvent.click(within(modal).getByRole('button', {name: 'Delete'}));
-
-      expect(deleteMock).toHaveBeenCalled();
-      expect(browserHistory.push).toHaveBeenCalledWith({
-        pathname: `/organizations/${org.slug}/issues/`,
-        query: {project: project.id},
-      });
+    const updateMock = MockApiClient.addMockResponse({
+      url: `/projects/${org.slug}/${project.slug}/issues/`,
+      method: 'PUT',
+      body: {},
     });
-
-    it('resolves and unresolves issue', () => {
-      const issuesApi = MockApiClient.addMockResponse({
-        url: `/projects/${org.slug}/project/issues/`,
-        method: 'PUT',
-        body: {...group, status: 'resolved'},
-      });
-
-      const {rerender} = render(
+    render(
+      <Fragment>
+        <GlobalModal />
         <GroupActions
           group={group}
           project={project}
           organization={org}
           disabled={false}
-        />,
-        {organization: org}
-      );
+        />
+      </Fragment>,
+      {organization: org}
+    );
 
-      userEvent.click(screen.getByRole('button', {name: 'Resolve'}));
+    userEvent.click(screen.getByLabelText('More Actions'));
+    userEvent.click(await screen.findByText('Share'));
 
-      expect(issuesApi).toHaveBeenCalledWith(
-        `/projects/${org.slug}/project/issues/`,
-        expect.objectContaining({data: {status: 'resolved', statusDetails: {}}})
-      );
+    const modal = screen.getByRole('dialog');
+    expect(within(modal).getByText('Share Issue')).toBeInTheDocument();
+    expect(updateMock).toHaveBeenCalled();
+  });
 
-      rerender(
+  it('opens delete confirm modal from more actions dropdown', async () => {
+    const org = {
+      ...organization,
+      access: [...organization.access, 'event:admin'],
+    };
+    MockApiClient.addMockResponse({
+      url: `/projects/${org.slug}/${project.slug}/issues/`,
+      method: 'PUT',
+      body: {},
+    });
+    const deleteMock = MockApiClient.addMockResponse({
+      url: `/projects/${org.slug}/${project.slug}/issues/`,
+      method: 'DELETE',
+      body: {},
+    });
+    render(
+      <Fragment>
+        <GlobalModal />
         <GroupActions
-          group={{...group, status: 'resolved'}}
+          group={group}
           project={project}
           organization={org}
           disabled={false}
         />
-      );
+      </Fragment>,
+      {organization: org}
+    );
 
-      const resolvedButton = screen.getByRole('button', {name: 'Resolved'});
-      expect(resolvedButton).toBeInTheDocument();
-      userEvent.click(resolvedButton);
+    userEvent.click(screen.getByLabelText('More Actions'));
+    userEvent.click(await screen.findByRole('menuitemradio', {name: 'Delete'}));
 
-      expect(issuesApi).toHaveBeenCalledWith(
-        `/projects/${org.slug}/project/issues/`,
-        expect.objectContaining({data: {status: 'unresolved', statusDetails: {}}})
-      );
+    const modal = screen.getByRole('dialog');
+    expect(
+      within(modal).getByText(/Deleting this issue is permanent/)
+    ).toBeInTheDocument();
+
+    userEvent.click(within(modal).getByRole('button', {name: 'Delete'}));
+
+    expect(deleteMock).toHaveBeenCalled();
+    expect(browserHistory.push).toHaveBeenCalledWith({
+      pathname: `/organizations/${organization.slug}/issues/`,
+      query: {project: project.id},
+    });
+  });
+
+  it('resolves and unresolves issue', () => {
+    const issuesApi = MockApiClient.addMockResponse({
+      url: `/projects/${organization.slug}/project/issues/`,
+      method: 'PUT',
+      body: {...group, status: 'resolved'},
     });
+
+    const {rerender} = render(
+      <GroupActions
+        group={group}
+        project={project}
+        organization={organization}
+        disabled={false}
+      />,
+      {organization}
+    );
+
+    userEvent.click(screen.getByRole('button', {name: 'Resolve'}));
+
+    expect(issuesApi).toHaveBeenCalledWith(
+      `/projects/${organization.slug}/project/issues/`,
+      expect.objectContaining({data: {status: 'resolved', statusDetails: {}}})
+    );
+
+    rerender(
+      <GroupActions
+        group={{...group, status: 'resolved'}}
+        project={project}
+        organization={organization}
+        disabled={false}
+      />
+    );
+
+    userEvent.click(screen.getByRole('button', {name: 'Resolved'}));
+
+    expect(issuesApi).toHaveBeenCalledWith(
+      `/projects/${organization.slug}/project/issues/`,
+      expect.objectContaining({data: {status: 'unresolved', statusDetails: {}}})
+    );
   });
 });

+ 153 - 240
static/app/views/issueDetails/actions/index.tsx

@@ -18,7 +18,6 @@ import IgnoreActions, {getIgnoreActions} from 'sentry/components/actions/ignore'
 import ResolveActions from 'sentry/components/actions/resolve';
 import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import {Button} from 'sentry/components/button';
-import type {MenuItemProps} from 'sentry/components/dropdownMenu';
 import DropdownMenu from 'sentry/components/dropdownMenu';
 import EnvironmentPageFilter from 'sentry/components/environmentPageFilter';
 import {
@@ -51,8 +50,6 @@ import {uniqueId} from 'sentry/utils/guid';
 import withApi from 'sentry/utils/withApi';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import withOrganization from 'sentry/utils/withOrganization';
-import ShareIssue from 'sentry/views/issueDetails/actions/shareIssue';
-import ReviewAction from 'sentry/views/issueList/actions/reviewAction';
 
 import ShareIssueModal from './shareModal';
 import SubscribeAction from './subscribeAction';
@@ -361,264 +358,180 @@ class Actions extends Component<Props> {
     const shareCap = getIssueCapability(group.issueCategory, 'share');
 
     const hasDeleteAccess = organization.access.includes('event:admin');
-    const sharedMenuItems: MenuItemProps[] = [
-      {
-        key: bookmarkKey,
-        label: bookmarkTitle,
-        onAction: this.onToggleBookmark,
-      },
-      {
-        key: 'reprocess',
-        label: t('Reprocess events'),
-        hidden: !displayReprocessEventAction(organization.features, event),
-        onAction: this.onReprocessEvent,
-      },
-      {
-        key: 'delete-issue',
-        priority: 'danger',
-        label: t('Delete'),
-        hidden: !hasDeleteAccess,
-        disabled: !deleteCap.enabled,
-        details: deleteCap.disabledReason,
-        onAction: this.openDeleteModal,
-      },
-      {
-        key: 'delete-and-discard',
-        priority: 'danger',
-        label: t('Delete and discard future events'),
-        hidden: !hasDeleteAccess,
-        disabled: !deleteDiscardCap.enabled,
-        details: deleteDiscardCap.disabledReason,
-        onAction: this.openDiscardModal,
-      },
-    ];
-
-    if (orgFeatures.has('issue-actions-v2')) {
-      const {dropdownItems, onIgnore} = getIgnoreActions({onUpdate: this.onUpdate});
-      return (
-        <ActionWrapper>
-          <DropdownMenu
-            triggerProps={{
-              'aria-label': t('More Actions'),
-              icon: <IconEllipsis size="xs" />,
-              showChevron: false,
-              size: 'sm',
-            }}
-            items={[
-              ...(isIgnored
-                ? []
-                : [
-                    {
-                      key: 'ignore',
-                      className: 'hidden-sm hidden-md hidden-lg',
-                      label: t('Ignore'),
-                      isSubmenu: true,
-                      disabled,
-                      children: [
-                        {
-                          key: 'ignore-now',
-                          label: t('Ignore Issue'),
-                          onAction: () => onIgnore(),
-                        },
-                        ...dropdownItems,
-                      ],
-                    },
-                  ]),
-              {
-                key: 'open-in-discover',
-                className: 'hidden-sm hidden-md hidden-lg',
-                label: t('Open in Discover'),
-                to: disabled ? '' : this.getDiscoverUrl(),
-                onAction: () => this.trackIssueAction('open_in_discover'),
-              },
-              {
-                key: group.isSubscribed ? 'unsubscribe' : 'subscribe',
-                className: 'hidden-sm hidden-md hidden-lg',
-                label: group.isSubscribed ? t('Unsubscribe') : t('Subscribe'),
-                disabled: disabled || group.subscriptionDetails?.disabled,
-                onAction: this.onToggleSubscribe,
-              },
-              {
-                key: 'mark-review',
-                label: t('Mark reviewed'),
-                disabled: !group.inbox || disabled,
-                details:
-                  !group.inbox || disabled ? t('Issue has been reviewed') : undefined,
-                onAction: () => this.onUpdate({inbox: false}),
-              },
-              {
-                key: 'share',
-                label: t('Share'),
-                disabled: disabled || !shareCap.enabled,
-                hidden: !orgFeatures.has('shared-issues'),
-                onAction: this.openShareModal,
-              },
-              ...sharedMenuItems,
-            ]}
-          />
-          <SubscribeAction
-            className="hidden-xs"
-            disabled={disabled}
-            disablePriority
-            group={group}
-            onClick={this.handleClick(disabled, this.onToggleSubscribe)}
-            icon={group.isSubscribed ? <IconSubscribed /> : <IconUnsubscribed />}
-            size="sm"
-          />
-          <div className="hidden-xs">
-            <EnvironmentPageFilter alignDropdown="right" size="sm" />
-          </div>
-          <Feature
-            hookName="feature-disabled:open-in-discover"
-            features={['discover-basic']}
-            organization={organization}
-          >
-            <ActionButton
-              className="hidden-xs"
-              disabled={disabled}
-              to={disabled ? '' : this.getDiscoverUrl()}
-              onClick={() => this.trackIssueAction('open_in_discover')}
-              size="sm"
-            >
-              <GuideAnchor target="open_in_discover">{t('Open in Discover')}</GuideAnchor>
-            </ActionButton>
-          </Feature>
-          {isResolved || isIgnored ? (
-            <ActionButton
-              priority="primary"
-              title={
-                isAutoResolved
-                  ? t(
-                      'This event is resolved due to the Auto Resolve configuration for this project'
-                    )
-                  : t('Change status to unresolved')
-              }
-              size="sm"
-              icon={isResolved ? <IconCheckmark /> : <IconMute />}
-              disabled={disabled || isAutoResolved}
-              onClick={() =>
-                this.onUpdate({status: ResolutionStatus.UNRESOLVED, statusDetails: {}})
-              }
-            >
-              {isIgnored ? t('Ignored') : t('Resolved')}
-            </ActionButton>
-          ) : (
-            <Fragment>
-              <GuideAnchor target="ignore_delete_discard" position="bottom" offset={20}>
-                <IgnoreActions
-                  className="hidden-xs"
-                  isIgnored={isIgnored}
-                  onUpdate={this.onUpdate}
-                  disabled={disabled}
-                  size="sm"
-                  hideIcon
-                  disableTooltip
-                />
-              </GuideAnchor>
-              <GuideAnchor target="resolve" position="bottom" offset={20}>
-                <ResolveActions
-                  disableTooltip
-                  disabled={disabled}
-                  disableDropdown={disabled}
-                  hasRelease={hasRelease}
-                  latestRelease={project.latestRelease}
-                  onUpdate={this.onUpdate}
-                  orgSlug={organization.slug}
-                  projectSlug={project.slug}
-                  isResolved={isResolved}
-                  isAutoResolved={isAutoResolved}
-                  size="sm"
-                  hideIcon
-                  priority="primary"
-                />
-              </GuideAnchor>
-            </Fragment>
-          )}
-        </ActionWrapper>
-      );
-    }
 
+    const {dropdownItems, onIgnore} = getIgnoreActions({onUpdate: this.onUpdate});
     return (
-      <Wrapper>
-        <GuideAnchor target="resolve" position="bottom" offset={20}>
-          <ResolveActions
-            disabled={disabled}
-            disableDropdown={disabled}
-            hasRelease={hasRelease}
-            latestRelease={project.latestRelease}
-            onUpdate={this.onUpdate}
-            orgSlug={organization.slug}
-            projectSlug={project.slug}
-            isResolved={isResolved}
-            isAutoResolved={
-              group.status === 'resolved' ? group.statusDetails.autoResolved : undefined
-            }
-          />
-        </GuideAnchor>
-        <GuideAnchor target="ignore_delete_discard" position="bottom" offset={20}>
-          <IgnoreActions
-            isIgnored={isIgnored}
-            onUpdate={this.onUpdate}
-            disabled={disabled}
-          />
-        </GuideAnchor>
-        <ReviewAction
-          onUpdate={this.onUpdate}
-          disabled={!group.inbox || disabled}
-          tooltip={t('Issue has been reviewed')}
-          tooltipProps={{disabled: !!group.inbox || disabled, delay: 300}}
+      <ActionWrapper>
+        <DropdownMenu
+          triggerProps={{
+            'aria-label': t('More Actions'),
+            icon: <IconEllipsis size="xs" />,
+            showChevron: false,
+            size: 'sm',
+          }}
+          items={[
+            ...(isIgnored
+              ? []
+              : [
+                  {
+                    key: 'ignore',
+                    className: 'hidden-sm hidden-md hidden-lg',
+                    label: t('Ignore'),
+                    isSubmenu: true,
+                    disabled,
+                    children: [
+                      {
+                        key: 'ignore-now',
+                        label: t('Ignore Issue'),
+                        onAction: () => onIgnore(),
+                      },
+                      ...dropdownItems,
+                    ],
+                  },
+                ]),
+            {
+              key: 'open-in-discover',
+              className: 'hidden-sm hidden-md hidden-lg',
+              label: t('Open in Discover'),
+              to: disabled ? '' : this.getDiscoverUrl(),
+              onAction: () => this.trackIssueAction('open_in_discover'),
+            },
+            {
+              key: group.isSubscribed ? 'unsubscribe' : 'subscribe',
+              className: 'hidden-sm hidden-md hidden-lg',
+              label: group.isSubscribed ? t('Unsubscribe') : t('Subscribe'),
+              disabled: disabled || group.subscriptionDetails?.disabled,
+              onAction: this.onToggleSubscribe,
+            },
+            {
+              key: 'mark-review',
+              label: t('Mark reviewed'),
+              disabled: !group.inbox || disabled,
+              details:
+                !group.inbox || disabled ? t('Issue has been reviewed') : undefined,
+              onAction: () => this.onUpdate({inbox: false}),
+            },
+            {
+              key: 'share',
+              label: t('Share'),
+              disabled: disabled || !shareCap.enabled,
+              hidden: !orgFeatures.has('shared-issues'),
+              onAction: this.openShareModal,
+            },
+            {
+              key: bookmarkKey,
+              label: bookmarkTitle,
+              onAction: this.onToggleBookmark,
+            },
+            {
+              key: 'reprocess',
+              label: t('Reprocess events'),
+              hidden: !displayReprocessEventAction(organization.features, event),
+              onAction: this.onReprocessEvent,
+            },
+            {
+              key: 'delete-issue',
+              priority: 'danger',
+              label: t('Delete'),
+              hidden: !hasDeleteAccess,
+              disabled: !deleteCap.enabled,
+              details: deleteCap.disabledReason,
+              onAction: this.openDeleteModal,
+            },
+            {
+              key: 'delete-and-discard',
+              priority: 'danger',
+              label: t('Delete and discard future events'),
+              hidden: !hasDeleteAccess,
+              disabled: !deleteDiscardCap.enabled,
+              details: deleteDiscardCap.disabledReason,
+              onAction: this.openDiscardModal,
+            },
+          ]}
+        />
+        <SubscribeAction
+          className="hidden-xs"
+          disabled={disabled}
+          disablePriority
+          group={group}
+          onClick={this.handleClick(disabled, this.onToggleSubscribe)}
+          icon={group.isSubscribed ? <IconSubscribed /> : <IconUnsubscribed />}
+          size="sm"
         />
+        <div className="hidden-xs">
+          <EnvironmentPageFilter alignDropdown="right" size="sm" />
+        </div>
         <Feature
           hookName="feature-disabled:open-in-discover"
           features={['discover-basic']}
           organization={organization}
         >
           <ActionButton
+            className="hidden-xs"
             disabled={disabled}
             to={disabled ? '' : this.getDiscoverUrl()}
             onClick={() => this.trackIssueAction('open_in_discover')}
+            size="sm"
           >
             <GuideAnchor target="open_in_discover">{t('Open in Discover')}</GuideAnchor>
           </ActionButton>
         </Feature>
-        {orgFeatures.has('shared-issues') && (
-          <ShareIssue
-            organization={organization}
-            group={group}
-            disabled={disabled || !shareCap.enabled}
-            disabledReason={shareCap.disabledReason}
-            onToggle={this.onToggleShare}
-          />
+        {isResolved || isIgnored ? (
+          <ActionButton
+            priority="primary"
+            title={
+              isAutoResolved
+                ? t(
+                    'This event is resolved due to the Auto Resolve configuration for this project'
+                  )
+                : t('Change status to unresolved')
+            }
+            size="sm"
+            icon={isResolved ? <IconCheckmark /> : <IconMute />}
+            disabled={disabled || isAutoResolved}
+            onClick={() =>
+              this.onUpdate({status: ResolutionStatus.UNRESOLVED, statusDetails: {}})
+            }
+          >
+            {isIgnored ? t('Ignored') : t('Resolved')}
+          </ActionButton>
+        ) : (
+          <Fragment>
+            <GuideAnchor target="ignore_delete_discard" position="bottom" offset={20}>
+              <IgnoreActions
+                className="hidden-xs"
+                isIgnored={isIgnored}
+                onUpdate={this.onUpdate}
+                disabled={disabled}
+                size="sm"
+                hideIcon
+                disableTooltip
+              />
+            </GuideAnchor>
+            <GuideAnchor target="resolve" position="bottom" offset={20}>
+              <ResolveActions
+                disableTooltip
+                disabled={disabled}
+                disableDropdown={disabled}
+                hasRelease={hasRelease}
+                latestRelease={project.latestRelease}
+                onUpdate={this.onUpdate}
+                orgSlug={organization.slug}
+                projectSlug={project.slug}
+                isResolved={isResolved}
+                isAutoResolved={isAutoResolved}
+                size="sm"
+                hideIcon
+                priority="primary"
+              />
+            </GuideAnchor>
+          </Fragment>
         )}
-        <SubscribeAction
-          disabled={disabled}
-          group={group}
-          onClick={this.handleClick(disabled, this.onToggleSubscribe)}
-        />
-        <DropdownMenu
-          triggerProps={{
-            'aria-label': t('More Actions'),
-            icon: <IconEllipsis size="xs" />,
-            showChevron: false,
-            size: 'xs',
-          }}
-          items={sharedMenuItems}
-        />
-      </Wrapper>
+      </ActionWrapper>
     );
   }
 }
 
-const Wrapper = styled('div')`
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: flex-start;
-  align-items: center;
-  grid-auto-flow: column;
-  gap: ${space(0.5)};
-  white-space: nowrap;
-`;
-
 const ActionWrapper = styled('div')`
   display: flex;
   align-items: center;

+ 0 - 65
static/app/views/issueDetails/actions/shareIssue.tsx

@@ -1,65 +0,0 @@
-import styled from '@emotion/styled';
-
-import {openModal} from 'sentry/actionCreators/modal';
-import {Button} from 'sentry/components/button';
-import {Tooltip} from 'sentry/components/tooltip';
-import {t} from 'sentry/locale';
-import type {Group, Organization} from 'sentry/types';
-
-import ShareIssueModal from './shareModal';
-
-interface ShareIssueProps {
-  group: Group;
-  onToggle: () => void;
-  organization: Organization;
-  disabled?: boolean;
-  disabledReason?: string;
-}
-
-function ShareIssue({
-  onToggle,
-  disabled,
-  group,
-  organization,
-  disabledReason,
-}: ShareIssueProps) {
-  const handleOpen = () => {
-    // Starts sharing as soon as dropdown is opened
-    openModal(modalProps => (
-      <ShareIssueModal
-        {...modalProps}
-        organization={organization}
-        projectSlug={group.project.slug}
-        groupId={group.id}
-        onToggle={onToggle}
-      />
-    ));
-  };
-
-  return (
-    <Tooltip title={disabledReason} disabled={!disabled}>
-      <Button
-        size="xs"
-        onClick={handleOpen}
-        disabled={disabled}
-        icon={
-          <IndicatorDot
-            aria-label={group.isPublic ? t('Shared') : t('Not Shared')}
-            isShared={group.isPublic}
-          />
-        }
-      >
-        {t('Share')}
-      </Button>
-    </Tooltip>
-  );
-}
-
-export default ShareIssue;
-
-const IndicatorDot = styled('div')<{isShared?: boolean}>`
-  border-radius: 50%;
-  width: 10px;
-  height: 10px;
-  background: ${p => (p.isShared ? p.theme.active : p.theme.border)};
-`;

+ 10 - 35
static/app/views/issueDetails/groupEvents.tsx

@@ -3,7 +3,6 @@ import {browserHistory, RouteComponentProps} from 'react-router';
 import styled from '@emotion/styled';
 
 import {Client} from 'sentry/api';
-import EnvironmentPageFilter from 'sentry/components/environmentPageFilter';
 import EventSearchBar from 'sentry/components/events/searchBar';
 import * as Layout from 'sentry/components/layouts/thirds';
 import space from 'sentry/styles/space';
@@ -78,38 +77,20 @@ class GroupEvents extends Component<Props, State> {
     );
   };
 
-  renderSearchBar() {
-    // New issue actions moves the environment picker to the header
-    const hasIssueActionsV2 =
-      this.props.organization.features.includes('issue-actions-v2');
-
-    const searchBar = (
-      <EventSearchBar
-        organization={this.props.organization}
-        defaultQuery=""
-        onSearch={this.handleSearch}
-        excludedTags={excludedTags}
-        query={this.state.query}
-        hasRecentSearches={false}
-      />
-    );
-
-    if (hasIssueActionsV2) {
-      return searchBar;
-    }
-    return (
-      <FilterSection>
-        <EnvironmentPageFilter />
-        {searchBar}
-      </FilterSection>
-    );
-  }
-
   render() {
     return (
       <Layout.Body>
         <Layout.Main fullWidth>
-          <AllEventsFilters>{this.renderSearchBar()}</AllEventsFilters>
+          <AllEventsFilters>
+            <EventSearchBar
+              organization={this.props.organization}
+              defaultQuery=""
+              onSearch={this.handleSearch}
+              excludedTags={excludedTags}
+              query={this.state.query}
+              hasRecentSearches={false}
+            />
+          </AllEventsFilters>
           <AllEventsTable
             issueId={this.props.group.id}
             location={this.props.location}
@@ -123,12 +104,6 @@ class GroupEvents extends Component<Props, State> {
   }
 }
 
-const FilterSection = styled('div')`
-  display: grid;
-  gap: ${space(1)};
-  grid-template-columns: max-content 1fr;
-`;
-
 const AllEventsFilters = styled('div')`
   margin-bottom: ${space(2)};
 `;

+ 11 - 38
static/app/views/issueDetails/header.tsx

@@ -20,7 +20,6 @@ import Link from 'sentry/components/links/link';
 import ReplayCountBadge from 'sentry/components/replays/replayCountBadge';
 import ReplaysFeatureBadge from 'sentry/components/replays/replaysFeatureBadge';
 import useReplaysCount from 'sentry/components/replays/useReplaysCount';
-import SeenByList from 'sentry/components/seenByList';
 import ShortId from 'sentry/components/shortId';
 import {Item, TabList} from 'sentry/components/tabs';
 import {Tooltip} from 'sentry/components/tooltip';
@@ -296,8 +295,6 @@ function GroupHeader({
     </GuideAnchor>
   );
 
-  const hasIssueActionsV2 = organization.features.includes('issue-actions-v2');
-
   return (
     <Layout.Header>
       <div className={className}>
@@ -311,15 +308,13 @@ function GroupHeader({
               {label: shortIdBreadCrumb},
             ]}
           />
-          {hasIssueActionsV2 && (
-            <GroupActions
-              group={group}
-              project={project}
-              disabled={disableActions}
-              event={event}
-              query={location.query}
-            />
-          )}
+          <GroupActions
+            group={group}
+            project={project}
+            disabled={disableActions}
+            event={event}
+            query={location.query}
+          />
         </BreadcrumbActionWrapper>
         <HeaderRow>
           <TitleWrapper>
@@ -357,26 +352,10 @@ function GroupHeader({
             </div>
           </StatsWrapper>
         </HeaderRow>
-        {hasIssueActionsV2 ? (
-          // Environment picker for mobile
-          <HeaderRow className="hidden-sm hidden-md hidden-lg">
-            <EnvironmentPageFilter alignDropdown="right" />
-          </HeaderRow>
-        ) : (
-          <HeaderRow>
-            <GroupActions
-              group={group}
-              project={project}
-              disabled={disableActions}
-              event={event}
-              query={location.query}
-            />
-            <StyledSeenByList
-              seenBy={group.seenBy}
-              iconTooltip={t('People who have viewed this issue')}
-            />
-          </HeaderRow>
-        )}
+        {/* Environment picker for mobile */}
+        <HeaderRow className="hidden-sm hidden-md hidden-lg">
+          <EnvironmentPageFilter alignDropdown="right" />
+        </HeaderRow>
         <GroupHeaderTabs {...{baseUrl, disabledTabs, eventRoute, group, project}} />
       </div>
     </Layout.Header>
@@ -428,12 +407,6 @@ const TitleHeading = styled('div')`
   gap: ${space(1)};
 `;
 
-const StyledSeenByList = styled(SeenByList)`
-  @media (max-width: ${p => p.theme.breakpoints.small}) {
-    display: none;
-  }
-`;
-
 const StyledEventOrGroupTitle = styled(EventOrGroupTitle)`
   font-size: inherit;
 `;