index.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import {Fragment} from 'react';
  2. // eslint-disable-next-line no-restricted-imports
  3. import {withRouter, WithRouterProps} from 'react-router';
  4. import {css} from '@emotion/react';
  5. import {ModalRenderProps} from 'sentry/actionCreators/modal';
  6. import Feature from 'sentry/components/acl/feature';
  7. import FeatureDisabled from 'sentry/components/acl/featureDisabled';
  8. import FieldFromConfig from 'sentry/components/forms/fieldFromConfig';
  9. import Form from 'sentry/components/forms/form';
  10. import HookOrDefault from 'sentry/components/hookOrDefault';
  11. import {getDebugSourceName} from 'sentry/data/debugFileSources';
  12. import {t, tct} from 'sentry/locale';
  13. import {Organization} from 'sentry/types';
  14. import {AppStoreConnectStatusData, CustomRepoType} from 'sentry/types/debugFiles';
  15. import AppStoreConnect from './appStoreConnect';
  16. import Http from './http';
  17. import {getFinalData, getFormFieldsAndInitialData} from './utils';
  18. type AppStoreConnectInitialData = React.ComponentProps<
  19. typeof AppStoreConnect
  20. >['initialData'];
  21. type HttpInitialData = React.ComponentProps<typeof Http>['initialData'];
  22. type RouteParams = {
  23. orgId: string;
  24. projectId: string;
  25. };
  26. type Props = WithRouterProps<RouteParams, {}> & {
  27. appStoreConnectSourcesQuantity: number;
  28. /**
  29. * Callback invoked with the updated config value.
  30. */
  31. onSave: (data: Record<string, any>) => Promise<void>;
  32. organization: Organization;
  33. /**
  34. * Type of this source.
  35. */
  36. sourceType: CustomRepoType;
  37. appStoreConnectStatusData?: AppStoreConnectStatusData;
  38. /**
  39. * The sourceConfig. May be empty to create a new one.
  40. */
  41. sourceConfig?: Record<string, any>;
  42. } & Pick<ModalRenderProps, 'Header' | 'Body' | 'Footer' | 'closeModal' | 'CloseButton'>;
  43. const HookedAppStoreConnectMultiple = HookOrDefault({
  44. hookName: 'component:disabled-app-store-connect-multiple',
  45. defaultComponent: ({children}) => <Fragment>{children}</Fragment>,
  46. });
  47. const HookedCustomSymbolSources = HookOrDefault({
  48. hookName: 'component:disabled-custom-symbol-sources',
  49. defaultComponent: ({children}) => <Fragment>{children}</Fragment>,
  50. });
  51. function DebugFileCustomRepository({
  52. Header,
  53. Body,
  54. Footer,
  55. CloseButton,
  56. onSave,
  57. sourceConfig,
  58. sourceType,
  59. params: {orgId, projectId: projectSlug},
  60. appStoreConnectStatusData,
  61. closeModal,
  62. organization,
  63. appStoreConnectSourcesQuantity,
  64. }: Props) {
  65. function handleSave(data?: Record<string, any>) {
  66. if (!data) {
  67. closeModal();
  68. window.location.reload();
  69. return;
  70. }
  71. onSave({...getFinalData(sourceType, data), type: sourceType}).then(() => {
  72. closeModal();
  73. });
  74. }
  75. if (sourceType === CustomRepoType.APP_STORE_CONNECT) {
  76. return (
  77. <Feature organization={organization} features={['app-store-connect-multiple']}>
  78. {({hasFeature, features}) => {
  79. if (
  80. hasFeature ||
  81. (appStoreConnectSourcesQuantity === 1 && sourceConfig) ||
  82. appStoreConnectSourcesQuantity === 0
  83. ) {
  84. return (
  85. <AppStoreConnect
  86. Header={Header}
  87. Body={Body}
  88. Footer={Footer}
  89. orgSlug={orgId}
  90. projectSlug={projectSlug}
  91. onSubmit={handleSave}
  92. initialData={sourceConfig as AppStoreConnectInitialData}
  93. appStoreConnectStatusData={appStoreConnectStatusData}
  94. />
  95. );
  96. }
  97. return (
  98. <Fragment>
  99. <CloseButton />
  100. <HookedAppStoreConnectMultiple organization={organization}>
  101. <FeatureDisabled
  102. features={features}
  103. featureName={t('App Store Connect Multiple')}
  104. hideHelpToggle
  105. />
  106. </HookedAppStoreConnectMultiple>
  107. </Fragment>
  108. );
  109. }}
  110. </Feature>
  111. );
  112. }
  113. return (
  114. <Feature organization={organization} features={['custom-symbol-sources']}>
  115. {({hasFeature, features}) => {
  116. if (hasFeature) {
  117. if (sourceType === CustomRepoType.HTTP) {
  118. return (
  119. <Http
  120. Header={Header}
  121. Body={Body}
  122. Footer={Footer}
  123. onSubmit={handleSave}
  124. initialData={sourceConfig as HttpInitialData}
  125. />
  126. );
  127. }
  128. const {initialData, fields} = getFormFieldsAndInitialData(
  129. sourceType,
  130. sourceConfig
  131. );
  132. return (
  133. <Fragment>
  134. <Header closeButton>
  135. {sourceConfig
  136. ? tct('Update [name] Repository', {
  137. name: getDebugSourceName(sourceType),
  138. })
  139. : tct('Add [name] Repository', {name: getDebugSourceName(sourceType)})}
  140. </Header>
  141. {fields && (
  142. <Form
  143. allowUndo
  144. requireChanges
  145. initialData={initialData}
  146. onSubmit={handleSave}
  147. footerClass="modal-footer"
  148. >
  149. {fields.map((field, i) => (
  150. <FieldFromConfig
  151. key={field.name || i}
  152. field={field}
  153. inline={false}
  154. stacked
  155. />
  156. ))}
  157. </Form>
  158. )}
  159. </Fragment>
  160. );
  161. }
  162. return (
  163. <Fragment>
  164. <CloseButton />
  165. <HookedCustomSymbolSources organization={organization}>
  166. <FeatureDisabled
  167. features={features}
  168. featureName={t('Custom Symbol Sources')}
  169. hideHelpToggle
  170. />
  171. </HookedCustomSymbolSources>
  172. </Fragment>
  173. );
  174. }}
  175. </Feature>
  176. );
  177. }
  178. export default withRouter(DebugFileCustomRepository);
  179. export const modalCss = css`
  180. width: 100%;
  181. max-width: 680px;
  182. `;