foreman_webhooks 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/webhooks_controller.rb +7 -1
  3. data/app/controllers/concerns/foreman_webhooks/controller/parameters/webhook.rb +1 -0
  4. data/app/controllers/webhooks_controller.rb +1 -24
  5. data/app/services/foreman_webhooks/webhook_service.rb +1 -1
  6. data/app/views/foreman_webhooks/webhook_templates/remote_execution_-_host_job.erb +0 -1
  7. data/config/routes.rb +6 -2
  8. data/lib/foreman_webhooks/engine.rb +2 -2
  9. data/lib/foreman_webhooks/version.rb +1 -1
  10. data/package.json +6 -6
  11. data/webpack/ForemanWebhooks/Routes/ForemanWebhooksRoutes.js +2 -2
  12. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/ForemanFormikField.js +117 -0
  13. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/WebhookFormTabs.css +7 -0
  14. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/WebhookFormTabs.js +163 -0
  15. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/WebhookForm.js +69 -0
  16. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/WebhookFormSelectors.js +58 -0
  17. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/__tests__/WebhookForm.test.js +51 -0
  18. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/__tests__/__snapshots__/WebhookForm.test.js.snap +510 -0
  19. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/constants.js +9 -0
  20. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/index.js +73 -0
  21. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/EmptyWebhooksIndexPage/index.js +63 -0
  22. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookCreateModal.js +69 -0
  23. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookDeleteModal.js +1 -0
  24. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookEditModal.js +107 -0
  25. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookEditModalSelectors.js +22 -0
  26. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookModal.scss +6 -0
  27. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/index.js +1 -0
  28. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/nameToEditFormatter.js +19 -0
  29. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/NameToEditCell.js +35 -0
  30. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTable.js +31 -14
  31. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTableSchema.js +12 -4
  32. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/WebhooksTable.test.js +13 -4
  33. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/__snapshots__/WebhooksTable.test.js.snap +62 -19
  34. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/index.js +27 -5
  35. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/WebhooksIndexPage.js +61 -32
  36. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/WebhooksIndexPage.fixtures.js +36 -0
  37. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/WebhooksIndexPage.test.js +3 -1
  38. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/__snapshots__/WebhooksIndexPage.test.js.snap +18 -60
  39. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/__snapshots__/integration.test.js.snap +43 -0
  40. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/integration.test.js +34 -0
  41. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksPageActions.js +3 -0
  42. data/webpack/ForemanWebhooks/Routes/Webhooks/constants.js +11 -1
  43. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +1 -0
  44. data/webpack/__mocks__/foremanReact/common/HOC.js +26 -1
  45. data/webpack/__mocks__/foremanReact/common/urlHelpers.js +7 -0
  46. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +6 -1
  47. data/webpack/__mocks__/foremanReact/components/Loading/Loading.js +2 -0
  48. data/webpack/__mocks__/foremanReact/components/Loading/index.js +3 -0
  49. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +3 -1
  50. data/webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js +9 -0
  51. data/webpack/__mocks__/foremanReact/components/common/forms/FormField.js +3 -0
  52. data/webpack/__mocks__/foremanReact/components/common/table.js +21 -0
  53. data/webpack/__mocks__/foremanReact/history.js +3 -0
  54. data/webpack/__mocks__/foremanReact/redux/actions/common/forms.js +1 -0
  55. data/webpack/test_setup.js +15 -0
  56. metadata +30 -7
  57. data/app/views/webhooks/_form.html.erb +0 -38
  58. data/app/views/webhooks/_templates.html.erb +0 -5
  59. data/app/views/webhooks/edit.html.erb +0 -3
  60. data/app/views/webhooks/new.html.erb +0 -3
  61. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/EmptyWebhooksTable/index.js +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7eefadfce94e1499842423b790e8c387e4f62ce98a1e6b09fe8a9001718b9f1
4
- data.tar.gz: ad0b5f62406983e72601d9a28aa7c8a84d364fb99b9984445b61b459f17446f0
3
+ metadata.gz: 24ca3b029befe6d1a5d05f89f7418861dfaf246e56ec07108d3e5cddbb87196d
4
+ data.tar.gz: 9801e362e3a140aeaec85b02e534069e5c1b3802a2ed970ef341de5ce3ffe1cf
5
5
  SHA512:
