123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- import {Component, Fragment} from 'react';
- import styled from '@emotion/styled';
- import type {Location} from 'history';
- import {addSuccessMessage} from 'sentry/actionCreators/indicator';
- import {Button} from 'sentry/components/button';
- import Confirm from 'sentry/components/confirm';
- import PanelHeader from 'sentry/components/panels/panelHeader';
- import ToolbarHeader from 'sentry/components/toolbarHeader';
- import {t} from 'sentry/locale';
- import GroupingStore from 'sentry/stores/groupingStore';
- import {space} from 'sentry/styles/space';
- import type {Organization} from 'sentry/types/organization';
- import type {Project} from 'sentry/types/project';
- import {trackAnalytics} from 'sentry/utils/analytics';
- type Props = {
- location: Location;
- onMerge: () => void;
- groupId?: string;
- itemsWouldGroup?: Array<{id: string; shouldBeGrouped: string | undefined}> | undefined;
- organization?: Organization;
- project?: Project;
- };
- const initialState = {
- mergeCount: 0,
- mergeList: [] as string[],
- };
- type State = typeof initialState;
- class SimilarToolbar extends Component<Props, State> {
- state: State = initialState;
- componentWillUnmount() {
- this.listener?.();
- }
- onGroupChange = ({mergeList}) => {
- if (!mergeList?.length) {
- this.setState({mergeCount: 0});
- return;
- }
- if (mergeList.length !== this.state.mergeCount) {
- this.setState({mergeCount: mergeList.length, mergeList});
- }
- };
- listener = GroupingStore.listen(this.onGroupChange, undefined);
- handleSimilarityEmbeddings = (value: string) => {
- if (
- this.state.mergeList.length === 0 ||
- !this.props.organization ||
- !this.props.groupId
- ) {
- return;
- }
- for (const parentGroupId of this.state.mergeList) {
- const itemWouldGroup = this.props.itemsWouldGroup?.find(
- item => item.id === parentGroupId
- );
- trackAnalytics(
- 'issue_details.similar_issues.similarity_embeddings_feedback_recieved',
- {
- organization: this.props.organization,
- projectId: this.props.project?.id,
- parentGroupId,
- groupId: this.props.groupId,
- value,
- wouldGroup: itemWouldGroup?.shouldBeGrouped,
- }
- );
- }
- addSuccessMessage('Sent analytic for similarity embeddings grouping');
- };
- render() {
- const {onMerge, project, location} = this.props;
- const {mergeCount} = this.state;
- const hasSimilarityEmbeddingsFeature =
- project?.features.includes('similarity-embeddings') ||
- location.query.similarityEmbeddings === '1';
- return (
- <PanelHeader hasButtons>
- <ButtonPanel>
- <Confirm
- disabled={mergeCount === 0}
- message={t('Are you sure you want to merge these issues?')}
- onConfirm={onMerge}
- >
- <Button size="xs" title={t('Merging %s issues', mergeCount)}>
- {t('Merge %s', `(${mergeCount || 0})`)}
- </Button>
- </Confirm>
- {hasSimilarityEmbeddingsFeature && (
- <Fragment>
- <Button
- disabled={mergeCount === 0}
- size="xs"
- title={t('Agree with the grouping of %s issues', mergeCount)}
- onClick={() => {
- this.handleSimilarityEmbeddings('Yes');
- }}
- >
- {t('Agree %s', `(${mergeCount || 0})`)}
- </Button>
- <Button
- disabled={mergeCount === 0}
- size="xs"
- title={t('Disagree with the grouping of %s issues', mergeCount)}
- onClick={() => {
- this.handleSimilarityEmbeddings('No');
- }}
- >
- {t('Disagree %s', `(${mergeCount || 0})`)}
- </Button>
- </Fragment>
- )}
- </ButtonPanel>
- <Columns>
- <StyledToolbarHeader>{t('Events')}</StyledToolbarHeader>
- <StyledToolbarHeader>{t('Exception')}</StyledToolbarHeader>
- <StyledToolbarHeader>{t('Message')}</StyledToolbarHeader>
- {hasSimilarityEmbeddingsFeature && (
- <StyledToolbarHeader>{t('Would Group')}</StyledToolbarHeader>
- )}
- </Columns>
- </PanelHeader>
- );
- }
- }
- export default SimilarToolbar;
- const Columns = styled('div')`
- display: flex;
- align-items: center;
- flex-shrink: 0;
- min-width: 350px;
- width: 350px;
- `;
- const StyledToolbarHeader = styled(ToolbarHeader)`
- flex: 1;
- flex-shrink: 0;
- display: flex;
- justify-content: center;
- padding: ${space(0.5)} 0;
- `;
- const ButtonPanel = styled('div')`
- display: flex;
- align-items: left;
- gap: ${space(1)};
- `;
|