modal.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import * as React from 'react';
  2. import ModalActions from 'app/actions/modalActions';
  3. import GlobalModal from 'app/components/globalModal';
  4. import type {DashboardWidgetModalOptions} from 'app/components/modals/addDashboardWidgetModal';
  5. import {InviteRow} from 'app/components/modals/inviteMembersModal/types';
  6. import type {ReprocessEventModalOptions} from 'app/components/modals/reprocessEventModal';
  7. import {AppStoreConnectContextProps} from 'app/components/projects/appStoreConnectContext';
  8. import {
  9. DebugFileSource,
  10. Group,
  11. IssueOwnership,
  12. Organization,
  13. Project,
  14. SentryApp,
  15. Team,
  16. } from 'app/types';
  17. import {Event} from 'app/types/event';
  18. type ModalProps = Required<React.ComponentProps<typeof GlobalModal>>;
  19. export type ModalOptions = ModalProps['options'];
  20. export type ModalRenderProps = Parameters<NonNullable<ModalProps['children']>>[0];
  21. /**
  22. * Show a modal
  23. */
  24. export function openModal(
  25. renderer: (renderProps: ModalRenderProps) => React.ReactNode,
  26. options?: ModalOptions
  27. ) {
  28. ModalActions.openModal(renderer, options);
  29. }
  30. /**
  31. * Close modal
  32. */
  33. export function closeModal() {
  34. ModalActions.closeModal();
  35. }
  36. type OpenSudoModalOptions = {
  37. onClose?: () => void;
  38. superuser?: boolean;
  39. sudo?: boolean;
  40. retryRequest?: () => Promise<any>;
  41. };
  42. type emailVerificationModalOptions = {
  43. onClose?: () => void;
  44. emailVerified?: boolean;
  45. actionMessage?: string;
  46. };
  47. type inviteMembersModalOptions = {
  48. onClose?: () => void;
  49. initialData?: Partial<InviteRow>[];
  50. source?: string;
  51. };
  52. export async function openSudo({onClose, ...args}: OpenSudoModalOptions = {}) {
  53. const mod = await import('app/components/modals/sudoModal');
  54. const {default: Modal} = mod;
  55. openModal(deps => <Modal {...deps} {...args} />, {onClose});
  56. }
  57. export async function openEmailVerification({
  58. onClose,
  59. ...args
  60. }: emailVerificationModalOptions = {}) {
  61. const mod = await import('app/components/modals/emailVerificationModal');
  62. const {default: Modal} = mod;
  63. openModal(deps => <Modal {...deps} {...args} />, {onClose});
  64. }
  65. type OpenDiffModalOptions = {
  66. targetIssueId: string;
  67. project: Project;
  68. baseIssueId: Group['id'];
  69. orgId: Organization['id'];
  70. baseEventId?: Event['id'];
  71. targetEventId?: string;
  72. };
  73. export async function openDiffModal(options: OpenDiffModalOptions) {
  74. const mod = await import('app/components/modals/diffModal');
  75. const {default: Modal, modalCss} = mod;
  76. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  77. }
  78. type CreateTeamModalOptions = {
  79. /**
  80. * The organization to create a team for
  81. */
  82. organization: Organization;
  83. /**
  84. * An initial project to add the team to. This may be deprecated soon as we may add a project selection inside of the modal flow
  85. */
  86. project?: Project;
  87. onClose?: (team: Team) => void;
  88. };
  89. export async function openCreateTeamModal(options: CreateTeamModalOptions) {
  90. const mod = await import('app/components/modals/createTeamModal');
  91. const {default: Modal} = mod;
  92. openModal(deps => <Modal {...deps} {...options} />);
  93. }
  94. type CreateOwnershipRuleModalOptions = {
  95. /**
  96. * The organization to create a rules for
  97. */
  98. organization: Organization;
  99. /**
  100. * The project to create a rules for
  101. */
  102. project: Project;
  103. issueId: string;
  104. };
  105. export type EditOwnershipRulesModalOptions = {
  106. organization: Organization;
  107. project: Project;
  108. ownership: IssueOwnership;
  109. onSave: (text: string | null) => void;
  110. };
  111. export async function openCreateOwnershipRule(options: CreateOwnershipRuleModalOptions) {
  112. const mod = await import('app/components/modals/createOwnershipRuleModal');
  113. const {default: Modal, modalCss} = mod;
  114. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  115. }
  116. export async function openEditOwnershipRules(options: EditOwnershipRulesModalOptions) {
  117. const mod = await import('app/components/modals/editOwnershipRulesModal');
  118. const {default: Modal, modalCss} = mod;
  119. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  120. }
  121. export async function openCommandPalette(options: ModalOptions = {}) {
  122. const mod = await import('app/components/modals/commandPalette');
  123. const {default: Modal, modalCss} = mod;
  124. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  125. }
  126. type RecoveryModalOptions = {
  127. authenticatorName: string;
  128. };
  129. export async function openRecoveryOptions(options: RecoveryModalOptions) {
  130. const mod = await import('app/components/modals/recoveryOptionsModal');
  131. const {default: Modal} = mod;
  132. openModal(deps => <Modal {...deps} {...options} />);
  133. }
  134. export type TeamAccessRequestModalOptions = {
  135. memberId: string;
  136. teamId: string;
  137. orgId: string;
  138. };
  139. export async function openTeamAccessRequestModal(options: TeamAccessRequestModalOptions) {
  140. const mod = await import('app/components/modals/teamAccessRequestModal');
  141. const {default: Modal} = mod;
  142. openModal(deps => <Modal {...deps} {...options} />);
  143. }
  144. export async function redirectToProject(newProjectSlug: string) {
  145. const mod = await import('app/components/modals/redirectToProject');
  146. const {default: Modal} = mod;
  147. openModal(deps => <Modal {...deps} slug={newProjectSlug} />, {});
  148. }
  149. type HelpSearchModalOptions = {
  150. organization?: Organization;
  151. placeholder?: string;
  152. };
  153. export async function openHelpSearchModal(options?: HelpSearchModalOptions) {
  154. const mod = await import('app/components/modals/helpSearchModal');
  155. const {default: Modal, modalCss} = mod;
  156. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  157. }
  158. export type SentryAppDetailsModalOptions = {
  159. sentryApp: SentryApp;
  160. isInstalled: boolean;
  161. onInstall: () => Promise<void>;
  162. organization: Organization;
  163. onCloseModal?: () => void; // used for analytics
  164. };
  165. type DebugFileSourceModalOptions = {
  166. sourceType: DebugFileSource;
  167. onSave: (data: Record<string, any>) => Promise<void>;
  168. appStoreConnectContext?: AppStoreConnectContextProps;
  169. onClose?: () => void;
  170. sourceConfig?: Record<string, any>;
  171. };
  172. export async function openDebugFileSourceModal({
  173. onClose,
  174. ...restOptions
  175. }: DebugFileSourceModalOptions) {
  176. const mod = await import(
  177. /* webpackChunkName: "DebugFileCustomRepository" */ 'app/components/modals/debugFileCustomRepository'
  178. );
  179. const {default: Modal, modalCss} = mod;
  180. openModal(deps => <Modal {...deps} {...restOptions} />, {
  181. modalCss,
  182. onClose,
  183. });
  184. }
  185. export async function openInviteMembersModal({
  186. onClose,
  187. ...args
  188. }: inviteMembersModalOptions = {}) {
  189. const mod = await import('app/components/modals/inviteMembersModal');
  190. const {default: Modal, modalCss} = mod;
  191. openModal(deps => <Modal {...deps} {...args} />, {modalCss, onClose});
  192. }
  193. export async function openAddDashboardWidgetModal(options: DashboardWidgetModalOptions) {
  194. const mod = await import('app/components/modals/addDashboardWidgetModal');
  195. const {default: Modal, modalCss} = mod;
  196. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  197. }
  198. export async function openReprocessEventModal({
  199. onClose,
  200. ...options
  201. }: ReprocessEventModalOptions & {onClose?: () => void}) {
  202. const mod = await import('app/components/modals/reprocessEventModal');
  203. const {default: Modal} = mod;
  204. openModal(deps => <Modal {...deps} {...options} />, {onClose});
  205. }