6
- metadata.gz: 662cfadd46b2f4cf687623a2383b2d27304464606a19df2dd53825accb75668381edada4d3c614705940773cf390a5e31d53c10f2aa4171f94cf690e5023992b
7
- data.tar.gz: 10a37322e66de2ca65a93313b9bfc60b53e35ee1cad0ff599c88ca68f5b888829c3f235747458b13f3735ce315164e117bda4dc5b018f7e050f276c0c84070a2
6
+ metadata.gz: 726f0cdf6c8f7a1c4f3e691020e0fc1e64c0ae76dc9f4bec8864d972025075b2c3f00d9b74360543de4a237ccbe1b8e5f8484cbae4b059c4f633afc32dec63da
7
+ data.tar.gz: 5617358f79addd62638f92dc6669a2088e44bf808997f8ce91853ea307d2d29fd6af5948841579340f17adf06b3266a8703ab4d47181ebdddb6be6c59acf17ee
@@ -6,7 +6,7 @@ module Api
6
6
  include Api::Version2
7
7
  include ForemanWebhooks::Controller::Parameters::Webhook
8
8
 
9
- before_action :find_resource, only: %i[show update destroy]
9
+ before_action :find_resource, only: %i[show destroy]
10
10
 
11
11
  api :GET, '/webhooks/', N_('List Webhooks')
12
12
  param_group :search_and_pagination, ::Api::V2::BaseController
@@ -50,6 +50,7 @@ module Api
50
50
  param :id, :identifier, required: true
51
51
  param_group :webhook, as: :update
52
52
  def update
53
+ @webhook = Webhook.find(params[:id])
53
54
  process_response @webhook.update(webhook_params)
54
55
  end
55
56
 
@@ -58,6 +59,11 @@ module Api
58
59
  def destroy
59
60
  process_response @webhook.destroy
60
61
  end
62
+
63
+ api :GET, '/webhooks/events', N_('List available events for subscription')
64
+ def events
65
+ render json: Webhook.available_events.sort.map { |e| e.delete_suffix(Webhook::EVENT_POSTFIX) }.to_json
66
+ end
61
67
  end
62
68
  end
63
69
  end
@@ -27,6 +27,7 @@ module ForemanWebhooks
27
27
  end
28
28
 
29
29
  def webhook_params
30
+ params['webhook']['event'] = params['event'] unless params['event'].blank?
30
31
  self.class.webhook_params_filter.filter_params(params, parameter_filter_context)
31
32
  end
32
33
  end
@@ -4,30 +4,7 @@ class WebhooksController < ::ApplicationController
4
4
  include ForemanWebhooks::Controller::Parameters::Webhook
5
5
  include Foreman::Controller::AutoCompleteSearch
6
6
 
7
- before_action :find_resource, only: %i[edit update destroy]
8
-
9
- def new
10
- @webhook = Webhook.new
11
- end
12
-
13
- def create
14
- @webhook = Webhook.new(webhook_params)
15
- if @webhook.save
16
- process_success success_redirect: '/webhooks'
17
- else
18
- process_error
19
- end
20
- end
21
-
22
- def edit; end
23
-
24
- def update
25
- if @webhook.update(webhook_params)
26
- process_success success_redirect: '/webhooks'
27
- else
28
- process_error
29
- end
30
- end
7
+ before_action :find_resource, only: %i[destroy]
31
8
 
32
9
  def destroy
33
10
  if @webhook.destroy
@@ -95,7 +95,7 @@ module ForemanWebhooks
95
95
  uri = URI.parse(url)
96
96
 
97
97
  request = Object.const_get("Net::HTTP::#{http_method.to_s.capitalize}").new(uri.request_uri)
98
- request.basic_auth(user, password) if user && password
98
+ request.basic_auth(user, password) if !user.blank? && !password.blank?
99
99
  request['Content-Type'] = content_type
100
100
  request['X-Request-Id'] = ::Logging.mdc['request'] || SecureRandom.uuid
101
101
  request['X-Session-Id'] = ::Logging.mdc['session'] || SecureRandom.uuid
@@ -18,4 +18,3 @@ model: WebhookTemplate
18
18
  # Task ended at <%= @object.task.ended_at %>
19
19
  # Task resulted with <%= @object.task.result %>
20
20
  # Task state <%= @object.task.state %>
21
- # Task action output <%= @object.task.action_output %>
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Rails.application.routes.draw do
4
- resources :webhooks, except: %i[index show] do
4
+ resources :webhooks, except: %i[index show new edit update] do
5
5
  collection do
