modal.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import type {ModalTypes} from 'sentry/components/globalModal';
  2. import type {DashboardWidgetModalOptions} from 'sentry/components/modals/addDashboardWidgetModal';
  3. import type {CreateNewIntegrationModalOptions} from 'sentry/components/modals/createNewIntegrationModal';
  4. import type {CreateReleaseIntegrationModalOptions} from 'sentry/components/modals/createReleaseIntegrationModal';
  5. import {DashboardWidgetLibraryModalOptions} from 'sentry/components/modals/dashboardWidgetLibraryModal';
  6. import type {DashboardWidgetQuerySelectorModalOptions} from 'sentry/components/modals/dashboardWidgetQuerySelectorModal';
  7. import {InviteRow} from 'sentry/components/modals/inviteMembersModal/types';
  8. import type {ReprocessEventModalOptions} from 'sentry/components/modals/reprocessEventModal';
  9. import {OverwriteWidgetModalProps} from 'sentry/components/modals/widgetBuilder/overwriteWidgetModal';
  10. import type {WidgetViewerModalOptions} from 'sentry/components/modals/widgetViewerModal';
  11. import ModalStore from 'sentry/stores/modalStore';
  12. import {
  13. Group,
  14. IssueOwnership,
  15. Organization,
  16. Project,
  17. SentryApp,
  18. Team,
  19. } from 'sentry/types';
  20. import {AppStoreConnectStatusData, CustomRepoType} from 'sentry/types/debugFiles';
  21. import {Event} from 'sentry/types/event';
  22. export type ModalOptions = ModalTypes['options'];
  23. export type ModalRenderProps = ModalTypes['renderProps'];
  24. /**
  25. * Show a modal
  26. */
  27. export function openModal(
  28. renderer: (renderProps: ModalRenderProps) => React.ReactNode,
  29. options?: ModalOptions
  30. ) {
  31. ModalStore.openModal(renderer, options ?? {});
  32. }
  33. /**
  34. * Close modal
  35. */
  36. export function closeModal() {
  37. ModalStore.closeModal();
  38. }
  39. type OpenSudoModalOptions = {
  40. isSuperuser?: boolean;
  41. needsReload?: boolean;
  42. onClose?: () => void;
  43. retryRequest?: () => Promise<any>;
  44. sudo?: boolean;
  45. };
  46. type emailVerificationModalOptions = {
  47. actionMessage?: string;
  48. emailVerified?: boolean;
  49. onClose?: () => void;
  50. };
  51. type inviteMembersModalOptions = {
  52. initialData?: Partial<InviteRow>[];
  53. onClose?: () => void;
  54. source?: string;
  55. };
  56. export async function openSudo({onClose, ...args}: OpenSudoModalOptions = {}) {
  57. const mod = await import('sentry/components/modals/sudoModal');
  58. const {default: Modal} = mod;
  59. openModal(deps => <Modal {...deps} {...args} />, {onClose});
  60. }
  61. export async function openEmailVerification({
  62. onClose,
  63. ...args
  64. }: emailVerificationModalOptions = {}) {
  65. const mod = await import('sentry/components/modals/emailVerificationModal');
  66. const {default: Modal} = mod;
  67. openModal(deps => <Modal {...deps} {...args} />, {onClose});
  68. }
  69. type OpenDiffModalOptions = {
  70. baseIssueId: Group['id'];
  71. orgId: Organization['id'];
  72. project: Project;
  73. targetIssueId: string;
  74. baseEventId?: Event['id'];
  75. targetEventId?: string;
  76. };
  77. export async function openDiffModal(options: OpenDiffModalOptions) {
  78. const mod = await import('sentry/components/modals/diffModal');
  79. const {default: Modal, modalCss} = mod;
  80. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  81. }
  82. type CreateTeamModalOptions = {
  83. /**
  84. * The organization to create a team for
  85. */
  86. organization: Organization;
  87. onClose?: (team: Team) => void;
  88. /**
  89. * 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
  90. */
  91. project?: Project;
  92. };
  93. export async function openCreateTeamModal(options: CreateTeamModalOptions) {
  94. const mod = await import('sentry/components/modals/createTeamModal');
  95. const {default: Modal} = mod;
  96. openModal(deps => <Modal {...deps} {...options} />);
  97. }
  98. type CreateOwnershipRuleModalOptions = {
  99. issueId: string;
  100. /**
  101. * The organization to create a rules for
  102. */
  103. organization: Organization;
  104. /**
  105. * The project to create a rules for
  106. */
  107. project: Project;
  108. };
  109. export type EditOwnershipRulesModalOptions = {
  110. onSave: (text: string | null) => void;
  111. organization: Organization;
  112. ownership: IssueOwnership;
  113. project: Project;
  114. };
  115. export async function openCreateOwnershipRule(options: CreateOwnershipRuleModalOptions) {
  116. const mod = await import('sentry/components/modals/createOwnershipRuleModal');
  117. const {default: Modal, modalCss} = mod;
  118. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  119. }
  120. export async function openEditOwnershipRules(options: EditOwnershipRulesModalOptions) {
  121. const mod = await import('sentry/components/modals/editOwnershipRulesModal');
  122. const {default: Modal, modalCss} = mod;
  123. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  124. }
  125. export async function openCommandPalette(options: ModalOptions = {}) {
  126. const mod = await import('sentry/components/modals/commandPalette');
  127. const {default: Modal, modalCss} = mod;
  128. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  129. }
  130. type RecoveryModalOptions = {
  131. authenticatorName: string;
  132. };
  133. export async function openRecoveryOptions(options: RecoveryModalOptions) {
  134. const mod = await import('sentry/components/modals/recoveryOptionsModal');
  135. const {default: Modal} = mod;
  136. openModal(deps => <Modal {...deps} {...options} />);
  137. }
  138. export type TeamAccessRequestModalOptions = {
  139. memberId: string;
  140. orgId: string;
  141. teamId: string;
  142. };
  143. export async function openTeamAccessRequestModal(options: TeamAccessRequestModalOptions) {
  144. const mod = await import('sentry/components/modals/teamAccessRequestModal');
  145. const {default: Modal} = mod;
  146. openModal(deps => <Modal {...deps} {...options} />);
  147. }
  148. export async function redirectToProject(newProjectSlug: string) {
  149. const mod = await import('sentry/components/modals/redirectToProject');
  150. const {default: Modal} = mod;
  151. openModal(deps => <Modal {...deps} slug={newProjectSlug} />, {});
  152. }
  153. type HelpSearchModalOptions = {
  154. organization?: Organization;
  155. placeholder?: string;
  156. };
  157. export async function openHelpSearchModal(options?: HelpSearchModalOptions) {
  158. const mod = await import('sentry/components/modals/helpSearchModal');
  159. const {default: Modal, modalCss} = mod;
  160. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  161. }
  162. export type SentryAppDetailsModalOptions = {
  163. isInstalled: boolean;
  164. onInstall: () => Promise<void>;
  165. organization: Organization;
  166. sentryApp: SentryApp;
  167. onCloseModal?: () => void; // used for analytics
  168. };
  169. type DebugFileSourceModalOptions = {
  170. appStoreConnectSourcesQuantity: number;
  171. onSave: (data: Record<string, any>) => Promise<void>;
  172. organization: Organization;
  173. sourceType: CustomRepoType;
  174. appStoreConnectStatusData?: AppStoreConnectStatusData;
  175. onClose?: () => void;
  176. sourceConfig?: Record<string, any>;
  177. };
  178. export async function openDebugFileSourceModal({
  179. onClose,
  180. ...restOptions
  181. }: DebugFileSourceModalOptions) {
  182. const mod = await import('sentry/components/modals/debugFileCustomRepository');
  183. const {default: Modal, modalCss} = mod;
  184. openModal(deps => <Modal {...deps} {...restOptions} />, {
  185. modalCss,
  186. onClose,
  187. });
  188. }
  189. export async function openInviteMembersModal({
  190. onClose,
  191. ...args
  192. }: inviteMembersModalOptions = {}) {
  193. const mod = await import('sentry/components/modals/inviteMembersModal');
  194. const {default: Modal, modalCss} = mod;
  195. openModal(deps => <Modal {...deps} {...args} />, {modalCss, onClose});
  196. }
  197. export async function openAddDashboardWidgetModal(options: DashboardWidgetModalOptions) {
  198. const mod = await import('sentry/components/modals/addDashboardWidgetModal');
  199. const {default: Modal, modalCss} = mod;
  200. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  201. }
  202. export async function openWidgetBuilderOverwriteModal(
  203. options: OverwriteWidgetModalProps
  204. ) {
  205. const mod = await import('sentry/components/modals/widgetBuilder/overwriteWidgetModal');
  206. const {default: Modal, modalCss} = mod;
  207. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  208. }
  209. export async function openAddToDashboardModal(options) {
  210. const mod = await import('sentry/components/modals/widgetBuilder/addToDashboardModal');
  211. const {default: Modal, modalCss} = mod;
  212. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  213. }
  214. export async function openReprocessEventModal({
  215. onClose,
  216. ...options
  217. }: ReprocessEventModalOptions & {onClose?: () => void}) {
  218. const mod = await import('sentry/components/modals/reprocessEventModal');
  219. const {default: Modal} = mod;
  220. openModal(deps => <Modal {...deps} {...options} />, {onClose});
  221. }
  222. export async function demoSignupModal(options: ModalOptions = {}) {
  223. const mod = await import('sentry/components/modals/demoSignUp');
  224. const {default: Modal, modalCss} = mod;
  225. openModal(deps => <Modal {...deps} {...options} />, {modalCss});
  226. }
  227. export async function openDashboardWidgetQuerySelectorModal(
  228. options: DashboardWidgetQuerySelectorModalOptions
  229. ) {
  230. const mod = await import('sentry/components/modals/dashboardWidgetQuerySelectorModal');
  231. const {default: Modal, modalCss} = mod;
  232. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  233. }
  234. export async function openDashboardWidgetLibraryModal(
  235. options: DashboardWidgetLibraryModalOptions
  236. ) {
  237. const mod = await import('sentry/components/modals/dashboardWidgetLibraryModal');
  238. const {default: Modal, modalCss} = mod;
  239. openModal(deps => <Modal {...deps} {...options} />, {backdrop: 'static', modalCss});
  240. }
  241. export async function openWidgetViewerModal({
  242. onClose,
  243. ...options
  244. }: WidgetViewerModalOptions & {onClose?: () => void}) {
  245. const mod = await import('sentry/components/modals/widgetViewerModal');
  246. const {default: Modal, modalCss} = mod;
  247. openModal(deps => <Modal {...deps} {...options} />, {
  248. backdrop: 'static',
  249. modalCss,
  250. onClose,
  251. });
  252. }
  253. export async function openCreateNewIntegrationModal(
  254. options: CreateNewIntegrationModalOptions
  255. ) {
  256. const mod = await import('sentry/components/modals/createNewIntegrationModal');
  257. const {default: Modal} = mod;
  258. openModal(deps => <Modal {...deps} {...options} />);
  259. }
  260. export async function openCreateReleaseIntegration(
  261. options: CreateReleaseIntegrationModalOptions
  262. ) {
  263. const mod = await import('sentry/components/modals/createReleaseIntegrationModal');
  264. const {default: Modal} = mod;
  265. openModal(deps => <Modal {...deps} {...options} />);
  266. }