issueActions.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import Form from 'sentry/components/deprecatedforms/form';
  2. import FormState from 'sentry/components/forms/state';
  3. import DefaultIssueActions from 'sentry/plugins/components/issueActions';
  4. import type {Writable} from 'sentry/types/core';
  5. class IssueActions extends DefaultIssueActions {
  6. changeField = (
  7. action: DefaultIssueActions['props']['actionType'],
  8. name: string,
  9. value: any
  10. ) => {
  11. const key = this.getFormDataKey(action);
  12. const formData = {
  13. ...this.state[key],
  14. [name]: value,
  15. };
  16. const state: Pick<Writable<DefaultIssueActions['state']>, 'state' | typeof key> = {
  17. ...this.state,
  18. [key]: formData,
  19. };
  20. if (name === 'issuetype') {
  21. state.state = FormState.LOADING;
  22. this.setState(
  23. state,
  24. this.onLoad.bind(this, () => {
  25. this.api.request(
  26. this.getPluginCreateEndpoint() + '?issuetype=' + encodeURIComponent(value),
  27. {
  28. success: (data: DefaultIssueActions['state']['unlinkFieldList']) => {
  29. // Try not to change things the user might have edited
  30. // unless they're no longer valid
  31. const oldData = this.state.createFormData;
  32. const createFormData = {};
  33. data?.forEach(field => {
  34. let val;
  35. if (
  36. field.choices &&
  37. !field.choices.find(c => c[0] === oldData[field.name])
  38. ) {
  39. val = field.default;
  40. } else {
  41. val = oldData[field.name] || field.default;
  42. }
  43. createFormData[field.name] = val;
  44. });
  45. this.setState(
  46. {
  47. createFieldList: data,
  48. error: undefined,
  49. loading: false,
  50. createFormData,
  51. },
  52. this.onLoadSuccess
  53. );
  54. },
  55. error: this.errorHandler,
  56. }
  57. );
  58. })
  59. );
  60. return;
  61. }
  62. this.setState(state);
  63. };
  64. renderForm(): React.ReactNode {
  65. let form: React.ReactNode = null;
  66. // For create form, split into required and optional fields
  67. if (this.props.actionType === 'create') {
  68. if (this.state.createFieldList) {
  69. const renderField = field => {
  70. if (field.has_autocomplete) {
  71. field = Object.assign(
  72. {
  73. url:
  74. '/api/0/issues/' +
  75. this.getGroup().id +
  76. '/plugins/' +
  77. this.props.plugin.slug +
  78. '/autocomplete',
  79. },
  80. field
  81. );
  82. }
  83. return (
  84. <div key={field.name}>
  85. {this.renderField({
  86. config: field,
  87. formData: this.state.createFormData,
  88. onChange: this.changeField.bind(this, 'create', field.name),
  89. })}
  90. </div>
  91. );
  92. };
  93. const isRequired = f => (f.required !== null ? f.required : true);
  94. const fields = this.state.createFieldList;
  95. const requiredFields = fields.filter(f => isRequired(f)).map(f => renderField(f));
  96. const optionalFields = fields
  97. .filter(f => !isRequired(f))
  98. .map(f => renderField(f));
  99. form = (
  100. <Form onSubmit={this.createIssue} submitLabel="Create Issue" footerClass="">
  101. <h5>Required Fields</h5>
  102. {requiredFields}
  103. {optionalFields.length ? <h5>Optional Fields</h5> : null}
  104. {optionalFields}
  105. </Form>
  106. );
  107. }
  108. } else {
  109. form = super.renderForm();
  110. }
  111. return form;
  112. }
  113. }
  114. export default IssueActions;