6
6
  get 'auto_complete_search'
7
7
  end
@@ -14,7 +14,11 @@ Rails.application.routes.draw do
14
14
  defaults: { apiv: 'v2' },
15
15
  apiv: /v1|v2/,
16
16
  constraints: ApiConstraints.new(version: 2, default: true) do
17
- resources :webhooks, only: %i[index show create update destroy]
17
+ resources :webhooks, only: %i[index show create update destroy] do
18
+ collection do
19
+ get :events
20
+ end
21
+ end
18
22
  resources :webhook_templates, except: %i[new edit] do
19
23
  member do
20
24
  post :clone
@@ -15,7 +15,7 @@ module ForemanWebhooks
15
15
 
16
16
  initializer 'foreman_webhooks.register_plugin', before: :finisher_hook do |_app|
17
17
  Foreman::Plugin.register :foreman_webhooks do
18
- requires_foreman '>= 2.3'
18
+ requires_foreman '>= 2.5'
19
19
 
20
20
  apipie_documented_controllers ["#{ForemanWebhooks::Engine.root}/app/controllers/api/v2/*.rb"]
21
21
  ApipieDSL.configuration.sections += ['webhooks']
@@ -28,7 +28,7 @@ module ForemanWebhooks
28
28
  # Add permissions
29
29
  security_block :foreman_webhooks do
30
30
  permission :view_webhooks, { webhooks: %i[index show auto_complete_search],
31
- 'api/v2/webhooks': %i[index show] }, resource_type: 'Webhook'
31
+ 'api/v2/webhooks': %i[index show events] }, resource_type: 'Webhook'
32
32
  permission :create_webhooks, { webhooks: %i[new create],
33
33
  'api/v2/webhooks': [:create] }, resource_type: 'Webhook'
34
34
  permission :edit_webhooks, { webhooks: %i[edit update],
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanWebhooks
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
data/package.json CHANGED
@@ -21,15 +21,15 @@
21
21
  "url": "https://projects.theforeman.org/projects/webhooks/issues"
22
22
  },
