import * as React from 'react'; import styled from '@emotion/styled'; import {openModal} from 'sentry/actionCreators/modal'; import ActionLink from 'sentry/components/actions/actionLink'; import ButtonBar from 'sentry/components/buttonBar'; import CustomResolutionModal from 'sentry/components/customResolutionModal'; import DropdownLink from 'sentry/components/dropdownLink'; import Tooltip from 'sentry/components/tooltip'; import {IconCheckmark, IconChevron} from 'sentry/icons'; import {t} from 'sentry/locale'; import { Organization, Release, ResolutionStatus, ResolutionStatusDetails, UpdateResolutionStatus, } from 'sentry/types'; import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent'; import {formatVersion} from 'sentry/utils/formatters'; import withOrganization from 'sentry/utils/withOrganization'; import ActionButton from './button'; import MenuHeader from './menuHeader'; import MenuItemActionLink from './menuItemActionLink'; const defaultProps = { isResolved: false, isAutoResolved: false, confirmLabel: t('Resolve'), }; type Props = { organization: Organization; hasRelease: boolean; onUpdate: (data: UpdateResolutionStatus) => void; orgSlug: string; latestRelease?: Release; projectSlug?: string; shouldConfirm?: boolean; confirmMessage?: React.ReactNode; disabled?: boolean; disableDropdown?: boolean; projectFetchError?: boolean; } & Partial; class ResolveActions extends React.Component { static defaultProps = defaultProps; handleAnotherExistingReleaseResolution(statusDetails: ResolutionStatusDetails) { const {organization, onUpdate} = this.props; onUpdate({ status: ResolutionStatus.RESOLVED, statusDetails, }); trackAdvancedAnalyticsEvent('resolve_issue', { organization, release: 'anotherExisting', }); } handleCurrentReleaseResolution = () => { const {onUpdate, organization, hasRelease, latestRelease} = this.props; hasRelease && onUpdate({ status: ResolutionStatus.RESOLVED, statusDetails: { inRelease: latestRelease ? latestRelease.version : 'latest', }, }); trackAdvancedAnalyticsEvent('resolve_issue', { organization, release: 'current', }); }; handleNextReleaseResolution = () => { const {onUpdate, organization, hasRelease} = this.props; hasRelease && onUpdate({ status: ResolutionStatus.RESOLVED, statusDetails: { inNextRelease: true, }, }); trackAdvancedAnalyticsEvent('resolve_issue', { organization, release: 'next', }); }; renderResolved() { const {isAutoResolved, onUpdate} = this.props; return ( } label={t('Unresolve')} disabled={isAutoResolved} onClick={() => onUpdate({status: ResolutionStatus.UNRESOLVED})} /> ); } renderDropdownMenu() { const { projectSlug, isResolved, hasRelease, latestRelease, confirmMessage, shouldConfirm, disabled, confirmLabel, disableDropdown, } = this.props; if (isResolved) { return this.renderResolved(); } const actionTitle = !hasRelease ? t('Set up release tracking in order to use this feature.') : ''; const actionLinkProps = { shouldConfirm, message: confirmMessage, confirmLabel, disabled: disabled || !hasRelease, }; return ( } /> } caret={false} alwaysRenderMenu disabled={!projectSlug ? disabled : disableDropdown} > {t('Resolved In')} {t('The next release')} {latestRelease ? t('The current release (%s)', formatVersion(latestRelease.version)) : t('The current release')} hasRelease && this.openCustomReleaseModal()} shouldConfirm={false} > {t('Another existing release')} ); } openCustomReleaseModal() { const {orgSlug, projectSlug} = this.props; openModal(deps => ( this.handleAnotherExistingReleaseResolution(statusDetails) } orgSlug={orgSlug} projectSlug={projectSlug} /> )); } render() { const { isResolved, onUpdate, confirmMessage, shouldConfirm, disabled, confirmLabel, projectFetchError, } = this.props; if (isResolved) { return this.renderResolved(); } const actionLinkProps = { shouldConfirm, message: confirmMessage, confirmLabel, disabled, }; return ( } onAction={() => onUpdate({status: ResolutionStatus.RESOLVED})} hasDropdown > {t('Resolve')} {this.renderDropdownMenu()} ); } } export default withOrganization(ResolveActions); const StyledActionButton = styled(ActionButton)` box-shadow: none; `;