customResolutionModal.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import {Fragment, useState} from 'react';
  2. import type {ModalRenderProps} from 'sentry/actionCreators/modal';
  3. import {Button} from 'sentry/components/button';
  4. import SelectAsyncField from 'sentry/components/deprecatedforms/selectAsyncField';
  5. import TimeSince from 'sentry/components/timeSince';
  6. import Version from 'sentry/components/version';
  7. import {t} from 'sentry/locale';
  8. import configStore from 'sentry/stores/configStore';
  9. import {space} from 'sentry/styles/space';
  10. import type {Organization, Release} from 'sentry/types';
  11. import {isVersionInfoSemver} from 'sentry/views/releases/utils';
  12. interface CustomResolutionModalProps extends ModalRenderProps {
  13. onSelected: (change: {inRelease: string}) => void;
  14. organization: Organization;
  15. projectSlug?: string;
  16. }
  17. function CustomResolutionModal(props: CustomResolutionModalProps) {
  18. const [version, setVersion] = useState('');
  19. const currentUser = configStore.get('user');
  20. const onChange = (selection: string | number | boolean) => {
  21. setVersion(selection as string);
  22. };
  23. const onAsyncFieldResults = (results: Release[]) => {
  24. return results.map(release => {
  25. const isAuthor = release.authors.some(
  26. author => author.email && author.email === currentUser?.email
  27. );
  28. return {
  29. value: release.version,
  30. label: (
  31. <Fragment>
  32. <Version version={release.version} anchor={false} />{' '}
  33. {isVersionInfoSemver(release.versionInfo.version)
  34. ? t('(semver)')
  35. : t('(non-semver)')}
  36. </Fragment>
  37. ),
  38. textValue: release.versionInfo.description ?? release.version,
  39. details: (
  40. <span>
  41. {t('Created')} <TimeSince date={release.dateCreated} />
  42. {isAuthor ? <Fragment> — {t('You committed')}</Fragment> : null}
  43. </span>
  44. ),
  45. release,
  46. };
  47. });
  48. };
  49. const url = props.projectSlug
  50. ? `/projects/${props.organization.slug}/${props.projectSlug}/releases/`
  51. : `/organizations/${props.organization.slug}/releases/`;
  52. const onSubmit = (e: React.FormEvent) => {
  53. e.preventDefault();
  54. props.onSelected({inRelease: version});
  55. props.closeModal();
  56. };
  57. const {Header, Body, Footer} = props;
  58. return (
  59. <form onSubmit={onSubmit}>
  60. <Header>
  61. <h4>{t('Resolved In')}</h4>
  62. </Header>
  63. <Body>
  64. <SelectAsyncField
  65. label={t('Version')}
  66. id="version"
  67. name="version"
  68. onChange={onChange}
  69. placeholder={t('e.g. 1.0.4')}
  70. url={url}
  71. onResults={onAsyncFieldResults}
  72. onQuery={query => ({query})}
  73. />
  74. </Body>
  75. <Footer>
  76. <Button css={{marginRight: space(1.5)}} onClick={props.closeModal}>
  77. {t('Cancel')}
  78. </Button>
  79. <Button type="submit" priority="primary">
  80. {t('Resolve')}
  81. </Button>
  82. </Footer>
  83. </form>
  84. );
  85. }
  86. export default CustomResolutionModal;