Browse Source

feat(saved-search) Add delete button to org saved searches (#12522)

Add a delete button to organization saved search dropdown. While the
visuals of this component are likely to change this gets the behavior
for delete in-place.

This depends on the delete API in #12502

Fixes SEN-397
Mark Story 6 years ago
parent
commit
58bf615af5

+ 19 - 0
src/sentry/static/sentry/app/actionCreators/savedSearches.jsx

@@ -69,3 +69,22 @@ export function fetchRecentSearches(api, orgId, type, query) {
 
   return promise;
 }
+
+/**
+ * Send a DELETE rquest to remove a saved search
+ *
+ * @param {Object} api API client
+ * @param {String} orgId Organization slug
+ * @param {Object} search The search to remove.
+ */
+export function deleteSavedSearch(api, orgId, search) {
+  const url = `/organizations/${orgId}/searches/${search.id}/`;
+
+  const promise = api
+    .requestPromise(url, {
+      method: 'DELETE',
+    })
+    .catch(handleXhrErrorResponse('Unable to delete a saved search'));
+
+  return promise;
+}

+ 8 - 0
src/sentry/static/sentry/app/components/confirm.jsx

@@ -27,6 +27,9 @@ class Confirm extends React.PureComponent {
     onConfirming: PropTypes.func,
     onCancel: PropTypes.func,
     header: PropTypes.node,
+
+    // Stop event propgation when opening the confirm modal
+    stopPropagation: PropTypes.bool,
   };
 
   static defaultProps = {
@@ -34,6 +37,7 @@ class Confirm extends React.PureComponent {
     disableConfirmButton: false,
     cancelText: t('Cancel'),
     confirmText: t('Confirm'),
+    stopPropagation: false,
   };
 
   static getDerivedStateFromProps(props, state) {
@@ -105,6 +109,10 @@ class Confirm extends React.PureComponent {
       return;
     }
 
+    if (e && this.props.stopPropagation) {
+      e.stopPropagation();
+    }
+
     if (bypass) {
       this.props.onConfirm();
       return;

+ 28 - 17
src/sentry/static/sentry/app/views/organizationStream/overview.jsx

@@ -19,7 +19,7 @@ import {Panel, PanelBody} from 'app/components/panels';
 import StreamGroup from 'app/components/stream/group';
 import {fetchOrganizationTags, fetchTagValues} from 'app/actionCreators/tags';
 import {fetchOrgMembers, indexMembersByProject} from 'app/actionCreators/members';
-import {fetchSavedSearches} from 'app/actionCreators/savedSearches';
+import {fetchSavedSearches, deleteSavedSearch} from 'app/actionCreators/savedSearches';
 import ConfigStore from 'app/stores/configStore';
 import GroupStore from 'app/stores/groupStore';
 import SelectedGroupStore from 'app/stores/selectedGroupStore';
@@ -213,10 +213,6 @@ const OrganizationStream = createReactClass({
     return pickBy(params, v => utils.defined(v));
   },
 
-  getAccess() {
-    return new Set(this.props.organization.access);
-  },
-
   getFeatures() {
     return new Set(this.props.organization.features);
   },
@@ -342,10 +338,6 @@ const OrganizationStream = createReactClass({
     return `/organizations/${params.orgId}/issues/`;
   },
 
-  onSavedSearchSelect(search) {
-    this.setState({savedSearch: search, issuesLoading: true}, this.transitionTo);
-  },
-
   onRealtimeChange(realtime) {
     Cookies.set('realtimeActive', realtime.toString());
     this.setState({
@@ -601,6 +593,26 @@ const OrganizationStream = createReactClass({
     this.setState({savedSearch: data}, this.transitionTo);
   },
 
+  onSavedSearchSelect(search) {
+    this.setState({savedSearch: search, issuesLoading: true}, this.transitionTo);
+  },
+
+  onSavedSearchDelete(search) {
+    const {orgId} = this.props.params;
+    const {savedSearchList} = this.state;
+
+    deleteSavedSearch(this.api, orgId, search).then(() => {
+      this.setState(
+        {
+          savedSearchList: savedSearchList.filter(s => s.id != search.id),
+          savedSearch: null,
+          issuesLoading: true,
+        },
+        this.transitionTo
+      );
+    });
+  },
+
   renderAwaitingEvents(projects) {
     const {organization} = this.props;
     const project = projects.length > 0 ? projects[0] : null;
@@ -627,13 +639,12 @@ const OrganizationStream = createReactClass({
     if (this.state.savedSearchLoading) {
       return this.renderLoading();
     }
-    const params = this.props.params;
     const classes = ['stream-row'];
     if (this.state.isSidebarVisible) {
       classes.push('show-sidebar');
     }
-    const {orgId, searchId} = this.props.params;
-    const access = this.getAccess();
+
+    const {params, organization} = this.props;
     const query = this.getQuery();
 
     // If we have a selected project set release data up
@@ -659,10 +670,9 @@ const OrganizationStream = createReactClass({
       <div className={classNames(classes)}>
         <div className="stream-content">
           <StreamFilters
-            access={access}
-            orgId={orgId}
+            organization={organization}
             projectId={projectId}
-            searchId={searchId}
+            searchId={params.searchId}
             query={query}
             sort={this.getSort()}
             queryCount={this.state.queryCount}
@@ -671,6 +681,7 @@ const OrganizationStream = createReactClass({
             onSearch={this.onSearch}
             onSavedSearchCreate={this.onSavedSearchCreate}
             onSavedSearchSelect={this.onSavedSearchSelect}
+            onSavedSearchDelete={this.onSavedSearchDelete}
             onSidebarToggle={this.onSidebarToggle}
             isSearchDisabled={this.state.isSidebarVisible}
             savedSearchList={this.state.savedSearchList}
@@ -680,7 +691,7 @@ const OrganizationStream = createReactClass({
 
           <Panel>
             <StreamActions
-              orgId={params.orgId}
+              orgId={organization.slug}
               projectId={projectId}
               selection={this.props.selection}
               hasReleases={hasReleases}
@@ -710,7 +721,7 @@ const OrganizationStream = createReactClass({
           tags={this.state.tags}
           query={query}
           onQueryChange={this.onSearch}
-          orgId={params.orgId}
+          orgId={organization.slug}
           tagValueLoader={this.tagValueLoader}
         />
       </div>

+ 9 - 7
src/sentry/static/sentry/app/views/stream/filters.jsx

@@ -3,6 +3,7 @@ import React from 'react';
 
 import Feature from 'app/components/acl/feature';
 
+import SentryTypes from 'app/sentryTypes';
 import SearchBar from './searchBar';
 import SortOptions from './sortOptions';
 import SavedSearchSelector from './savedSearchSelector';
@@ -10,9 +11,8 @@ import OrganizationSavedSearchSelector from './organizationSavedSearchSelector';
 
 class StreamFilters extends React.Component {
   static propTypes = {
-    orgId: PropTypes.string.isRequired,
     projectId: PropTypes.string,
-    access: PropTypes.object.isRequired,
+    organization: SentryTypes.Organization,
 
     searchId: PropTypes.string,
     savedSearchList: PropTypes.array.isRequired,
@@ -28,6 +28,7 @@ class StreamFilters extends React.Component {
     onSidebarToggle: PropTypes.func,
     onSavedSearchCreate: PropTypes.func.isRequired,
     onSavedSearchSelect: PropTypes.func.isRequired,
+    onSavedSearchDelete: PropTypes.func.isRequired,
     tagValueLoader: PropTypes.func.isRequired,
     tags: PropTypes.object.isRequired,
   };
@@ -47,8 +48,7 @@ class StreamFilters extends React.Component {
 
   render() {
     const {
-      access,
-      orgId,
+      organization,
       projectId,
       searchId,
       queryCount,
@@ -62,6 +62,7 @@ class StreamFilters extends React.Component {
       onSearch,
       onSavedSearchCreate,
       onSavedSearchSelect,
+      onSavedSearchDelete,
       onSortChange,
       tagValueLoader,
       tags,
@@ -75,8 +76,7 @@ class StreamFilters extends React.Component {
               features={['org-saved-searches']}
               renderDisabled={() => (
                 <SavedSearchSelector
-                  access={access}
-                  orgId={orgId}
+                  organization={organization}
                   projectId={projectId}
                   searchId={searchId}
                   queryCount={queryCount}
@@ -89,8 +89,10 @@ class StreamFilters extends React.Component {
               )}
             >
               <OrganizationSavedSearchSelector
+                organization={organization}
                 savedSearchList={savedSearchList}
                 onSavedSearchSelect={onSavedSearchSelect}
+                onSavedSearchDelete={onSavedSearchDelete}
                 queryCount={queryCount}
                 queryMaxCount={queryMaxCount}
               />
@@ -103,7 +105,7 @@ class StreamFilters extends React.Component {
               </div>
 
               <SearchBar
-                orgId={orgId}
+                orgId={organization.slug}
                 query={query || ''}
                 onSearch={onSearch}
                 disabled={isSearchDisabled}

+ 67 - 14
src/sentry/static/sentry/app/views/stream/organizationSavedSearchSelector.jsx

@@ -3,16 +3,22 @@ import PropTypes from 'prop-types';
 import styled from 'react-emotion';
 
 import {t} from 'app/locale';
+import Access from 'app/components/acl/access';
+import Button from 'app/components/button';
+import Confirm from 'app/components/confirm';
 import MenuItem from 'app/components/menuItem';
 import DropdownLink from 'app/components/dropdownLink';
 import QueryCount from 'app/components/queryCount';
 import InlineSvg from 'app/components/inlineSvg';
+import SentryTypes from 'app/sentryTypes';
 import space from 'app/styles/space';
 
 export default class OrganizationSavedSearchSelector extends React.Component {
   static propTypes = {
+    organization: SentryTypes.Organization.isRequired,
     savedSearchList: PropTypes.array.isRequired,
     onSavedSearchSelect: PropTypes.func.isRequired,
+    onSavedSearchDelete: PropTypes.func.isRequired,
     query: PropTypes.string,
     queryCount: PropTypes.number,
     queryMaxCount: PropTypes.number,
@@ -33,7 +39,12 @@ export default class OrganizationSavedSearchSelector extends React.Component {
   }
 
   renderList() {
-    const {savedSearchList, onSavedSearchSelect} = this.props;
+    const {
+      savedSearchList,
+      onSavedSearchDelete,
+      onSavedSearchSelect,
+      organization,
+    } = this.props;
 
     if (savedSearchList.length === 0) {
       return <EmptyItem>{t("There don't seem to be any saved searches yet.")}</EmptyItem>;
@@ -42,10 +53,27 @@ export default class OrganizationSavedSearchSelector extends React.Component {
     return savedSearchList.map(search => (
       <StyledMenuItem onSelect={() => onSavedSearchSelect(search)} key={search.id}>
         {search.isPinned && <InlineSvg src={'icon-pin'} />}
-        <span>
-          <strong>{search.name}</strong>
-        </span>
-        <code>{search.query}</code>
+        <SearchTitle>{search.name}</SearchTitle>
+        <SearchQuery>{search.query}</SearchQuery>
+        {search.isGlobal === false && (
+          <Access
+            organization={organization}
+            access={['org:write']}
+            renderNoAccessMessage={false}
+          >
+            <Confirm
+              onConfirm={() => onSavedSearchDelete(search)}
+              message={t('Are you sure you want to delete this saved search?')}
+              stopPropagation
+            >
+              <Button
+                title={t('Delete this saved search')}
+                icon="icon-trash"
+                size="xsmall"
+              />
+            </Confirm>
+          </Access>
+        )}
       </StyledMenuItem>
     ));
   }
@@ -77,21 +105,46 @@ const Container = styled.div`
   }
 `;
 
+const SearchTitle = styled.strong`
+  display: block;
+  max-width: 100%;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  overflow: hidden;
+  color: ${p => p.theme.gray5};
+  padding: 0;
+  background: inherit;
+`;
+
+const SearchQuery = styled.code`
+  display: block;
+  max-width: 100%;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  overflow: hidden;
+  color: ${p => p.theme.gray5};
+  padding: 0;
+  background: inherit;
+`;
+
 const StyledMenuItem = styled(MenuItem)`
+  position: relative;
+
   & a {
     /* override shared-components.less */
     padding: ${space(0.25)} ${space(1)} !important;
   }
-  & span,
-  & code {
+
+  & button {
+    display: none;
+  }
+
+  &:focus,
+  &:hover button {
     display: block;
-    max-width: 100%;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    overflow: hidden;
-    color: ${p => p.theme.gray5};
-    padding: 0;
-    background: inherit;
+    position: absolute;
+    top: ${space(0.5)};
+    right: ${space(1)};
   }
 `;
 

+ 10 - 10
src/sentry/static/sentry/app/views/stream/savedSearchSelector.jsx

@@ -9,6 +9,7 @@ import IndicatorStore from 'app/stores/indicatorStore';
 import DropdownLink from 'app/components/dropdownLink';
 import QueryCount from 'app/components/queryCount';
 import MenuItem from 'app/components/menuItem';
+import SentryTypes from 'app/sentryTypes';
 import Tooltip from 'app/components/tooltip';
 import Tag from 'app/views/settings/components/tag';
 import {BooleanField, FormState, TextField} from 'app/components/forms';
@@ -18,9 +19,8 @@ import space from 'app/styles/space';
 const SaveSearchButton = withApi(
   class SaveSearchButton extends React.Component {
     static propTypes = {
-      orgId: PropTypes.string.isRequired,
+      organization: SentryTypes.Organization.isRequired,
       projectId: PropTypes.string,
-      access: PropTypes.object.isRequired,
       api: PropTypes.object.isRequired,
       query: PropTypes.string.isRequired,
       disabled: PropTypes.bool,
@@ -85,8 +85,8 @@ const SaveSearchButton = withApi(
         },
         () => {
           const loadingIndicator = IndicatorStore.add(t('Saving changes..'));
-          const {orgId, projectId} = this.props;
-          api.request(`/projects/${orgId}/${projectId}/searches/`, {
+          const {organization, projectId} = this.props;
+          api.request(`/projects/${organization.slug}/${projectId}/searches/`, {
             method: 'POST',
             data: this.state.formData,
             success: data => {
@@ -115,7 +115,8 @@ const SaveSearchButton = withApi(
 
     render() {
       const isSaving = this.state.state === FormState.SAVING;
-      const {tooltip, buttonTitle, style, children, disabled} = this.props;
+      const {tooltip, buttonTitle, style, children, disabled, organization} = this.props;
+      const access = new Set(organization.access);
       return (
         <React.Fragment>
           <Tooltip
@@ -175,7 +176,7 @@ const SaveSearchButton = withApi(
                   label={t('Make this the default view for myself.')}
                   onChange={this.onFieldChange.bind(this, 'isUserDefault')}
                 />
-                {this.props.access.has('project:write') && (
+                {access.has('project:write') && (
                   <BooleanField
                     key="isDefault"
                     name="is-default"
@@ -209,10 +210,9 @@ const SaveSearchButton = withApi(
 const SavedSearchSelector = withApi(
   class SavedSearchSelector extends React.Component {
     static propTypes = {
-      orgId: PropTypes.string.isRequired,
+      organization: SentryTypes.Organization.isRequired,
       projectId: PropTypes.string,
       searchId: PropTypes.string,
-      access: PropTypes.object.isRequired,
       query: PropTypes.string,
       savedSearchList: PropTypes.array.isRequired,
       queryCount: PropTypes.number,
@@ -236,7 +236,7 @@ const SavedSearchSelector = withApi(
 
     render() {
       const {
-        orgId,
+        organization,
         projectId,
         queryCount,
         queryMaxCount,
@@ -288,7 +288,7 @@ const SavedSearchSelector = withApi(
                 <Button
                   size="xsmall"
                   priority="default"
-                  to={`/${orgId}/${projectId}/settings/saved-searches/`}
+                  to={`/${organization.slug}/${projectId}/settings/saved-searches/`}
                   disabled={!hasProject}
                 >
                   {t('Manage')}

+ 7 - 10
src/sentry/static/sentry/app/views/stream/stream.jsx

@@ -670,16 +670,13 @@ const Stream = createReactClass({
     if (this.state.loading) {
       return this.renderLoading();
     }
-    const params = this.props.params;
     const classes = ['stream-row'];
     if (this.state.isSidebarVisible) {
       classes.push('show-sidebar');
     }
-    const {orgId, projectId} = this.props.params;
     const {organization} = this.context;
 
     const searchId = this.state.searchId;
-    const access = this.getAccess();
     const projectFeatures = this.getProjectFeatures();
     const project = this.getProject();
 
@@ -694,9 +691,8 @@ const Stream = createReactClass({
       <div className={classNames(classes)}>
         <div className="stream-content">
           <StreamFilters
-            access={access}
-            orgId={orgId}
-            projectId={projectId}
+            organization={organization}
+            projectId={project.slug}
             query={this.state.query}
             sort={this.state.sort}
             searchId={searchId}
@@ -706,6 +702,7 @@ const Stream = createReactClass({
             onSearch={this.onSearch}
             onSavedSearchCreate={this.onSavedSearchCreate}
             onSavedSearchSelect={this.onSavedSearchSelect}
+            onSavedSearchDelete={() => {}}
             onSidebarToggle={this.onSidebarToggle}
             isSearchDisabled={this.state.isSidebarVisible}
             savedSearchList={this.state.savedSearchList}
@@ -714,8 +711,8 @@ const Stream = createReactClass({
           />
           <Panel>
             <StreamActions
-              orgId={params.orgId}
-              projectId={params.projectId}
+              orgId={organization.slug}
+              projectId={project.slug}
               selection={selection}
               hasReleases={projectFeatures.has('releases')}
               latestRelease={this.context.project.latestRelease}
@@ -744,8 +741,8 @@ const Stream = createReactClass({
           tags={this.props.tags}
           query={this.state.query}
           onQueryChange={this.onSearch}
-          orgId={params.orgId}
-          projectId={params.projectId}
+          orgId={organization.slug}
+          projectId={project.slug}
           tagValueLoader={this.tagValueLoader}
         />
       </div>

+ 54 - 0
tests/js/spec/components/actions/__snapshots__/ignore.spec.jsx.snap

@@ -249,6 +249,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
           message="Yoooooo"
           onConfirm={[Function]}
           priority="primary"
+          stopPropagation={false}
         >
           <a
             className="btn btn-default btn-sm"
@@ -477,6 +478,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                 message="Yoooooo"
                                 onConfirm={[Function]}
                                 priority="primary"
+                                stopPropagation={false}
                               >
                                 <a
                                   onClick={[Function]}
@@ -572,6 +574,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                 message="Yoooooo"
                                 onConfirm={[Function]}
                                 priority="primary"
+                                stopPropagation={false}
                               >
                                 <a
                                   onClick={[Function]}
@@ -667,6 +670,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                 message="Yoooooo"
                                 onConfirm={[Function]}
                                 priority="primary"
+                                stopPropagation={false}
                               >
                                 <a
                                   onClick={[Function]}
@@ -762,6 +766,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                 message="Yoooooo"
                                 onConfirm={[Function]}
                                 priority="primary"
+                                stopPropagation={false}
                               >
                                 <a
                                   onClick={[Function]}
@@ -857,6 +862,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                 message="Yoooooo"
                                 onConfirm={[Function]}
                                 priority="primary"
+                                stopPropagation={false}
                               >
                                 <a
                                   onClick={[Function]}
@@ -1077,6 +1083,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1166,6 +1173,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1255,6 +1263,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1344,6 +1353,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1485,6 +1495,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1574,6 +1585,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1663,6 +1675,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1752,6 +1765,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1893,6 +1907,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -1982,6 +1997,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2071,6 +2087,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2160,6 +2177,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2301,6 +2319,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2390,6 +2409,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2479,6 +2499,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2568,6 +2589,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2709,6 +2731,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2798,6 +2821,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2887,6 +2911,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -2976,6 +3001,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3117,6 +3143,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3206,6 +3233,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3295,6 +3323,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3384,6 +3413,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3603,6 +3633,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3692,6 +3723,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3781,6 +3813,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -3870,6 +3903,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4011,6 +4045,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4100,6 +4135,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4189,6 +4225,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4278,6 +4315,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4419,6 +4457,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4508,6 +4547,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4597,6 +4637,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4686,6 +4727,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4827,6 +4869,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -4916,6 +4959,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5005,6 +5049,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5094,6 +5139,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5235,6 +5281,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5324,6 +5371,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5413,6 +5461,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5502,6 +5551,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5643,6 +5693,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5732,6 +5783,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5821,6 +5873,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}
@@ -5910,6 +5963,7 @@ exports[`IgnoreActions with confirmation step renders 1`] = `
                                           message="Yoooooo"
                                           onConfirm={[Function]}
                                           priority="primary"
+                                          stopPropagation={false}
                                         >
                                           <a
                                             onClick={[Function]}

+ 3 - 0
tests/js/spec/components/actions/__snapshots__/resolve.spec.jsx.snap

@@ -98,6 +98,7 @@ exports[`ResolveActions with confirmation step renders 1`] = `
           message="Are you sure???"
           onConfirm={[Function]}
           priority="primary"
+          stopPropagation={false}
         >
           <a
             className="btn btn-default btn-sm"
@@ -283,6 +284,7 @@ exports[`ResolveActions with confirmation step renders 1`] = `
                         message="Are you sure???"
                         onConfirm={[Function]}
                         priority="primary"
+                        stopPropagation={false}
                       >
                         <a
                           className="tip"
@@ -366,6 +368,7 @@ exports[`ResolveActions with confirmation step renders 1`] = `
                         message="Are you sure???"
                         onConfirm={[Function]}
                         priority="primary"
+                        stopPropagation={false}
                       >
                         <a
                           className="tip"

+ 21 - 0
tests/js/spec/components/confirm.spec.jsx

@@ -73,4 +73,25 @@ describe('Confirm', function() {
     expect(mock).toHaveBeenCalled();
     expect(mock.mock.calls).toHaveLength(1);
   });
+
+  it('can stop propagation on the event', function() {
+    const mock = jest.fn();
+    const wrapper = mount(
+      <Confirm message="Are you sure?" onConfirm={mock} stopPropagation>
+        <button>Confirm?</button>
+      </Confirm>,
+      TestStubs.routerContext()
+    );
+
+    expect(mock).not.toHaveBeenCalled();
+
+    const event = {
+      stopPropagation: jest.fn(),
+    };
+
+    wrapper.find('button').simulate('click', event);
+    wrapper.update();
+
+    expect(event.stopPropagation).toHaveBeenCalledTimes(1);
+  });
 });

Some files were not shown because too many files changed in this diff