index.tsx 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137
  1. // XXX(epurkhiser): When we switch to the new React JSX runtime we will no
  2. // longer need this import and can drop babel-preset-css-prop for babel-preset.
  3. /// <reference types="@emotion/react/types/css-prop" />
  4. import {FocusTrap} from 'focus-trap';
  5. import u2f from 'u2f-api';
  6. import exportGlobals from 'app/bootstrap/exportGlobals';
  7. import Alert from 'app/components/alert';
  8. import {getInterval} from 'app/components/charts/utils';
  9. import {SymbolicatorStatus} from 'app/components/events/interfaces/types';
  10. import {API_ACCESS_SCOPES, DEFAULT_RELATIVE_PERIODS} from 'app/constants';
  11. import {PlatformKey} from 'app/data/platformCategories';
  12. import {OrgExperiments, UserExperiments} from 'app/types/experiments';
  13. import {
  14. INSTALLED,
  15. NOT_INSTALLED,
  16. PENDING,
  17. } from 'app/views/organizationIntegrations/constants';
  18. import {Field} from 'app/views/settings/components/forms/type';
  19. import {DynamicSamplingRules} from './dynamicSampling';
  20. import {Event} from './event';
  21. import {Mechanism, RawStacktrace, StacktraceType} from './stacktrace';
  22. export enum SentryInitRenderReactComponent {
  23. INDICATORS = 'Indicators',
  24. SETUP_WIZARD = 'SetupWizard',
  25. SYSTEM_ALERTS = 'SystemAlerts',
  26. U2F_SIGN = 'U2fSign',
  27. }
  28. export type OnSentryInitConfiguration =
  29. | {
  30. name: 'passwordStrength';
  31. input: string;
  32. element: string;
  33. }
  34. | {
  35. name: 'renderReact';
  36. container: string;
  37. component: SentryInitRenderReactComponent;
  38. props?: Record<string, any>;
  39. }
  40. | {
  41. name: 'onReady';
  42. onReady: (globals: typeof exportGlobals) => void;
  43. };
  44. declare global {
  45. interface Window {
  46. /**
  47. * Assets public location
  48. */
  49. __sentryGlobalStaticPrefix: string;
  50. /**
  51. * The config object provided by the backend.
  52. */
  53. __initialData: Config;
  54. /**
  55. * Pipeline
  56. */
  57. __pipelineInitialData: PipelineInitialData;
  58. /**
  59. * This allows our server-rendered templates to push configuration that should be
  60. * run after we render our main application.
  61. *
  62. * An example of this is dynamically importing the `passwordStrength` module only
  63. * on the organization login page.
  64. */
  65. __onSentryInit:
  66. | OnSentryInitConfiguration[]
  67. | {
  68. push: (config: OnSentryInitConfiguration) => void;
  69. };
  70. /**
  71. * Sentrys version string
  72. */
  73. __SENTRY__VERSION?: string;
  74. /**
  75. * The CSRF cookie ised on the backend
  76. */
  77. csrfCookieName?: string;
  78. /**
  79. * Used to open tooltips for testing purposes.
  80. */
  81. __openAllTooltips: () => void;
  82. /**
  83. * Used to close tooltips for testing purposes.
  84. */
  85. __closeAllTooltips: () => void;
  86. /**
  87. * Primary entrypoint for rendering the sentry app. This is typically
  88. * called in the django templates, or in the case of the EXPERIMENTAL_SPA,
  89. * after config hydration.
  90. */
  91. SentryRenderApp: () => void;
  92. sentryEmbedCallback?: ((embed: any) => void) | null;
  93. /**
  94. * Set to true if adblock could be installed.
  95. * See sentry/js/ads.js for how this global is disabled.
  96. */
  97. adblockSuspected?: boolean;
  98. // typing currently used for demo add on
  99. // TODO: improve typing
  100. SentryApp?: {
  101. HookStore: any;
  102. ConfigStore: any;
  103. Modal: any;
  104. modalFocusTrap?: {
  105. current?: FocusTrap;
  106. };
  107. getModalPortal: () => HTMLElement;
  108. };
  109. }
  110. }
  111. export type PipelineInitialData = {
  112. name: string;
  113. props: Record<string, any>;
  114. };
  115. export type IntegrationInstallationStatus =
  116. | typeof INSTALLED
  117. | typeof NOT_INSTALLED
  118. | typeof PENDING;
  119. export type SentryAppStatus = 'unpublished' | 'published' | 'internal';
  120. export type ObjectStatus =
  121. | 'active'
  122. | 'disabled'
  123. | 'pending_deletion'
  124. | 'deletion_in_progress';
  125. export type Avatar = {
  126. avatarUuid: string | null;
  127. avatarType: 'letter_avatar' | 'upload' | 'gravatar' | 'background';
  128. };
  129. export type Actor = {
  130. type: 'user' | 'team';
  131. id: string;
  132. name: string;
  133. email?: string;
  134. };
  135. /**
  136. * Organization summaries are sent when you request a
  137. * list of all organizations
  138. */
  139. export type OrganizationSummary = {
  140. status: {
  141. // TODO(ts): Are these fields == `ObjectStatus`?
  142. id: string;
  143. name: string;
  144. };
  145. require2FA: boolean;
  146. avatar: Avatar;
  147. features: string[];
  148. name: string;
  149. dateCreated: string;
  150. id: string;
  151. isEarlyAdopter: boolean;
  152. slug: string;
  153. };
  154. export type Relay = {
  155. publicKey: string;
  156. name: string;
  157. created?: string;
  158. lastModified?: string;
  159. description?: string;
  160. };
  161. export type RelayActivity = {
  162. publicKey: string;
  163. relayId: string;
  164. version: string;
  165. firstSeen: string;
  166. lastSeen: string;
  167. };
  168. export type RelaysByPublickey = {
  169. [publicKey: string]: {
  170. name: string;
  171. activities: Array<RelayActivity>;
  172. description?: string;
  173. created?: string;
  174. };
  175. };
  176. /**
  177. * Detailed organization (e.g. when requesting details for a single org)
  178. *
  179. * Lightweight in this case means it does not contain `projects` or `teams`
  180. */
  181. export type LightWeightOrganization = OrganizationSummary & {
  182. relayPiiConfig: string;
  183. scrubIPAddresses: boolean;
  184. attachmentsRole: string;
  185. debugFilesRole: string;
  186. eventsMemberAdmin: boolean;
  187. alertsMemberWrite: boolean;
  188. sensitiveFields: string[];
  189. openMembership: boolean;
  190. quota: {
  191. maxRateInterval: number | null;
  192. projectLimit: number | null;
  193. accountLimit: number | null;
  194. maxRate: number | null;
  195. };
  196. defaultRole: string;
  197. experiments: Partial<OrgExperiments>;
  198. allowJoinRequests: boolean;
  199. scrapeJavaScript: boolean;
  200. isDefault: boolean;
  201. pendingAccessRequests: number;
  202. availableRoles: {id: string; name: string}[];
  203. enhancedPrivacy: boolean;
  204. safeFields: string[];
  205. storeCrashReports: number;
  206. access: Scope[];
  207. allowSharedIssues: boolean;
  208. dataScrubberDefaults: boolean;
  209. dataScrubber: boolean;
  210. apdexThreshold: number;
  211. onboardingTasks: OnboardingTaskStatus[];
  212. trustedRelays: Relay[];
  213. role?: string;
  214. };
  215. /**
  216. * Full organization details
  217. */
  218. export type Organization = LightWeightOrganization & {
  219. projects: Project[];
  220. teams: Team[];
  221. };
  222. /**
  223. * Minimal organization shape used on shared issue views.
  224. */
  225. export type SharedViewOrganization = {
  226. slug: string;
  227. id?: string;
  228. features?: Array<string>;
  229. };
  230. // Minimal project representation for use with avatars.
  231. export type AvatarProject = {
  232. slug: string;
  233. platform?: PlatformKey;
  234. id?: string | number;
  235. };
  236. /**
  237. * Simple timeseries data used in groups, projects and release health.
  238. */
  239. export type TimeseriesValue = [timestamp: number, value: number];
  240. export type Project = {
  241. id: string;
  242. dateCreated: string;
  243. isMember: boolean;
  244. teams: Team[];
  245. features: string[];
  246. organization: Organization;
  247. isBookmarked: boolean;
  248. isInternal: boolean;
  249. hasUserReports?: boolean;
  250. hasAccess: boolean;
  251. firstEvent: 'string' | null;
  252. firstTransactionEvent: boolean;
  253. subjectTemplate: string;
  254. digestsMaxDelay: number;
  255. digestsMinDelay: number;
  256. environments: string[];
  257. // XXX: These are part of the DetailedProject serializer
  258. dynamicSampling: {
  259. next_id: number;
  260. rules: DynamicSamplingRules;
  261. } | null;
  262. plugins: Plugin[];
  263. processingIssues: number;
  264. relayPiiConfig: string;
  265. groupingConfig: string;
  266. latestDeploys?: Record<string, Pick<Deploy, 'dateFinished' | 'version'>> | null;
  267. builtinSymbolSources?: string[];
  268. symbolSources?: string;
  269. stats?: TimeseriesValue[];
  270. transactionStats?: TimeseriesValue[];
  271. latestRelease?: Release;
  272. options?: Record<string, boolean | string>;
  273. sessionStats?: {
  274. currentCrashFreeRate: number | null;
  275. previousCrashFreeRate: number | null;
  276. hasHealthData: boolean;
  277. };
  278. } & AvatarProject;
  279. export type MinimalProject = Pick<Project, 'id' | 'slug' | 'platform'>;
  280. // Response from project_keys endpoints.
  281. export type ProjectKey = {
  282. id: string;
  283. name: string;
  284. label: string;
  285. public: string;
  286. secret: string;
  287. projectId: string;
  288. isActive: boolean;
  289. rateLimit: {
  290. window: string;
  291. count: number;
  292. } | null;
  293. dsn: {
  294. secret: string;
  295. public: string;
  296. csp: string;
  297. security: string;
  298. minidump: string;
  299. unreal: string;
  300. cdn: string;
  301. };
  302. browserSdkVersion: string;
  303. browserSdk: {
  304. choices: [key: string, value: string][];
  305. };
  306. dateCreated: string;
  307. };
  308. export type Health = {
  309. totalUsers: number;
  310. totalUsers24h: number | null;
  311. totalProjectUsers24h: number | null;
  312. totalSessions: number;
  313. totalSessions24h: number | null;
  314. totalProjectSessions24h: number | null;
  315. crashFreeUsers: number | null;
  316. crashFreeSessions: number | null;
  317. stats: HealthGraphData;
  318. sessionsCrashed: number;
  319. sessionsErrored: number;
  320. adoption: number | null;
  321. sessionsAdoption: number | null;
  322. hasHealthData: boolean;
  323. durationP50: number | null;
  324. durationP90: number | null;
  325. };
  326. export type HealthGraphData = Record<string, TimeseriesValue[]>;
  327. export type Team = {
  328. id: string;
  329. name: string;
  330. slug: string;
  331. isMember: boolean;
  332. hasAccess: boolean;
  333. isPending: boolean;
  334. memberCount: number;
  335. avatar: Avatar;
  336. externalTeams: ExternalTeam[];
  337. };
  338. export type TeamWithProjects = Team & {projects: Project[]};
  339. // This type is incomplete
  340. export type EventMetadata = {
  341. value?: string;
  342. message?: string;
  343. directive?: string;
  344. type?: string;
  345. title?: string;
  346. uri?: string;
  347. filename?: string;
  348. origin?: string;
  349. function?: string;
  350. stripped_crash?: boolean;
  351. };
  352. export type EventAttachment = {
  353. id: string;
  354. dateCreated: string;
  355. headers: Object;
  356. mimetype: string;
  357. name: string;
  358. sha1: string;
  359. size: number;
  360. type: string;
  361. event_id: string;
  362. };
  363. export type EntryData = Record<string, any | Array<any>>;
  364. type EnableIntegrationSuggestion = {
  365. type: 'enableIntegration';
  366. integrationName: string;
  367. enables: Array<SDKUpdatesSuggestion>;
  368. integrationUrl?: string | null;
  369. };
  370. type UpdateSdkSuggestion = {
  371. type: 'updateSdk';
  372. sdkName: string;
  373. newSdkVersion: string;
  374. enables: Array<SDKUpdatesSuggestion>;
  375. sdkUrl?: string | null;
  376. };
  377. type ChangeSdkSuggestion = {
  378. type: 'changeSdk';
  379. newSdkName: string;
  380. enables: Array<SDKUpdatesSuggestion>;
  381. sdkUrl?: string | null;
  382. };
  383. export type SDKUpdatesSuggestion =
  384. | EnableIntegrationSuggestion
  385. | UpdateSdkSuggestion
  386. | ChangeSdkSuggestion;
  387. export type ProjectSdkUpdates = {
  388. projectId: string;
  389. sdkName: string;
  390. sdkVersion: string;
  391. suggestions: SDKUpdatesSuggestion[];
  392. };
  393. export type EventsStatsData = [number, {count: number}[]][];
  394. // API response format for a single series
  395. export type EventsStats = {
  396. data: EventsStatsData;
  397. totals?: {count: number};
  398. order?: number;
  399. };
  400. // API response format for multiple series
  401. export type MultiSeriesEventsStats = {[seriesName: string]: EventsStats};
  402. /**
  403. * Avatars are a more primitive version of User.
  404. */
  405. export type AvatarUser = {
  406. id: string;
  407. name: string;
  408. username: string;
  409. email: string;
  410. avatarUrl?: string;
  411. avatar?: Avatar;
  412. ip_address: string;
  413. // Compatibility shim with EventUser serializer
  414. ipAddress?: string;
  415. options?: {
  416. avatarType: Avatar['avatarType'];
  417. };
  418. lastSeen?: string;
  419. };
  420. /**
  421. * This is an authenticator that a user is enrolled in
  422. */
  423. type UserEnrolledAuthenticator = {
  424. dateUsed: EnrolledAuthenticator['lastUsedAt'];
  425. dateCreated: EnrolledAuthenticator['createdAt'];
  426. type: Authenticator['id'];
  427. id: EnrolledAuthenticator['authId'];
  428. };
  429. export type User = Omit<AvatarUser, 'options'> & {
  430. lastLogin: string;
  431. isSuperuser: boolean;
  432. isAuthenticated: boolean;
  433. emails: {
  434. is_verified: boolean;
  435. id: string;
  436. email: string;
  437. }[];
  438. isManaged: boolean;
  439. lastActive: string;
  440. isStaff: boolean;
  441. identities: any[];
  442. isActive: boolean;
  443. has2fa: boolean;
  444. canReset2fa: boolean;
  445. authenticators: UserEnrolledAuthenticator[];
  446. dateJoined: string;
  447. options: {
  448. theme: 'system' | 'light' | 'dark';
  449. timezone: string;
  450. stacktraceOrder: number;
  451. language: string;
  452. clock24Hours: boolean;
  453. avatarType: Avatar['avatarType'];
  454. };
  455. flags: {newsletter_consent_prompt: boolean};
  456. hasPasswordAuth: boolean;
  457. permissions: Set<string>;
  458. experiments: Partial<UserExperiments>;
  459. };
  460. // XXX(epurkhiser): we should understand how this is diff from User['emails]
  461. // above
  462. export type UserEmail = {
  463. email: string;
  464. isPrimary: boolean;
  465. isVerified: boolean;
  466. };
  467. export type CommitAuthor = {
  468. email?: string;
  469. name?: string;
  470. };
  471. export type Environment = {
  472. id: string;
  473. displayName: string;
  474. name: string;
  475. // XXX: Provided by the backend but unused due to `getUrlRoutingName()`
  476. // urlRoutingName: string;
  477. };
  478. export type RecentSearch = {
  479. id: string;
  480. organizationId: string;
  481. type: SavedSearchType;
  482. query: string;
  483. lastSeen: string;
  484. dateCreated: string;
  485. };
  486. // XXX: Deprecated Sentry 9 attributes are not included here.
  487. export type SavedSearch = {
  488. id: string;
  489. type: SavedSearchType;
  490. name: string;
  491. query: string;
  492. sort: string;
  493. isGlobal: boolean;
  494. isPinned: boolean;
  495. isOrgCustom: boolean;
  496. dateCreated: string;
  497. };
  498. export enum SavedSearchType {
  499. ISSUE = 0,
  500. EVENT = 1,
  501. }
  502. export type PluginNoProject = {
  503. id: string;
  504. name: string;
  505. slug: string;
  506. shortName: string;
  507. type: string;
  508. canDisable: boolean;
  509. isTestable: boolean;
  510. hasConfiguration: boolean;
  511. metadata: any; // TODO(ts)
  512. contexts: any[]; // TODO(ts)
  513. status: string;
  514. assets: Array<{url: string}>;
  515. doc: string;
  516. features: string[];
  517. featureDescriptions: IntegrationFeature[];
  518. isHidden: boolean;
  519. version?: string;
  520. author?: {name: string; url: string};
  521. description?: string;
  522. resourceLinks?: Array<{title: string; url: string}>;
  523. };
  524. export type Plugin = PluginNoProject & {
  525. enabled: boolean;
  526. };
  527. export type PluginProjectItem = {
  528. projectId: string;
  529. projectSlug: string;
  530. projectName: string;
  531. projectPlatform: PlatformKey;
  532. enabled: boolean;
  533. configured: boolean;
  534. };
  535. export type PluginWithProjectList = PluginNoProject & {
  536. projectList: PluginProjectItem[];
  537. };
  538. export type AppOrProviderOrPlugin =
  539. | SentryApp
  540. | IntegrationProvider
  541. | PluginWithProjectList
  542. | DocumentIntegration;
  543. export type IntegrationType = 'document' | 'plugin' | 'first_party' | 'sentry_app';
  544. export type DocumentIntegration = {
  545. slug: string;
  546. name: string;
  547. author: string;
  548. docUrl: string;
  549. description: string;
  550. features: IntegrationFeature[];
  551. resourceLinks: Array<{title: string; url: string}>;
  552. };
  553. export type DateString = Date | string | null;
  554. export type RelativePeriod = keyof typeof DEFAULT_RELATIVE_PERIODS;
  555. export type IntervalPeriod = ReturnType<typeof getInterval>;
  556. export type GlobalSelection = {
  557. projects: number[];
  558. environments: string[];
  559. datetime: {
  560. start: DateString;
  561. end: DateString;
  562. period: RelativePeriod | string;
  563. utc: boolean | null;
  564. };
  565. };
  566. export type AuthenticatorDevice = {
  567. key_handle: string;
  568. authId: string;
  569. name: string;
  570. timestamp?: string;
  571. };
  572. export type Authenticator = {
  573. /**
  574. * String used to display on button for user as CTA to enroll
  575. */
  576. enrollButton: string;
  577. /**
  578. * Display name for the authenticator
  579. */
  580. name: string;
  581. /**
  582. * Allows multiple enrollments to authenticator
  583. */
  584. allowMultiEnrollment: boolean;
  585. /**
  586. * String to display on button for user to remove authenticator
  587. */
  588. removeButton: string | null;
  589. canValidateOtp: boolean;
  590. /**
  591. * Is user enrolled to this authenticator
  592. */
  593. isEnrolled: boolean;
  594. /**
  595. * String to display on button for additional information about authenticator
  596. */
  597. configureButton: string;
  598. /**
  599. * Is this used as a backup interface?
  600. */
  601. isBackupInterface: boolean;
  602. /**
  603. * Description of the authenticator
  604. */
  605. description: string;
  606. createdAt: string | null;
  607. lastUsedAt: string | null;
  608. codes: string[];
  609. devices: AuthenticatorDevice[];
  610. phone?: string;
  611. secret?: string;
  612. /**
  613. * The form configuration for the authenticator is present during enrollment
  614. */
  615. form?: Field[];
  616. } & Partial<EnrolledAuthenticator> &
  617. (
  618. | {
  619. id: 'sms';
  620. }
  621. | {
  622. id: 'totp';
  623. qrcode: string;
  624. }
  625. | {
  626. id: 'u2f';
  627. challenge: ChallengeData;
  628. }
  629. );
  630. export type ChallengeData = {
  631. authenticateRequests: u2f.SignRequest;
  632. registerRequests: u2f.RegisterRequest;
  633. };
  634. export type EnrolledAuthenticator = {
  635. lastUsedAt: string | null;
  636. createdAt: string;
  637. authId: string;
  638. };
  639. export interface Config {
  640. theme: 'light' | 'dark';
  641. languageCode: string;
  642. csrfCookieName: string;
  643. features: Set<string>;
  644. singleOrganization: boolean;
  645. urlPrefix: string;
  646. needsUpgrade: boolean;
  647. supportEmail: string;
  648. user: User;
  649. invitesEnabled: boolean;
  650. privacyUrl: string | null;
  651. isOnPremise: boolean;
  652. lastOrganization: string | null;
  653. gravatarBaseUrl: string;
  654. /**
  655. * This comes from django (django.contrib.messages)
  656. */
  657. messages: {message: string; level: string}[];
  658. dsn: string;
  659. userIdentity: {ip_address: string; email: string; id: string; isStaff: boolean};
  660. termsUrl: string | null;
  661. isAuthenticated: boolean;
  662. version: {
  663. current: string;
  664. build: string;
  665. upgradeAvailable: boolean;
  666. latest: string;
  667. };
  668. statuspage?: {
  669. id: string;
  670. api_host: string;
  671. };
  672. sentryConfig: {
  673. dsn: string;
  674. release: string;
  675. whitelistUrls: string[];
  676. };
  677. distPrefix: string;
  678. apmSampling: number;
  679. dsn_requests: string;
  680. demoMode: boolean;
  681. }
  682. // https://github.com/getsentry/relay/blob/master/relay-common/src/constants.rs
  683. // Note: the value of the enum on the frontend is plural,
  684. // but the value of the enum on the backend is singular
  685. export enum DataCategory {
  686. DEFAULT = 'default',
  687. ERRORS = 'errors',
  688. TRANSACTIONS = 'transactions',
  689. ATTACHMENTS = 'attachments',
  690. }
  691. export const DataCategoryName = {
  692. [DataCategory.ERRORS]: 'Errors',
  693. [DataCategory.TRANSACTIONS]: 'Transactions',
  694. [DataCategory.ATTACHMENTS]: 'Attachments',
  695. };
  696. export type EventOrGroupType =
  697. | 'error'
  698. | 'csp'
  699. | 'hpkp'
  700. | 'expectct'
  701. | 'expectstaple'
  702. | 'default'
  703. | 'transaction';
  704. export type InboxReasonDetails = {
  705. until?: string | null;
  706. count?: number | null;
  707. window?: number | null;
  708. user_count?: number | null;
  709. user_window?: number | null;
  710. };
  711. export type InboxDetails = {
  712. reason_details: InboxReasonDetails;
  713. date_added?: string;
  714. reason?: number;
  715. };
  716. export type SuggestedOwnerReason = 'suspectCommit' | 'ownershipRule';
  717. // Received from the backend to denote suggested owners of an issue
  718. export type SuggestedOwner = {
  719. type: SuggestedOwnerReason;
  720. owner: string;
  721. date_added: string;
  722. };
  723. export enum GroupActivityType {
  724. NOTE = 'note',
  725. SET_RESOLVED = 'set_resolved',
  726. SET_RESOLVED_BY_AGE = 'set_resolved_by_age',
  727. SET_RESOLVED_IN_RELEASE = 'set_resolved_in_release',
  728. SET_RESOLVED_IN_COMMIT = 'set_resolved_in_commit',
  729. SET_RESOLVED_IN_PULL_REQUEST = 'set_resolved_in_pull_request',
  730. SET_UNRESOLVED = 'set_unresolved',
  731. SET_IGNORED = 'set_ignored',
  732. SET_PUBLIC = 'set_public',
  733. SET_PRIVATE = 'set_private',
  734. SET_REGRESSION = 'set_regression',
  735. CREATE_ISSUE = 'create_issue',
  736. UNMERGE_SOURCE = 'unmerge_source',
  737. UNMERGE_DESTINATION = 'unmerge_destination',
  738. FIRST_SEEN = 'first_seen',
  739. ASSIGNED = 'assigned',
  740. UNASSIGNED = 'unassigned',
  741. MERGE = 'merge',
  742. REPROCESS = 'reprocess',
  743. MARK_REVIEWED = 'mark_reviewed',
  744. }
  745. type GroupActivityBase = {
  746. dateCreated: string;
  747. id: string;
  748. project: Project;
  749. user?: null | User;
  750. assignee?: string;
  751. issue?: Group;
  752. };
  753. type GroupActivityNote = GroupActivityBase & {
  754. type: GroupActivityType.NOTE;
  755. data: {
  756. text: string;
  757. };
  758. };
  759. type GroupActivitySetResolved = GroupActivityBase & {
  760. type: GroupActivityType.SET_RESOLVED;
  761. data: Record<string, any>;
  762. };
  763. type GroupActivitySetUnresolved = GroupActivityBase & {
  764. type: GroupActivityType.SET_UNRESOLVED;
  765. data: Record<string, any>;
  766. };
  767. type GroupActivitySetPublic = GroupActivityBase & {
  768. type: GroupActivityType.SET_PUBLIC;
  769. data: Record<string, any>;
  770. };
  771. type GroupActivitySetPrivate = GroupActivityBase & {
  772. type: GroupActivityType.SET_PRIVATE;
  773. data: Record<string, any>;
  774. };
  775. type GroupActivitySetByAge = GroupActivityBase & {
  776. type: GroupActivityType.SET_RESOLVED_BY_AGE;
  777. data: Record<string, any>;
  778. };
  779. type GroupActivityUnassigned = GroupActivityBase & {
  780. type: GroupActivityType.UNASSIGNED;
  781. data: Record<string, any>;
  782. };
  783. type GroupActivityFirstSeen = GroupActivityBase & {
  784. type: GroupActivityType.FIRST_SEEN;
  785. data: Record<string, any>;
  786. };
  787. type GroupActivityMarkReviewed = GroupActivityBase & {
  788. type: GroupActivityType.MARK_REVIEWED;
  789. data: Record<string, any>;
  790. };
  791. type GroupActivityRegression = GroupActivityBase & {
  792. type: GroupActivityType.SET_REGRESSION;
  793. data: {
  794. version?: string;
  795. };
  796. };
  797. type GroupActivitySetByResolvedInRelease = GroupActivityBase & {
  798. type: GroupActivityType.SET_RESOLVED_IN_RELEASE;
  799. data: {
  800. version?: string;
  801. };
  802. };
  803. type GroupActivitySetByResolvedInCommit = GroupActivityBase & {
  804. type: GroupActivityType.SET_RESOLVED_IN_COMMIT;
  805. data: {
  806. commit: Commit;
  807. };
  808. };
  809. type GroupActivitySetByResolvedInPullRequest = GroupActivityBase & {
  810. type: GroupActivityType.SET_RESOLVED_IN_PULL_REQUEST;
  811. data: {
  812. pullRequest: PullRequest;
  813. };
  814. };
  815. export type GroupActivitySetIgnored = GroupActivityBase & {
  816. type: GroupActivityType.SET_IGNORED;
  817. data: {
  818. ignoreDuration?: number;
  819. ignoreUntil?: string;
  820. ignoreUserCount?: number;
  821. ignoreUserWindow?: number;
  822. ignoreWindow?: number;
  823. ignoreCount?: number;
  824. };
  825. };
  826. export type GroupActivityReprocess = GroupActivityBase & {
  827. type: GroupActivityType.REPROCESS;
  828. data: {
  829. eventCount: number;
  830. newGroupId: number;
  831. oldGroupId: number;
  832. };
  833. };
  834. type GroupActivityUnmergeDestination = GroupActivityBase & {
  835. type: GroupActivityType.UNMERGE_DESTINATION;
  836. data: {
  837. fingerprints: Array<string>;
  838. source?: {
  839. id: string;
  840. shortId: string;
  841. };
  842. };
  843. };
  844. type GroupActivityUnmergeSource = GroupActivityBase & {
  845. type: GroupActivityType.UNMERGE_SOURCE;
  846. data: {
  847. fingerprints: Array<string>;
  848. destination?: {
  849. id: string;
  850. shortId: string;
  851. };
  852. };
  853. };
  854. type GroupActivityMerge = GroupActivityBase & {
  855. type: GroupActivityType.MERGE;
  856. data: {
  857. issues: Array<any>;
  858. };
  859. };
  860. export type GroupActivityAssigned = GroupActivityBase & {
  861. type: GroupActivityType.ASSIGNED;
  862. data: {
  863. assignee: string;
  864. assigneeType: string;
  865. user: Team | User;
  866. };
  867. };
  868. export type GroupActivityCreateIssue = GroupActivityBase & {
  869. type: GroupActivityType.CREATE_ISSUE;
  870. data: {
  871. provider: string;
  872. location: string;
  873. title: string;
  874. };
  875. };
  876. export type GroupActivity =
  877. | GroupActivityNote
  878. | GroupActivitySetResolved
  879. | GroupActivitySetUnresolved
  880. | GroupActivitySetIgnored
  881. | GroupActivitySetByAge
  882. | GroupActivitySetByResolvedInRelease
  883. | GroupActivitySetByResolvedInRelease
  884. | GroupActivitySetByResolvedInCommit
  885. | GroupActivitySetByResolvedInPullRequest
  886. | GroupActivityFirstSeen
  887. | GroupActivityMerge
  888. | GroupActivityReprocess
  889. | GroupActivityUnassigned
  890. | GroupActivityMarkReviewed
  891. | GroupActivityUnmergeDestination
  892. | GroupActivitySetPublic
  893. | GroupActivitySetPrivate
  894. | GroupActivityRegression
  895. | GroupActivityUnmergeSource
  896. | GroupActivityAssigned
  897. | GroupActivityCreateIssue;
  898. export type Activity = GroupActivity;
  899. type GroupFiltered = {
  900. count: string;
  901. stats: Record<string, TimeseriesValue[]>;
  902. lastSeen: string;
  903. firstSeen: string;
  904. userCount: number;
  905. };
  906. export type GroupStats = GroupFiltered & {
  907. lifetime?: GroupFiltered;
  908. filtered: GroupFiltered | null;
  909. sessionCount?: string | null;
  910. id: string;
  911. };
  912. export type BaseGroupStatusReprocessing = {
  913. status: 'reprocessing';
  914. statusDetails: {
  915. pendingEvents: number;
  916. info: {
  917. dateCreated: string;
  918. totalEvents: number;
  919. };
  920. };
  921. };
  922. type BaseGroupStatusResolution = {
  923. status: ResolutionStatus;
  924. statusDetails: ResolutionStatusDetails;
  925. };
  926. export type GroupRelease = {
  927. firstRelease: Release;
  928. lastRelease: Release;
  929. };
  930. // TODO(ts): incomplete
  931. export type BaseGroup = {
  932. id: string;
  933. latestEvent: Event;
  934. activity: GroupActivity[];
  935. annotations: string[];
  936. assignedTo: Actor;
  937. culprit: string;
  938. firstSeen: string;
  939. hasSeen: boolean;
  940. isBookmarked: boolean;
  941. isUnhandled: boolean;
  942. isPublic: boolean;
  943. isSubscribed: boolean;
  944. lastSeen: string;
  945. level: Level;
  946. logger: string;
  947. metadata: EventMetadata;
  948. numComments: number;
  949. participants: User[];
  950. permalink: string;
  951. platform: PlatformKey;
  952. pluginActions: any[]; // TODO(ts)
  953. pluginContexts: any[]; // TODO(ts)
  954. pluginIssues: any[]; // TODO(ts)
  955. project: Project;
  956. seenBy: User[];
  957. shareId: string;
  958. shortId: string;
  959. tags: Pick<Tag, 'key' | 'name' | 'totalValues'>[];
  960. title: string;
  961. type: EventOrGroupType;
  962. userReportCount: number;
  963. subscriptionDetails: {disabled?: boolean; reason?: string} | null;
  964. status: string;
  965. inbox?: InboxDetails | null | false;
  966. owners?: SuggestedOwner[] | null;
  967. } & GroupRelease;
  968. export type GroupReprocessing = BaseGroup & GroupStats & BaseGroupStatusReprocessing;
  969. export type GroupResolution = BaseGroup & GroupStats & BaseGroupStatusResolution;
  970. export type Group = GroupResolution | GroupReprocessing;
  971. export type GroupCollapseRelease = Omit<Group, keyof GroupRelease> &
  972. Partial<GroupRelease>;
  973. export type GroupTombstone = {
  974. id: string;
  975. title: string;
  976. culprit: string;
  977. level: Level;
  978. actor: AvatarUser;
  979. metadata: EventMetadata;
  980. };
  981. export type ProcessingIssueItem = {
  982. id: string;
  983. type: string;
  984. checksum: string;
  985. numEvents: number;
  986. data: {
  987. // TODO(ts) This type is likely incomplete, but this is what
  988. // project processing issues settings uses.
  989. _scope: string;
  990. image_arch: string;
  991. image_uuid: string;
  992. image_path: string;
  993. };
  994. lastSeen: string;
  995. };
  996. export type ProcessingIssue = {
  997. project: string;
  998. numIssues: number;
  999. signedLink: string;
  1000. lastSeen: string;
  1001. hasMoreResolveableIssues: boolean;
  1002. hasIssues: boolean;
  1003. issuesProcessing: number;
  1004. resolveableIssues: number;
  1005. issues?: ProcessingIssueItem[];
  1006. };
  1007. /**
  1008. * Returned from /organizations/org/users/
  1009. */
  1010. export type Member = {
  1011. dateCreated: string;
  1012. email: string;
  1013. expired: boolean;
  1014. flags: {
  1015. 'sso:linked': boolean;
  1016. 'sso:invalid': boolean;
  1017. 'member-limit:restricted': boolean;
  1018. };
  1019. id: string;
  1020. inviteStatus: 'approved' | 'requested_to_be_invited' | 'requested_to_join';
  1021. invite_link: string | null;
  1022. inviterName: string | null;
  1023. isOnlyOwner: boolean;
  1024. name: string;
  1025. pending: boolean | undefined;
  1026. projects: string[];
  1027. role: string;
  1028. roleName: string;
  1029. roles: MemberRole[]; // TODO(ts): This is not present from API call
  1030. teams: string[];
  1031. user: User;
  1032. };
  1033. export type AccessRequest = {
  1034. id: string;
  1035. team: Team;
  1036. member: Member;
  1037. requester?: Partial<{
  1038. name: string;
  1039. username: string;
  1040. email: string;
  1041. }>;
  1042. };
  1043. export type Repository = {
  1044. dateCreated: string;
  1045. externalSlug: string;
  1046. id: string;
  1047. integrationId: string;
  1048. name: string;
  1049. provider: {id: string; name: string};
  1050. status: RepositoryStatus;
  1051. url: string;
  1052. };
  1053. export enum RepositoryStatus {
  1054. ACTIVE = 'active',
  1055. DISABLED = 'disabled',
  1056. HIDDEN = 'hidden',
  1057. PENDING_DELETION = 'pending_deletion',
  1058. DELETION_IN_PROGRESS = 'deletion_in_progress',
  1059. }
  1060. type BaseRepositoryProjectPathConfig = {
  1061. id: string;
  1062. projectId: string;
  1063. projectSlug: string;
  1064. repoId: string;
  1065. repoName: string;
  1066. stackRoot: string;
  1067. sourceRoot: string;
  1068. defaultBranch?: string;
  1069. };
  1070. export type RepositoryProjectPathConfig = BaseRepositoryProjectPathConfig & {
  1071. integrationId: string | null;
  1072. provider: BaseIntegrationProvider | null;
  1073. };
  1074. export type RepositoryProjectPathConfigWithIntegration =
  1075. BaseRepositoryProjectPathConfig & {
  1076. integrationId: string;
  1077. provider: BaseIntegrationProvider;
  1078. };
  1079. export type PullRequest = {
  1080. id: string;
  1081. title: string;
  1082. externalUrl: string;
  1083. repository: Repository;
  1084. };
  1085. type IntegrationDialog = {
  1086. actionText: string;
  1087. body: string;
  1088. };
  1089. type IntegrationAspects = {
  1090. alerts?: Array<React.ComponentProps<typeof Alert> & {text: string}>;
  1091. disable_dialog?: IntegrationDialog;
  1092. removal_dialog?: IntegrationDialog;
  1093. externalInstall?: {
  1094. url: string;
  1095. buttonText: string;
  1096. noticeText: string;
  1097. };
  1098. configure_integration?: {
  1099. title: string;
  1100. };
  1101. };
  1102. type BaseIntegrationProvider = {
  1103. key: string;
  1104. slug: string;
  1105. name: string;
  1106. canAdd: boolean;
  1107. canDisable: boolean;
  1108. features: string[];
  1109. };
  1110. export type IntegrationProvider = BaseIntegrationProvider & {
  1111. setupDialog: {url: string; width: number; height: number};
  1112. metadata: {
  1113. description: string;
  1114. features: IntegrationFeature[];
  1115. author: string;
  1116. noun: string;
  1117. issue_url: string;
  1118. source_url: string;
  1119. aspects: IntegrationAspects;
  1120. };
  1121. };
  1122. export type IntegrationFeature = {
  1123. description: string;
  1124. featureGate: string;
  1125. };
  1126. export type WebhookEvent = 'issue' | 'error';
  1127. export type Scope = typeof API_ACCESS_SCOPES[number];
  1128. export type SentryAppSchemaIssueLink = {
  1129. type: 'issue-link';
  1130. create: {
  1131. uri: string;
  1132. required_fields: any[];
  1133. optional_fields?: any[];
  1134. };
  1135. link: {
  1136. uri: string;
  1137. required_fields: any[];
  1138. optional_fields?: any[];
  1139. };
  1140. };
  1141. export type SentryAppSchemaStacktraceLink = {
  1142. type: 'stacktrace-link';
  1143. uri: string;
  1144. url: string;
  1145. params?: Array<string>;
  1146. };
  1147. export type SentryAppSchemaElement =
  1148. | SentryAppSchemaIssueLink
  1149. | SentryAppSchemaStacktraceLink;
  1150. export type SentryApp = {
  1151. status: SentryAppStatus;
  1152. scopes: Scope[];
  1153. isAlertable: boolean;
  1154. verifyInstall: boolean;
  1155. slug: string;
  1156. name: string;
  1157. uuid: string;
  1158. author: string;
  1159. events: WebhookEvent[];
  1160. schema: {
  1161. elements?: SentryAppSchemaElement[];
  1162. };
  1163. // possible null params
  1164. webhookUrl: string | null;
  1165. redirectUrl: string | null;
  1166. overview: string | null;
  1167. // optional params below
  1168. datePublished?: string;
  1169. clientId?: string;
  1170. clientSecret?: string;
  1171. owner?: {
  1172. id: number;
  1173. slug: string;
  1174. };
  1175. featureData: IntegrationFeature[];
  1176. };
  1177. export type Integration = {
  1178. id: string;
  1179. name: string;
  1180. icon: string;
  1181. domainName: string;
  1182. accountType: string;
  1183. status: ObjectStatus;
  1184. provider: BaseIntegrationProvider & {aspects: IntegrationAspects};
  1185. dynamicDisplayInformation?: {
  1186. configure_integration?: {
  1187. instructions: string[];
  1188. };
  1189. integration_detail?: {
  1190. uninstallationUrl?: string;
  1191. };
  1192. };
  1193. };
  1194. // we include the configOrganization when we need it
  1195. export type IntegrationWithConfig = Integration & {
  1196. configOrganization: Field[];
  1197. configData: object | null;
  1198. };
  1199. export type IntegrationExternalIssue = {
  1200. id: string;
  1201. key: string;
  1202. url: string;
  1203. title: string;
  1204. description: string;
  1205. displayName: string;
  1206. };
  1207. export type GroupIntegration = Integration & {
  1208. externalIssues: IntegrationExternalIssue[];
  1209. };
  1210. export type PlatformExternalIssue = {
  1211. id: string;
  1212. issueId: string;
  1213. serviceType: string;
  1214. displayName: string;
  1215. webUrl: string;
  1216. };
  1217. export type SentryAppInstallation = {
  1218. app: {
  1219. uuid: string;
  1220. slug: string;
  1221. };
  1222. organization: {
  1223. slug: string;
  1224. };
  1225. uuid: string;
  1226. status: 'installed' | 'pending';
  1227. code?: string;
  1228. };
  1229. export type SentryAppWebhookRequest = {
  1230. webhookUrl: string;
  1231. sentryAppSlug: string;
  1232. eventType: string;
  1233. date: string;
  1234. organization?: {
  1235. slug: string;
  1236. name: string;
  1237. };
  1238. responseCode: number;
  1239. errorUrl?: string;
  1240. };
  1241. export type ServiceHook = {
  1242. id: string;
  1243. events: string[];
  1244. dateCreated: string;
  1245. secret: string;
  1246. status: string;
  1247. url: string;
  1248. };
  1249. export type PermissionValue = 'no-access' | 'read' | 'write' | 'admin';
  1250. export type Permissions = {
  1251. Event: PermissionValue;
  1252. Member: PermissionValue;
  1253. Organization: PermissionValue;
  1254. Project: PermissionValue;
  1255. Release: PermissionValue;
  1256. Team: PermissionValue;
  1257. };
  1258. // See src/sentry/api/serializers/models/apitoken.py for the differences based on application
  1259. type BaseApiToken = {
  1260. id: string;
  1261. scopes: Scope[];
  1262. expiresAt: string;
  1263. dateCreated: string;
  1264. state: string;
  1265. };
  1266. // We include the token for API tokens used for internal apps
  1267. export type InternalAppApiToken = BaseApiToken & {
  1268. application: null;
  1269. token: string;
  1270. refreshToken: string;
  1271. };
  1272. export type ApiApplication = {
  1273. allowedOrigins: string[];
  1274. clientID: string;
  1275. clientSecret: string | null;
  1276. homepageUrl: string | null;
  1277. id: string;
  1278. name: string;
  1279. privacyUrl: string | null;
  1280. redirectUris: string[];
  1281. termsUrl: string | null;
  1282. };
  1283. export type UserReport = {
  1284. id: string;
  1285. eventID: string;
  1286. issue: Group;
  1287. name: string;
  1288. event: {eventID: string; id: string};
  1289. user: User;
  1290. dateCreated: string;
  1291. comments: string;
  1292. email: string;
  1293. };
  1294. export type Release = BaseRelease &
  1295. ReleaseData & {
  1296. projects: ReleaseProject[];
  1297. };
  1298. export type ReleaseWithHealth = BaseRelease &
  1299. ReleaseData & {
  1300. projects: Required<ReleaseProject>[];
  1301. };
  1302. type ReleaseData = {
  1303. commitCount: number;
  1304. data: {};
  1305. lastDeploy?: Deploy;
  1306. deployCount: number;
  1307. lastEvent: string;
  1308. firstEvent: string;
  1309. lastCommit?: Commit;
  1310. authors: User[];
  1311. owner?: any; // TODO(ts)
  1312. newGroups: number;
  1313. versionInfo: VersionInfo;
  1314. fileCount: number | null;
  1315. currentProjectMeta: {
  1316. nextReleaseVersion: string | null;
  1317. prevReleaseVersion: string | null;
  1318. sessionsLowerBound: string | null;
  1319. sessionsUpperBound: string | null;
  1320. firstReleaseVersion: string | null;
  1321. lastReleaseVersion: string | null;
  1322. };
  1323. };
  1324. type BaseRelease = {
  1325. dateReleased: string;
  1326. url: string;
  1327. dateCreated: string;
  1328. version: string;
  1329. shortVersion: string;
  1330. ref: string;
  1331. status: ReleaseStatus;
  1332. };
  1333. export type CurrentRelease = {
  1334. environment: string;
  1335. firstSeen: string;
  1336. lastSeen: string;
  1337. release: Release;
  1338. stats: {
  1339. // 24h/30d is hardcoded in GroupReleaseWithStatsSerializer
  1340. '24h': TimeseriesValue[];
  1341. '30d': TimeseriesValue[];
  1342. };
  1343. };
  1344. export enum ReleaseStatus {
  1345. Active = 'open',
  1346. Archived = 'archived',
  1347. }
  1348. export type ReleaseProject = {
  1349. slug: string;
  1350. name: string;
  1351. id: number;
  1352. platform: PlatformKey;
  1353. platforms: PlatformKey[];
  1354. newGroups: number;
  1355. hasHealthData: boolean;
  1356. healthData?: Health;
  1357. };
  1358. export type ReleaseMeta = {
  1359. commitCount: number;
  1360. commitFilesChanged: number;
  1361. deployCount: number;
  1362. releaseFileCount: number;
  1363. version: string;
  1364. projects: ReleaseProject[];
  1365. versionInfo: VersionInfo;
  1366. released: string;
  1367. };
  1368. export type VersionInfo = {
  1369. buildHash: string | null;
  1370. description: string;
  1371. package: string | null;
  1372. version: {raw: string};
  1373. };
  1374. export type Deploy = {
  1375. id: string;
  1376. name: string;
  1377. url: string;
  1378. environment: string;
  1379. dateStarted: string;
  1380. dateFinished: string;
  1381. version: string;
  1382. };
  1383. export type Commit = {
  1384. id: string;
  1385. message: string | null;
  1386. dateCreated: string;
  1387. releases: BaseRelease[];
  1388. repository?: Repository;
  1389. author?: User;
  1390. };
  1391. export type Committer = {
  1392. author: User;
  1393. commits: Commit[];
  1394. };
  1395. export type CommitFile = {
  1396. id: string;
  1397. author: CommitAuthor;
  1398. commitMessage: string;
  1399. filename: string;
  1400. orgId: number;
  1401. repoName: string;
  1402. type: string;
  1403. };
  1404. export type MemberRole = {
  1405. id: string;
  1406. name: string;
  1407. desc: string;
  1408. allowed?: boolean;
  1409. };
  1410. export type SentryAppComponent = {
  1411. uuid: string;
  1412. type: 'issue-link' | 'alert-rule-action' | 'issue-media' | 'stacktrace-link';
  1413. schema: SentryAppSchemaStacktraceLink;
  1414. sentryApp: {
  1415. uuid: string;
  1416. slug:
  1417. | 'clickup'
  1418. | 'clubhouse'
  1419. | 'komodor'
  1420. | 'linear'
  1421. | 'rookout'
  1422. | 'spikesh'
  1423. | 'teamwork'
  1424. | 'zepel';
  1425. name: string;
  1426. };
  1427. };
  1428. export type SavedQueryVersions = 1 | 2;
  1429. export type NewQuery = {
  1430. id: string | undefined;
  1431. version: SavedQueryVersions;
  1432. name: string;
  1433. createdBy?: User;
  1434. // Query and Table
  1435. query?: string;
  1436. fields: Readonly<string[]>;
  1437. widths?: Readonly<string[]>;
  1438. orderby?: string;
  1439. expired?: boolean;
  1440. // GlobalSelectionHeader
  1441. projects: Readonly<number[]>;
  1442. environment?: Readonly<string[]>;
  1443. range?: string;
  1444. start?: string;
  1445. end?: string;
  1446. // Graph
  1447. yAxis?: string;
  1448. display?: string;
  1449. teams?: Readonly<('myteams' | number)[]>;
  1450. };
  1451. export type SavedQuery = NewQuery & {
  1452. id: string;
  1453. dateCreated: string;
  1454. dateUpdated: string;
  1455. };
  1456. export type SavedQueryState = {
  1457. savedQueries: SavedQuery[];
  1458. hasError: boolean;
  1459. isLoading: boolean;
  1460. };
  1461. /**
  1462. * The option format used by react-select based components
  1463. */
  1464. export type SelectValue<T> = {
  1465. label: string | number | React.ReactElement;
  1466. value: T;
  1467. disabled?: boolean;
  1468. tooltip?: string;
  1469. };
  1470. /**
  1471. * The 'other' option format used by checkboxes, radios and more.
  1472. */
  1473. export type Choices = [
  1474. value: string | number,
  1475. label: string | number | React.ReactElement
  1476. ][];
  1477. /**
  1478. * The issue config form fields we get are basically the form fields we use in
  1479. * the UI but with some extra information. Some fields marked optional in the
  1480. * form field are guaranteed to exist so we can mark them as required here
  1481. */
  1482. export type IssueConfigField = Field & {
  1483. name: string;
  1484. default?: string | number;
  1485. choices?: Choices;
  1486. url?: string;
  1487. multiple?: boolean;
  1488. };
  1489. export type IntegrationIssueConfig = {
  1490. status: ObjectStatus;
  1491. name: string;
  1492. domainName: string;
  1493. linkIssueConfig?: IssueConfigField[];
  1494. createIssueConfig?: IssueConfigField[];
  1495. provider: IntegrationProvider;
  1496. icon: string[];
  1497. };
  1498. export enum OnboardingTaskKey {
  1499. FIRST_PROJECT = 'create_project',
  1500. FIRST_EVENT = 'send_first_event',
  1501. INVITE_MEMBER = 'invite_member',
  1502. SECOND_PLATFORM = 'setup_second_platform',
  1503. USER_CONTEXT = 'setup_user_context',
  1504. RELEASE_TRACKING = 'setup_release_tracking',
  1505. SOURCEMAPS = 'setup_sourcemaps',
  1506. USER_REPORTS = 'setup_user_reports',
  1507. ISSUE_TRACKER = 'setup_issue_tracker',
  1508. ALERT_RULE = 'setup_alert_rules',
  1509. FIRST_TRANSACTION = 'setup_transactions',
  1510. }
  1511. export type OnboardingSupplementComponentProps = {
  1512. task: OnboardingTask;
  1513. onCompleteTask: () => void;
  1514. };
  1515. export type OnboardingTaskDescriptor = {
  1516. task: OnboardingTaskKey;
  1517. title: string;
  1518. description: string;
  1519. /**
  1520. * Can this task be skipped?
  1521. */
  1522. skippable: boolean;
  1523. /**
  1524. * A list of require task keys that must have been completed before these
  1525. * tasks may be completed.
  1526. */
  1527. requisites: OnboardingTaskKey[];
  1528. /**
  1529. * Should the onboarding task currently be displayed
  1530. */
  1531. display: boolean;
  1532. /**
  1533. * An extra component that may be rendered within the onboarding task item.
  1534. */
  1535. SupplementComponent?: React.ComponentType<OnboardingSupplementComponentProps>;
  1536. } & (
  1537. | {
  1538. actionType: 'app' | 'external';
  1539. location: string;
  1540. }
  1541. | {
  1542. actionType: 'action';
  1543. action: () => void;
  1544. }
  1545. );
  1546. export type OnboardingTaskStatus = {
  1547. task: OnboardingTaskKey;
  1548. status: 'skipped' | 'pending' | 'complete';
  1549. user?: AvatarUser | null;
  1550. dateCompleted?: string;
  1551. completionSeen?: string;
  1552. data?: object;
  1553. };
  1554. export type OnboardingTask = OnboardingTaskStatus &
  1555. OnboardingTaskDescriptor & {
  1556. /**
  1557. * Onboarding tasks that are currently incomplete and must be completed
  1558. * before this task should be completed.
  1559. */
  1560. requisiteTasks: OnboardingTask[];
  1561. };
  1562. export type Tag = {
  1563. name: string;
  1564. key: string;
  1565. values?: string[];
  1566. totalValues?: number;
  1567. predefined?: boolean;
  1568. isInput?: boolean;
  1569. /**
  1570. * How many values should be suggested in autocomplete.
  1571. * Overrides SmartSearchBar's `maxSearchItems` prop.
  1572. */
  1573. maxSuggestedValues?: number;
  1574. };
  1575. export type TagCollection = {[key: string]: Tag};
  1576. export type TagValue = {
  1577. count: number;
  1578. name: string;
  1579. value: string;
  1580. lastSeen: string;
  1581. key: string;
  1582. firstSeen: string;
  1583. query?: string;
  1584. email?: string;
  1585. username?: string;
  1586. identifier?: string;
  1587. ipAddress?: string;
  1588. } & AvatarUser;
  1589. type Topvalue = {
  1590. count: number;
  1591. firstSeen: string;
  1592. key: string;
  1593. lastSeen: string;
  1594. name: string;
  1595. value: string;
  1596. // Might not actually exist.
  1597. query?: string;
  1598. };
  1599. export type TagWithTopValues = {
  1600. topValues: Array<Topvalue>;
  1601. key: string;
  1602. name: string;
  1603. totalValues: number;
  1604. uniqueValues: number;
  1605. canDelete?: boolean;
  1606. };
  1607. export type Level = 'error' | 'fatal' | 'info' | 'warning' | 'sample';
  1608. export type Meta = {
  1609. chunks: Array<ChunkType>;
  1610. len: number;
  1611. rem: Array<MetaRemark>;
  1612. err: Array<MetaError>;
  1613. };
  1614. export type MetaError = string | [string, any];
  1615. export type MetaRemark = Array<string | number>;
  1616. export type ChunkType = {
  1617. text: string;
  1618. type: string;
  1619. rule_id: string | number;
  1620. remark?: string | number;
  1621. };
  1622. export enum ResolutionStatus {
  1623. RESOLVED = 'resolved',
  1624. UNRESOLVED = 'unresolved',
  1625. IGNORED = 'ignored',
  1626. }
  1627. export type ResolutionStatusDetails = {
  1628. actor?: AvatarUser;
  1629. autoResolved?: boolean;
  1630. ignoreCount?: number;
  1631. // Sent in requests. ignoreUntil is used in responses.
  1632. ignoreDuration?: number;
  1633. ignoreUntil?: string;
  1634. ignoreUserCount?: number;
  1635. ignoreUserWindow?: number;
  1636. ignoreWindow?: number;
  1637. inCommit?: Commit;
  1638. inRelease?: string;
  1639. inNextRelease?: boolean;
  1640. };
  1641. export type UpdateResolutionStatus = {
  1642. status: ResolutionStatus;
  1643. statusDetails?: ResolutionStatusDetails;
  1644. };
  1645. export type SubscriptionDetails = {disabled?: boolean; reason?: string};
  1646. export type Broadcast = {
  1647. id: string;
  1648. message: string;
  1649. title: string;
  1650. link: string;
  1651. cta: string;
  1652. isActive: boolean;
  1653. dateCreated: string;
  1654. dateExpires: string;
  1655. hasSeen: boolean;
  1656. };
  1657. export type SentryServiceIncident = {
  1658. id: string;
  1659. name: string;
  1660. updates?: string[];
  1661. url: string;
  1662. status: string;
  1663. };
  1664. export type SentryServiceStatus = {
  1665. indicator: 'major' | 'minor' | 'none';
  1666. incidents: SentryServiceIncident[];
  1667. url: string;
  1668. };
  1669. export type CrashFreeTimeBreakdown = {
  1670. date: string;
  1671. totalSessions: number;
  1672. crashFreeSessions: number | null;
  1673. crashFreeUsers: number | null;
  1674. totalUsers: number;
  1675. }[];
  1676. export type PlatformIntegration = {
  1677. id: string;
  1678. type: string;
  1679. language: string;
  1680. link: string | null;
  1681. name: string;
  1682. };
  1683. export type EventGroupComponent = {
  1684. contributes: boolean;
  1685. hint: string | null;
  1686. id: string;
  1687. name: string | null;
  1688. values: EventGroupComponent[] | string[];
  1689. };
  1690. export type EventGroupingConfig = {
  1691. base: string | null;
  1692. changelog: string;
  1693. delegates: string[];
  1694. hidden: boolean;
  1695. id: string;
  1696. latest: boolean;
  1697. risk: number;
  1698. strategies: string[];
  1699. };
  1700. type EventGroupVariantKey = 'custom-fingerprint' | 'app' | 'default' | 'system';
  1701. export enum EventGroupVariantType {
  1702. CUSTOM_FINGERPRINT = 'custom-fingerprint',
  1703. COMPONENT = 'component',
  1704. SALTED_COMPONENT = 'salted-component',
  1705. }
  1706. export type EventGroupVariant = {
  1707. description: string | null;
  1708. hash: string | null;
  1709. hashMismatch: boolean;
  1710. key: EventGroupVariantKey;
  1711. type: EventGroupVariantType;
  1712. values?: Array<string>;
  1713. client_values?: Array<string>;
  1714. matched_rule?: string;
  1715. component?: EventGroupComponent;
  1716. config?: EventGroupingConfig;
  1717. };
  1718. export type SourceMapsArchive = {
  1719. id: number;
  1720. type: 'release';
  1721. name: string;
  1722. date: string;
  1723. fileCount: number;
  1724. };
  1725. export type Artifact = {
  1726. dateCreated: string;
  1727. dist: string | null;
  1728. id: string;
  1729. name: string;
  1730. sha1: string;
  1731. size: number;
  1732. headers: {'Content-Type': string};
  1733. };
  1734. export type EventGroupInfo = Record<EventGroupVariantKey, EventGroupVariant>;
  1735. // TODO(epurkhiser): objc and cocoa should almost definitely be moved into PlatformKey
  1736. export type PlatformType = PlatformKey | 'objc' | 'cocoa';
  1737. export type Frame = {
  1738. absPath: string | null;
  1739. colNo: number | null;
  1740. context: Array<[number, string]>;
  1741. errors: Array<any> | null;
  1742. filename: string | null;
  1743. function: string | null;
  1744. inApp: boolean;
  1745. instructionAddr: string | null;
  1746. addrMode?: string;
  1747. lineNo: number | null;
  1748. module: string | null;
  1749. package: string | null;
  1750. platform: PlatformType | null;
  1751. rawFunction: string | null;
  1752. symbol: string | null;
  1753. symbolAddr: string | null;
  1754. symbolicatorStatus: SymbolicatorStatus;
  1755. trust: any | null;
  1756. vars: Record<string, any> | null;
  1757. origAbsPath?: string | null;
  1758. mapUrl?: string | null;
  1759. map?: string | null;
  1760. };
  1761. /**
  1762. * Note used in Group Activity and Alerts for users to comment
  1763. */
  1764. export type Note = {
  1765. /**
  1766. * Note contents (markdown allowed)
  1767. */
  1768. text: string;
  1769. /**
  1770. * Array of [id, display string] tuples used for @-mentions
  1771. */
  1772. mentions: [string, string][];
  1773. };
  1774. export type FilesByRepository = {
  1775. [repoName: string]: {
  1776. authors?: {[email: string]: CommitAuthor};
  1777. types?: Set<string>;
  1778. };
  1779. };
  1780. export type ExceptionValue = {
  1781. type: string;
  1782. value: string;
  1783. threadId: number | null;
  1784. stacktrace: StacktraceType | null;
  1785. rawStacktrace: RawStacktrace;
  1786. mechanism: Mechanism | null;
  1787. module: string | null;
  1788. frames: Frame[] | null;
  1789. };
  1790. export type ExceptionType = {
  1791. excOmitted: any | null;
  1792. hasSystemFrames: boolean;
  1793. values?: Array<ExceptionValue>;
  1794. };
  1795. /**
  1796. * Identity is used in Account Identities for SocialAuths
  1797. */
  1798. export type Identity = {
  1799. id: string;
  1800. provider: IntegrationProvider;
  1801. providerLabel: string;
  1802. };
  1803. // taken from https://stackoverflow.com/questions/46634876/how-can-i-change-a-readonly-property-in-typescript
  1804. export type Writable<T> = {-readonly [K in keyof T]: T[K]};
  1805. export type InternetProtocol = {
  1806. id: string;
  1807. ipAddress: string;
  1808. lastSeen: string;
  1809. firstSeen: string;
  1810. countryCode: string | null;
  1811. regionCode: string | null;
  1812. };
  1813. /**
  1814. * XXX(ts): This actually all comes from getsentry. We should definitely
  1815. * refactor this into a more proper 'hook' mechanism in the future
  1816. */
  1817. export type AuthConfig = {
  1818. canRegister: boolean;
  1819. serverHostname: string;
  1820. hasNewsletter: boolean;
  1821. githubLoginLink: string;
  1822. vstsLoginLink: string;
  1823. googleLoginLink: string;
  1824. };
  1825. export type AuthProvider = {
  1826. key: string;
  1827. name: string;
  1828. requiredFeature: string;
  1829. disables2FA: boolean;
  1830. };
  1831. export type PromptActivity = {
  1832. snoozedTime?: number;
  1833. dismissedTime?: number;
  1834. };
  1835. export type ServerlessFunction = {
  1836. name: string;
  1837. runtime: string;
  1838. version: number;
  1839. outOfDate: boolean;
  1840. enabled: boolean;
  1841. };
  1842. /**
  1843. * File storage service options for debug files
  1844. */
  1845. export type DebugFileSource = 'http' | 's3' | 'gcs' | 'appStoreConnect';
  1846. /**
  1847. * Base type for series style API response
  1848. */
  1849. export type SeriesApi = {
  1850. intervals: string[];
  1851. groups: {
  1852. by: Record<string, string | number>;
  1853. totals: Record<string, number>;
  1854. series: Record<string, number[]>;
  1855. }[];
  1856. };
  1857. export type SessionApiResponse = SeriesApi & {
  1858. start: DateString;
  1859. end: DateString;
  1860. query: string;
  1861. intervals: string[];
  1862. groups: {
  1863. by: Record<string, string | number>;
  1864. totals: Record<string, number>;
  1865. series: Record<string, number[]>;
  1866. }[];
  1867. };
  1868. export enum HealthStatsPeriodOption {
  1869. AUTO = 'auto',
  1870. TWENTY_FOUR_HOURS = '24h',
  1871. }
  1872. export type IssueOwnership = {
  1873. raw: string;
  1874. fallthrough: boolean;
  1875. dateCreated: string;
  1876. lastUpdated: string;
  1877. isActive: boolean;
  1878. autoAssignment: boolean;
  1879. };
  1880. export type CodeOwners = {
  1881. id: string;
  1882. raw: string;
  1883. dateCreated: string;
  1884. dateUpdated: string;
  1885. provider: 'github' | 'gitlab';
  1886. codeMapping?: RepositoryProjectPathConfig[];
  1887. };
  1888. export type KeyValueListData = {
  1889. key: string;
  1890. subject: string;
  1891. value?: React.ReactNode;
  1892. meta?: Meta;
  1893. subjectDataTestId?: string;
  1894. subjectIcon?: React.ReactNode;
  1895. }[];
  1896. export type ExternalActorMapping = {
  1897. id: string;
  1898. externalName: string;
  1899. userId?: string;
  1900. teamId?: string;
  1901. sentryName: string;
  1902. };
  1903. export type ExternalUser = {
  1904. id: string;
  1905. memberId: string;
  1906. externalName: string;
  1907. provider: string;
  1908. };
  1909. export type ExternalTeam = {
  1910. id: string;
  1911. teamId: string;
  1912. externalName: string;
  1913. provider: string;
  1914. };