genericField.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import BooleanField from 'sentry/components/deprecatedforms/booleanField';
  2. import EmailField from 'sentry/components/deprecatedforms/emailField';
  3. import FormField from 'sentry/components/deprecatedforms/formField';
  4. import NumberField from 'sentry/components/deprecatedforms/numberField';
  5. import PasswordField from 'sentry/components/deprecatedforms/passwordField';
  6. import SelectAsyncField from 'sentry/components/deprecatedforms/selectAsyncField';
  7. import SelectCreatableField from 'sentry/components/deprecatedforms/selectCreatableField';
  8. import SelectField from 'sentry/components/deprecatedforms/selectField';
  9. import TextareaField from 'sentry/components/deprecatedforms/textareaField';
  10. import TextField from 'sentry/components/deprecatedforms/textField';
  11. import FormState from 'sentry/components/forms/state';
  12. import {defined} from 'sentry/utils';
  13. type FieldType =
  14. | 'secret'
  15. | 'range'
  16. | 'bool'
  17. | 'email'
  18. | 'string'
  19. | 'text'
  20. | 'url'
  21. | 'number'
  22. | 'textarea';
  23. type SelectFieldType = 'select' | 'choice';
  24. type Config = {
  25. choices: Array<[number | string, number | string]>;
  26. default: string;
  27. name: string;
  28. placeholder: string;
  29. readonly: boolean;
  30. type: FieldType;
  31. help?: string;
  32. label?: string;
  33. required?: boolean;
  34. };
  35. type SelectFieldConfig = Omit<Config, 'type' | 'has_autocomplete'> & {
  36. has_autocomplete: false;
  37. type: SelectFieldType;
  38. };
  39. type AsyncSelectFieldConfig = Omit<SelectFieldConfig, 'has_autocomplete'> & {
  40. has_autocomplete: true;
  41. url: string;
  42. };
  43. interface FormData {
  44. [name: string]: string;
  45. }
  46. type Props = {
  47. config: Config | SelectFieldConfig | AsyncSelectFieldConfig;
  48. formData: FormData;
  49. formState: typeof FormState[keyof typeof FormState];
  50. onChange: FormField['props']['onChange'];
  51. formErrors?: object;
  52. };
  53. const GenericField = ({
  54. config,
  55. formData = {},
  56. formErrors = {},
  57. formState,
  58. onChange,
  59. }: Props) => {
  60. const required = defined(config.required) ? config.required : true;
  61. const fieldProps = {
  62. ...config,
  63. value: formData[config.name],
  64. onChange,
  65. label: config.label + (required ? '*' : ''),
  66. placeholder: config.placeholder,
  67. required,
  68. name: config.name,
  69. error: (formErrors || {})[config.name],
  70. defaultValue: config.default,
  71. disabled: config.readonly,
  72. key: config.name,
  73. formState,
  74. help:
  75. defined(config.help) && config.help !== '' ? (
  76. <span dangerouslySetInnerHTML={{__html: config.help}} />
  77. ) : null,
  78. };
  79. switch (config.type) {
  80. case 'secret':
  81. return <PasswordField {...fieldProps} />;
  82. case 'bool':
  83. return <BooleanField {...fieldProps} />;
  84. case 'email':
  85. return <EmailField {...fieldProps} />;
  86. case 'string':
  87. case 'text':
  88. case 'url':
  89. if (fieldProps.choices) {
  90. return <SelectCreatableField {...fieldProps} />;
  91. }
  92. return <TextField {...fieldProps} />;
  93. case 'number':
  94. return <NumberField {...fieldProps} />;
  95. case 'textarea':
  96. return <TextareaField {...fieldProps} />;
  97. case 'choice':
  98. case 'select':
  99. // the chrome required tip winds up in weird places
  100. // for select elements, so just make it look like
  101. // it's required (with *) and rely on server validation
  102. const {required: _, ...selectProps} = fieldProps;
  103. if (config.has_autocomplete) {
  104. // Redeclaring field props here as config has been narrowed to include the correct options for SelectAsyncField
  105. const selectFieldProps = {
  106. ...config,
  107. ...selectProps,
  108. };
  109. return <SelectAsyncField {...selectFieldProps} />;
  110. }
  111. return <SelectField {...selectProps} />;
  112. default:
  113. return null;
  114. }
  115. };
  116. export default GenericField;