23
23
  "peerDependencies": {
24
- "@theforeman/vendor": ">= 4.15.1"
24
+ "@theforeman/vendor": ">= 8.4.1"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@babel/core": "^7.7.0",
28
- "@theforeman/builder": "^4.15.1",
29
- "@theforeman/stories": "^4.15.1",
30
- "@theforeman/test": "^4.15.1",
31
- "@theforeman/vendor-dev": "^4.15.1",
32
- "@theforeman/eslint-plugin-foreman": "^4.15.1",
28
+ "@theforeman/builder": "^8.4.1",
29
+ "@theforeman/stories": "^8.4.1",
30
+ "@theforeman/test": "^8.4.1",
31
+ "@theforeman/vendor-dev": "^8.4.1",
32
+ "@theforeman/eslint-plugin-foreman": "^8.4.1",
33
33
  "babel-eslint": "^10.0.0",
34
34
  "eslint": "^6.8.0",
35
35
  "eslint-plugin-spellcheck": "^0.0.17",
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
- import WebhooksIndexPage from './Webhooks/WebhooksIndexPage';
2
+ import ConnectedWebhooksIndexPage from './Webhooks/WebhooksIndexPage';
3
3
 
4
4
  const ForemanWebhooksRoutes = [
5
5
  {
6
6
  path: '/webhooks',
7
7
  exact: true,
8
- render: props => <WebhooksIndexPage {...props} />,
8
+ render: props => <ConnectedWebhooksIndexPage {...props} />,
9
9
  },
10
10
  ];
11
11
 
@@ -0,0 +1,117 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Field as FormikField } from 'formik';
4
+ import { Spinner } from '@patternfly/react-core';
5
+ import { TypeAheadSelect } from 'patternfly-react';
6
+ import { filter } from 'lodash';
7
+
8
+ import { translate as __ } from 'foremanReact/common/I18n';
9
+
10
+ import FormField from 'foremanReact/components/common/forms/FormField';
11
+
12
+ const ForemanFormikField = ({
13
+ name,
14
+ type,
15
+ required,
16
+ label,
17
+ labelHelp,
18
+ inputSizeClass,
19
+ labelSizeClass,
20
+ rows,
21
+ placeholder,
22
+ options,
23
+ isLoading,
24
+ }) => (
25
+ <FormikField name={name}>
26
+ {({
27
+ field, // { name, value, onChange, onBlur }
28
+ form: { touched, errors, setFieldValue, setFieldTouched }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
29
+ }) => {
30
+ const defaultSelection = (fieldValue, initialOptions) => {
31
+ if (!fieldValue) return [];
32
+
33
+ return filter(initialOptions, o => o.value === fieldValue);
34
+ };
35
+ let content = null;
36
+ switch (type) {
37
+ case 'textarea':
38
+ content = (
39
+ <textarea
40
+ {...field}
41
+ className="form-control"
42
+ rows={rows}
43
+ placeholder={placeholder}
44
+ />
45
+ );
46
+ break;
47
+ case 'select':
48
+ content = isLoading ? (
49
+ <Spinner size="md" aria-label="loading icon" />
50
+ ) : (
51
+ <TypeAheadSelect
52
+ id={name}
53
+ options={options}
54
+ placeholder={__('Start typing to search')}
55
+ selected={defaultSelection(field.value, options)}
56
+ onChange={selected =>
57
+ setFieldValue(field.name, selected[0]?.value)
58
+ }
59
+ // onBlur={e => setFieldTouched(field.name, true)}
60
+ />
61
+ );
62
+ break;
63
+ default:
64
+ content = (
65
+ <input
66
+ {...field}
67
+ type={type}
68
+ checked={type === 'checkbox' ? field.value || '' : undefined}
69
+ className={type === 'checkbox' ? '' : 'form-control'}
70
+ />
71
+ );
72
+ }
73
+ return (
74
+ <FormField
75
+ {...field}
76
+ error={touched[name] ? errors[name] : undefined}
77
+ type={type}
78
+ inputSizeClass={inputSizeClass}
79
+ labelSizeClass={labelSizeClass}
80
+ required={required}
81
+ label={label}
82
+ labelHelp={labelHelp}
83
+ options={options}
84
+ >
85
+ {content}
86
+ </FormField>
87
+ );
88
+ }}
89
+ </FormikField>
90
+ );
91
+
92
+ ForemanFormikField.propTypes = {
93
+ name: PropTypes.string.isRequired,
94
+ type: PropTypes.string.isRequired,
95
+ required: PropTypes.bool,
96
+ label: PropTypes.string.isRequired,
97
+ labelHelp: PropTypes.string,
98
+ inputSizeClass: PropTypes.string,
99
+ labelSizeClass: PropTypes.string,
100
+ rows: PropTypes.number,
101
+ placeholder: PropTypes.string,
102
+ options: PropTypes.array,
103
+ isLoading: PropTypes.bool,
104
+ };
105
+
106
+ ForemanFormikField.defaultProps = {
107
+ required: false,
108
+ labelHelp: null,
109
+ inputSizeClass: 'col-md-8',
110
+ labelSizeClass: 'col-md-3',
111
+ rows: 1,
112
+ placeholder: '',
113
+ options: null,
114
+ isLoading: false,
115
+ };
116
+
117
+ export default ForemanFormikField;
@@ -0,0 +1,7 @@
1
+ .webhook-form-tab-content {
2
+ padding-top: 3em;
3
+ }
4
+
5
+ .webhook-form-tab:focus {
6
+ outline: none;
7
+ }
@@ -0,0 +1,163 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Tabs, Tab, TabTitleText } from '@patternfly/react-core';
4
+
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+
7
+ import ForemanFormikField from './ForemanFormikField';
8
+
9
+ import './WebhookFormTabs.css';
10
+
11
+ const WebhookFormTabs = ({
12
+ formProps,
13
+ disabled,
14
+ activeTab,
15
+ handleTabClick,
16
+ webhookTemplates,
17
+ httpMethods,
18
+ availableEvents,
19
+ isTemplatesLoading,
20
+ isEventsLoading,
21
+ }) => (
22
+ <Tabs activeKey={activeTab} onSelect={handleTabClick} isFilled>
23
+ <Tab
24
+ className="webhook-form-tab"
25
+ eventKey={0}
26
+ title={<TabTitleText>{__('General')}</TabTitleText>}
27
+ >
28
+ <div className="webhook-form-tab-content">
29
+ <ForemanFormikField
30
+ name="event"
31
+ type="select"
32
+ label={__('Subscribe to')}
33
+ required
34
+ allowClear={false}
35
+ options={availableEvents}
36
+ isLoading={isEventsLoading}
37
+ />
38
+ <ForemanFormikField
39
+ name="name"
40
+ type="text"
41
+ required
42
+ label={__('Name')}
43
+ />
44
+ <ForemanFormikField
45
+ name="target_url"
46
+ type="text"
47
+ required
48
+ label={__('Target URL')}
49
+ labelHelp={__('Target URL that should be called by Foreman')}
50
+ />
51
+ <ForemanFormikField
52
+ name="webhook_template_id"
53
+ type="select"
54
+ label={__('Template')}
55
+ required
56
+ allowClear={false}
57
+ options={webhookTemplates}
58
+ isLoading={isTemplatesLoading}
59
+ />
60
+ <ForemanFormikField
61
+ name="http_method"
62
+ type="select"
63
+ label={__('HTTP Method')}
64
+ required
65
+ allowClear={false}
66
+ options={httpMethods}
67
+ />
68
+ <ForemanFormikField
69
+ name="enabled"
70
+ type="checkbox"
71
+ label={__('Enabled')}
72
+ labelHelp={__('If unchecked, the webhook will be inactive')}
73
+ />
74
+ </div>
75
+ </Tab>
76
+ <Tab
77
+ className="webhook-form-tab"
78
+ eventKey={1}
79
+ title={<TabTitleText>{__('Credentials')}</TabTitleText>}
80
+ >
81
+ <div className="webhook-form-tab-content">
82
+ <ForemanFormikField
83
+ name="user"
84
+ type="text"
85
+ label={__('User')}
86
+ labelHelp={__('Authentication credentials')}
87
+ />
88
+ <ForemanFormikField
89
+ name="password"
90
+ type="password"
91
+ label={__('Password')}
92
+ labelHelp={__('Authentication credentials')}
93
+ />
94
+ <ForemanFormikField
95
+ name="verify_ssl"
96
+ type="checkbox"
97
+ label={__('Verify SSL')}
98
+ labelHelp={__(
99
+ "Uncheck this option to disable validation of the receiver's SSL certificate"
100
+ )}
101
+ />
102
+ <ForemanFormikField
103
+ name="proxy_authorization"
104
+ type="checkbox"
105
+ label={__('Proxy Authorization')}
106
+ labelHelp={__(
107
+ 'Authorize with Foreman client certificate and validate smart-proxy CA from Settings'
108
+ )}
109
+ />
110
+ <ForemanFormikField
111
+ name="ssl_ca_certs"
112
+ type="textarea"
113
+ label={__('X509 Certification Authorities')}
114
+ placeholder={__(
115
+ "Optional CAs in PEM format concatenated to verify the receiver's SSL certificate"
116
+ )}
117
+ inputSizeClass="col-md-8"
118
+ rows={8}
119
+ />
120
+ </div>
121
+ </Tab>
122
+ <Tab
123
+ className="webhook-form-tab"
124
+ eventKey={2}
125
+ title={<TabTitleText>{__('Additional')}</TabTitleText>}
126
+ >
127
+ <div className="webhook-form-tab-content">
128
+ <ForemanFormikField
129
+ name="http_content_type"
130
+ type="text"
131
+ label={__('HTTP Content Type')}
132
+ />
133
+ <ForemanFormikField
134
+ name="http_headers"
135
+ type="textarea"
136
+ label={__('Optional HTTP headers as JSON (ERB allowed)')}
137
+ placeholder='{\n"X-Shellhook-Arg-1": "value"\n}'
138
+ inputSizeClass="col-md-8"
139
+ rows={8}
140
+ />
141
+ </div>
142
+ </Tab>
143
+ </Tabs>
144
+ );
145
+
146
+ WebhookFormTabs.propTypes = {
147
+ formProps: PropTypes.object,
148
+ disabled: PropTypes.bool,
149
+ activeTab: PropTypes.number.isRequired,
150
+ handleTabClick: PropTypes.func.isRequired,
151
+ webhookTemplates: PropTypes.array.isRequired,
152
+ httpMethods: PropTypes.array.isRequired,
153
+ availableEvents: PropTypes.array.isRequired,
154
+ isTemplatesLoading: PropTypes.bool.isRequired,
155
+ isEventsLoading: PropTypes.bool.isRequired,
156
+ };
157
+
158
+ WebhookFormTabs.defaultProps = {
159
+ disabled: false,
160
+ formProps: {},
161
+ };
162
+
163
+ export default WebhookFormTabs;