import orderBy from 'lodash/orderBy'; import {bulkUpdate} from 'sentry/actionCreators/group'; import {Client} from 'sentry/api'; import {t, tct} from 'sentry/locale'; import {Group, GroupActivity} from 'sentry/types'; import {Event} from 'sentry/types/event'; /** * Fetches group data and mark as seen * * @param orgId organization slug * @param groupId groupId * @param eventId eventId or "latest" or "oldest" * @param envNames * @param projectId project slug required for eventId that is not latest or oldest */ export async function fetchGroupEvent( api: Client, orgId: string, groupId: string, eventId: string, envNames: string[], projectId?: string ): Promise { const url = eventId === 'latest' || eventId === 'oldest' ? `/issues/${groupId}/events/${eventId}/` : `/projects/${orgId}/${projectId}/events/${eventId}/?group_id=${groupId}`; const query: {environment?: string[]} = {}; if (envNames.length !== 0) { query.environment = envNames; } const data = await api.requestPromise(url, {query}); return data; } export function markEventSeen( api: Client, orgId: string, projectId: string, groupId: string ) { bulkUpdate( api, { orgId, projectId, itemIds: [groupId], failSilently: true, data: {hasSeen: true}, }, {} ); } export function fetchGroupUserReports(groupId: string, query: Record) { const api = new Client(); return api.requestPromise(`/issues/${groupId}/user-reports/`, { includeAllArgs: true, query, }); } /** * Returns the environment name for an event or null * * @param event */ export function getEventEnvironment(event: Event) { const tag = event.tags.find(({key}) => key === 'environment'); return tag ? tag.value : null; } const SUBSCRIPTION_REASONS = { commented: t( "You're receiving workflow notifications because you have commented on this issue." ), assigned: t( "You're receiving workflow notifications because you were assigned to this issue." ), bookmarked: t( "You're receiving workflow notifications because you have bookmarked this issue." ), changed_status: t( "You're receiving workflow notifications because you have changed the status of this issue." ), mentioned: t( "You're receiving workflow notifications because you have been mentioned in this issue." ), }; /** * @param group * @param removeLinks add/remove links to subscription reasons text (default: false) * @returns Reason for subscription */ export function getSubscriptionReason(group: Group, removeLinks = false) { if (group.subscriptionDetails && group.subscriptionDetails.disabled) { return tct('You have [link:disabled workflow notifications] for this project.', { link: removeLinks ? : , }); } if (!group.isSubscribed) { return t('Subscribe to workflow notifications for this issue'); } if (group.subscriptionDetails) { const {reason} = group.subscriptionDetails; if (reason === 'unknown') { return t( "You're receiving workflow notifications because you are subscribed to this issue." ); } if (reason && SUBSCRIPTION_REASONS.hasOwnProperty(reason)) { return SUBSCRIPTION_REASONS[reason]; } } return tct( "You're receiving updates because you are [link:subscribed to workflow notifications] for this project.", { link: removeLinks ? : , } ); } export function getGroupMostRecentActivity(activities: GroupActivity[]) { // Most recent activity return orderBy([...activities], ({dateCreated}) => new Date(dateCreated), ['desc'])[0]; } export enum ReprocessingStatus { REPROCESSED_AND_HASNT_EVENT = 'reprocessed_and_hasnt_event', REPROCESSED_AND_HAS_EVENT = 'reprocessed_and_has_event', REPROCESSING = 'reprocessing', NO_STATUS = 'no_status', } // Reprocessing Checks export function getGroupReprocessingStatus( group: Group, mostRecentActivity?: GroupActivity ) { const {status, count, activity: activities} = group; const groupCount = Number(count); switch (status) { case 'reprocessing': return ReprocessingStatus.REPROCESSING; case 'unresolved': { const groupMostRecentActivity = mostRecentActivity ?? getGroupMostRecentActivity(activities); if (groupMostRecentActivity?.type === 'reprocess') { if (groupCount === 0) { return ReprocessingStatus.REPROCESSED_AND_HASNT_EVENT; } return ReprocessingStatus.REPROCESSED_AND_HAS_EVENT; } return ReprocessingStatus.NO_STATUS; } default: return ReprocessingStatus.NO_STATUS; } }