form.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import styled from '@emotion/styled';
  2. import Textarea from 'sentry/components/forms/controls/textarea';
  3. import Field from 'sentry/components/forms/field';
  4. import FieldHelp from 'sentry/components/forms/field/fieldHelp';
  5. import TextCopyInput from 'sentry/components/forms/textCopyInput';
  6. import Input from 'sentry/components/input';
  7. import {t} from 'sentry/locale';
  8. import space from 'sentry/styles/space';
  9. import {Relay} from 'sentry/types';
  10. type FormField = keyof Pick<Relay, 'name' | 'publicKey' | 'description'>;
  11. type Values = Record<FormField, string>;
  12. type Props = {
  13. disables: Partial<Record<FormField, boolean>>;
  14. errors: Partial<Values>;
  15. isFormValid: boolean;
  16. onChange: (field: FormField, value: string) => void;
  17. onSave: () => void;
  18. onValidate: (field: FormField) => () => void;
  19. onValidateKey: () => void;
  20. values: Values;
  21. };
  22. const Form = ({
  23. values,
  24. onChange,
  25. errors,
  26. onValidate,
  27. isFormValid,
  28. disables,
  29. onValidateKey,
  30. onSave,
  31. }: Props) => {
  32. const handleChange =
  33. (field: FormField) =>
  34. (
  35. event: React.ChangeEvent<HTMLTextAreaElement> | React.ChangeEvent<HTMLInputElement>
  36. ) => {
  37. onChange(field, event.target.value);
  38. };
  39. const handleSubmit = () => {
  40. if (isFormValid) {
  41. onSave();
  42. }
  43. };
  44. // code below copied from app/views/organizationIntegrations/SplitInstallationIdModal.tsx
  45. // TODO: fix the common method selectText
  46. const onCopy = (value: string) => async () =>
  47. // This hack is needed because the normal copying methods with TextCopyInput do not work correctly
  48. await navigator.clipboard.writeText(value);
  49. return (
  50. <form onSubmit={handleSubmit} id="relay-form">
  51. <Field
  52. flexibleControlStateSize
  53. label={t('Display Name')}
  54. error={errors.name}
  55. inline={false}
  56. stacked
  57. required
  58. >
  59. <Input
  60. type="text"
  61. name="name"
  62. placeholder={t('Display Name')}
  63. onChange={handleChange('name')}
  64. value={values.name}
  65. onBlur={onValidate('name')}
  66. disabled={disables.name}
  67. />
  68. </Field>
  69. {disables.publicKey ? (
  70. <Field flexibleControlStateSize label={t('Public Key')} inline={false} stacked>
  71. <TextCopyInput onCopy={onCopy(values.publicKey)}>
  72. {values.publicKey}
  73. </TextCopyInput>
  74. </Field>
  75. ) : (
  76. <FieldWrapper>
  77. <StyledField
  78. label={t('Public Key')}
  79. error={errors.publicKey}
  80. flexibleControlStateSize
  81. inline={false}
  82. stacked
  83. required
  84. >
  85. <Input
  86. type="text"
  87. name="publicKey"
  88. placeholder={t('Public Key')}
  89. onChange={handleChange('publicKey')}
  90. value={values.publicKey}
  91. onBlur={onValidateKey}
  92. />
  93. </StyledField>
  94. <FieldHelp>
  95. {t(
  96. 'Only enter the Public Key value from your credentials file. Never share the Secret key with Sentry or any third party'
  97. )}
  98. </FieldHelp>
  99. </FieldWrapper>
  100. )}
  101. <Field flexibleControlStateSize label={t('Description')} inline={false} stacked>
  102. <Textarea
  103. name="description"
  104. placeholder={t('Description')}
  105. onChange={handleChange('description')}
  106. value={values.description}
  107. disabled={disables.description}
  108. autosize
  109. />
  110. </Field>
  111. </form>
  112. );
  113. };
  114. export default Form;
  115. const FieldWrapper = styled('div')`
  116. padding-bottom: ${space(2)};
  117. `;
  118. const StyledField = styled(Field)`
  119. padding-bottom: 0;
  120. `;