Browse Source

ref(grouping): Add tooltips to disabled 'unmerge' and 'compare' buttons (#38801)

Priscila Oliveira 2 years ago
parent
commit
db2bb276c2

+ 21 - 1
static/app/stores/groupingStore.tsx

@@ -447,6 +447,7 @@ const storeConfig: GroupingStoreDefinition = {
       this.mergedItems.size <= 1 ||
       this.unmergeList.size === 0 ||
       this.isAllUnmergedSelected();
+
     this.enableFingerprintCompare = this.unmergeList.size === 2;
 
     this.triggerUnmergeState();
@@ -631,7 +632,26 @@ const storeConfig: GroupingStoreDefinition = {
   },
 
   getState(): State {
-    return this.state;
+    return {
+      ...pick(this, [
+        'enableFingerprintCompare',
+        'error',
+        'filteredSimilarItems',
+        'loading',
+        'mergeDisabled',
+        'mergeList',
+        'mergeState',
+        'mergeState',
+        'mergedItems',
+        'mergedLinks',
+        'similarItems',
+        'similarLinks',
+        'unmergeDisabled',
+        'unmergeLastCollapsed',
+        'unmergeList',
+        'unmergeState',
+      ]),
+    };
   },
 };
 

+ 20 - 9
static/app/views/organizationGroupDetails/groupMerged/mergedItem.tsx

@@ -5,6 +5,7 @@ import Checkbox from 'sentry/components/checkbox';
 import EventOrGroupHeader from 'sentry/components/eventOrGroupHeader';
 import Tooltip from 'sentry/components/tooltip';
 import {IconChevron} from 'sentry/icons';
+import {t} from 'sentry/locale';
 import GroupingStore, {Fingerprint} from 'sentry/stores/groupingStore';
 import space from 'sentry/styles/space';
 import {Organization} from 'sentry/types';
@@ -12,6 +13,7 @@ import {Organization} from 'sentry/types';
 type Props = {
   fingerprint: Fingerprint;
   organization: Organization;
+  totalFingerprint: number;
 };
 
 type State = {
@@ -92,23 +94,32 @@ class MergedItem extends Component<Props, State> {
   }
 
   render() {
-    const {fingerprint, organization} = this.props;
+    const {fingerprint, organization, totalFingerprint} = this.props;
     const {latestEvent, id, label} = fingerprint;
     const {collapsed, busy, checked} = this.state;
-    const checkboxDisabled = busy;
+    const checkboxDisabled = busy || totalFingerprint === 1;
 
     // `latestEvent` can be null if last event w/ fingerprint is not within retention period
     return (
       <MergedGroup busy={busy}>
         <Controls expanded={!collapsed}>
           <ActionWrapper onClick={this.handleToggle}>
-            <Checkbox
-              id={id}
-              value={id}
-              checked={checked}
-              disabled={checkboxDisabled}
-              onChange={this.handleCheckClick}
-            />
+            <Tooltip
+              disabled={!checkboxDisabled}
+              title={
+                checkboxDisabled && totalFingerprint === 1
+                  ? t('To check, the list must contain 2 or more items')
+                  : undefined
+              }
+            >
+              <Checkbox
+                id={id}
+                value={id}
+                checked={checked}
+                disabled={checkboxDisabled}
+                onChange={this.handleCheckClick}
+              />
+            </Tooltip>
 
             <FingerprintLabel onClick={this.handleLabelClick} htmlFor={id}>
               {this.renderFingerprint(id, label)}

+ 2 - 1
static/app/views/organizationGroupDetails/groupMerged/mergedList.tsx

@@ -10,7 +10,7 @@ import {Group, Organization, Project} from 'sentry/types';
 import withOrganization from 'sentry/utils/withOrganization';
 
 import MergedItem from './mergedItem';
-import MergedToolbar from './mergedToolbar';
+import {MergedToolbar} from './mergedToolbar';
 
 type Props = {
   groupId: Group['id'];
@@ -74,6 +74,7 @@ function MergedList({
               key={fingerprint.id}
               organization={organization}
               fingerprint={fingerprint}
+              totalFingerprint={fingerprintsWithLatestEvent.length}
             />
           ))}
         </PanelBody>

+ 67 - 89
static/app/views/organizationGroupDetails/groupMerged/mergedToolbar.tsx

@@ -1,6 +1,4 @@
-import {Component} from 'react';
 import styled from '@emotion/styled';
-import pick from 'lodash/pick';
 
 import {openDiffModal} from 'sentry/actionCreators/modal';
 import Button from 'sentry/components/button';
@@ -8,6 +6,7 @@ import Confirm from 'sentry/components/confirm';
 import {PanelHeader} from 'sentry/components/panels';
 import {t, tct} from 'sentry/locale';
 import GroupingStore from 'sentry/stores/groupingStore';
+import {useLegacyStore} from 'sentry/stores/useLegacyStore';
 import space from 'sentry/styles/space';
 import {Group, Organization, Project} from 'sentry/types';
 
@@ -19,49 +18,25 @@ type Props = {
   project: Project;
 };
 
-type State = {
-  enableFingerprintCompare: boolean;
-  unmergeDisabled: boolean;
-  unmergeLastCollapsed: boolean;
-  unmergeList: Map<any, any>;
-};
-
-class MergedToolbar extends Component<Props, State> {
-  state: State = this.getInitialState();
-
-  getInitialState() {
-    // @ts-ignore GroupingStore types are not correct, store.init dinamically sets these
-    const {unmergeList, unmergeLastCollapsed, unmergeDisabled, enableFingerprintCompare} =
-      GroupingStore;
-
-    return {
-      enableFingerprintCompare,
-      unmergeList,
-      unmergeLastCollapsed,
-      unmergeDisabled,
-    };
-  }
-
-  componentWillUnmount() {
-    this.listener?.();
-  }
-
-  listener = GroupingStore.listen(data => this.onGroupChange(data), undefined);
-
-  onGroupChange = updateObj => {
-    const allowedKeys = [
-      'unmergeLastCollapsed',
-      'unmergeDisabled',
-      'unmergeList',
-      'enableFingerprintCompare',
-    ];
-
-    this.setState(pick(updateObj, allowedKeys));
-  };
-
-  handleShowDiff = (event: React.MouseEvent) => {
-    const {groupId, project, orgId} = this.props;
-    const {unmergeList} = this.state;
+export function MergedToolbar({
+  groupId,
+  project,
+  orgId,
+  onUnmerge,
+  onToggleCollapse,
+}: Props) {
+  const {
+    unmergeList,
+    mergedItems,
+    unmergeLastCollapsed,
+    unmergeDisabled,
+    enableFingerprintCompare,
+  } = useLegacyStore(GroupingStore);
+
+  const unmergeCount = unmergeList?.size ?? 0;
+
+  function handleShowDiff(event: React.MouseEvent) {
+    event.stopPropagation();
 
     const entries = unmergeList.entries();
 
@@ -83,52 +58,55 @@ class MergedToolbar extends Component<Props, State> {
       baseEventId,
       targetEventId,
     });
-
-    event.stopPropagation();
-  };
-
-  render() {
-    const {onUnmerge, onToggleCollapse} = this.props;
-
-    const {unmergeList, unmergeLastCollapsed, unmergeDisabled, enableFingerprintCompare} =
-      this.state;
-    const unmergeCount = (unmergeList && unmergeList.size) || 0;
-
-    return (
-      <PanelHeader hasButtons>
-        <div>
-          <Confirm
-            disabled={unmergeDisabled}
-            onConfirm={onUnmerge}
-            message={t(
-              'These events will be unmerged and grouped into a new issue. Are you sure you want to unmerge these events?'
-            )}
-          >
-            <Button
-              size="sm"
-              title={tct('Unmerging [unmergeCount] events', {unmergeCount})}
-            >
-              {t('Unmerge')} ({unmergeCount || 0})
-            </Button>
-          </Confirm>
-
-          <CompareButton
-            size="sm"
-            disabled={!enableFingerprintCompare}
-            onClick={this.handleShowDiff}
-          >
-            {t('Compare')}
-          </CompareButton>
-        </div>
-        <Button size="sm" onClick={onToggleCollapse}>
-          {unmergeLastCollapsed ? t('Expand All') : t('Collapse All')}
-        </Button>
-      </PanelHeader>
-    );
   }
-}
 
-export default MergedToolbar;
+  const unmergeDisabledReason =
+    mergedItems.length <= 1
+      ? t('To unmerge, the list must contain 2 or more items')
+      : unmergeList.size === 0
+      ? t('To unmerge, 1 or more items must be selected')
+      : GroupingStore.isAllUnmergedSelected()
+      ? t('We are unable to unmerge all items at once')
+      : undefined;
+
+  return (
+    <PanelHeader hasButtons>
+      <div>
+        <Confirm
+          disabled={unmergeDisabled}
+          onConfirm={onUnmerge}
+          message={t(
+            'These events will be unmerged and grouped into a new issue. Are you sure you want to unmerge these events?'
+          )}
+        >
+          <Button size="sm" title={unmergeDisabledReason}>
+            {mergedItems.length <= 1
+              ? t('Unmerge')
+              : tct('Unmerge ([itemsSelectedQuantity])', {
+                  itemsSelectedQuantity: unmergeCount,
+                })}
+          </Button>
+        </Confirm>
+
+        <CompareButton
+          size="sm"
+          disabled={!enableFingerprintCompare}
+          onClick={handleShowDiff}
+          title={
+            !enableFingerprintCompare
+              ? t('To compare, exactly 2 items must be selected')
+              : undefined
+          }
+        >
+          {t('Compare')}
+        </CompareButton>
+      </div>
+      <Button size="sm" onClick={onToggleCollapse}>
+        {unmergeLastCollapsed ? t('Expand All') : t('Collapse All')}
+      </Button>
+    </PanelHeader>
+  );
+}
 
 const CompareButton = styled(Button)`
   margin-left: ${space(1)};