webhooks-rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +20 -0
- data/app/assets/config/webhooks_manifest.js +1 -0
- data/app/assets/stylesheets/webhooks/application.css +15 -0
- data/app/controllers/webhooks/application_controller.rb +6 -0
- data/app/controllers/webhooks/attempts_controller.rb +25 -0
- data/app/controllers/webhooks/endpoints_controller.rb +65 -0
- data/app/controllers/webhooks/events_controller.rb +37 -0
- data/app/helpers/webhooks/application_helper.rb +6 -0
- data/app/jobs/webhooks/application_job.rb +6 -0
- data/app/jobs/webhooks/deliver_job.rb +11 -0
- data/app/mailers/webhooks/application_mailer.rb +8 -0
- data/app/models/webhooks/application_record.rb +7 -0
- data/app/models/webhooks/attempt.rb +71 -0
- data/app/models/webhooks/endpoint.rb +74 -0
- data/app/models/webhooks/event.rb +50 -0
- data/app/models/webhooks/event_serializer.rb +30 -0
- data/app/models/webhooks/request.rb +37 -0
- data/app/models/webhooks/response.rb +29 -0
- data/app/views/layouts/webhooks/application.html.erb +29 -0
- data/app/views/webhooks/attempts/_attempt.html.erb +32 -0
- data/app/views/webhooks/attempts/show.html.erb +33 -0
- data/app/views/webhooks/endpoints/_endpoint.html.erb +31 -0
- data/app/views/webhooks/endpoints/_form.html.erb +42 -0
- data/app/views/webhooks/endpoints/edit.html.erb +16 -0
- data/app/views/webhooks/endpoints/index.html.erb +41 -0
- data/app/views/webhooks/endpoints/new.html.erb +16 -0
- data/app/views/webhooks/endpoints/show.html.erb +102 -0
- data/app/views/webhooks/events/_event.html.erb +11 -0
- data/app/views/webhooks/events/index.html.erb +38 -0
- data/app/views/webhooks/events/new.html.erb +35 -0
- data/app/views/webhooks/events/show.html.erb +49 -0
- data/app/views/webhooks/requests/_request.html.erb +47 -0
- data/app/views/webhooks/responses/_response.html.erb +55 -0
- data/app/views/webhooks/shared/_navigation.html.erb +100 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20210518022959_create_webhooks_endpoints.rb +17 -0
- data/db/migrate/20210518043350_create_webhooks_events.rb +12 -0
- data/db/migrate/20210518050123_create_webhooks_attempts.rb +36 -0
- data/db/migrate/20210518054916_create_webhooks_requests.rb +14 -0
- data/db/migrate/20210518060614_create_webhooks_responses.rb +15 -0
- data/lib/tasks/webhooks_tasks.rake +5 -0
- data/lib/webhooks-rails.rb +3 -0
- data/lib/webhooks.rb +21 -0
- data/lib/webhooks/engine.rb +31 -0
- data/lib/webhooks/version.rb +5 -0
- metadata +183 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Webhooks
|
4
|
+
class EventSerializer
|
5
|
+
include ActiveModel::Serializers::JSON
|
6
|
+
|
7
|
+
attr_reader :id
|
8
|
+
attr_reader :type
|
9
|
+
attr_reader :event
|
10
|
+
attr_reader :created_at
|
11
|
+
|
12
|
+
def initialize(request)
|
13
|
+
event = request.event
|
14
|
+
|
15
|
+
@id = event.id
|
16
|
+
@type = event.event_type
|
17
|
+
@event = ActiveSupport::JSON.decode(event.event)
|
18
|
+
@created_at = event.created_at.iso8601(6)
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes
|
22
|
+
{
|
23
|
+
'id' => id,
|
24
|
+
'type' => type,
|
25
|
+
'event' => event,
|
26
|
+
'created_at' => created_at,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Webhooks
|
4
|
+
class Request < ApplicationRecord
|
5
|
+
belongs_to :attempt, class_name: 'Webhooks::Attempt', foreign_key: :webhooks_attempt_id, inverse_of: :request
|
6
|
+
has_one :response, class_name: 'Webhooks::Response', foreign_key: :webhooks_request_id, inverse_of: :request, dependent: :destroy
|
7
|
+
|
8
|
+
# Delegated associations
|
9
|
+
has_one :endpoint, through: :attempt
|
10
|
+
has_one :event, through: :attempt
|
11
|
+
|
12
|
+
before_create :perform_request
|
13
|
+
after_create :record_response
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def perform_request
|
18
|
+
self.body ||= EventSerializer.new(self).to_json
|
19
|
+
|
20
|
+
@response = Webhooks.client.post(endpoint.url) do |req|
|
21
|
+
timestamp = Time.zone.now
|
22
|
+
timestamped_payload = "#{timestamp.to_i}.#{body}"
|
23
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), endpoint.secret, timestamped_payload)
|
24
|
+
|
25
|
+
req.headers[Rails.application.config.webhooks.requests.header] = "t=#{timestamp.to_i},v1=#{signature}"
|
26
|
+
|
27
|
+
req.body = body
|
28
|
+
end
|
29
|
+
|
30
|
+
self.headers = @response.env.request_headers
|
31
|
+
end
|
32
|
+
|
33
|
+
def record_response
|
34
|
+
create_response!(response: @response)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Webhooks
|
4
|
+
class Response < ApplicationRecord
|
5
|
+
belongs_to :request, class_name: 'Webhooks::Request', foreign_key: :webhooks_request_id, inverse_of: :response
|
6
|
+
has_one :attempt, through: :request
|
7
|
+
has_one :endpoint, through: :attempt
|
8
|
+
|
9
|
+
validates :status_code, presence: true
|
10
|
+
validates :headers, presence: true
|
11
|
+
|
12
|
+
after_create :update_attempt_state
|
13
|
+
|
14
|
+
def update_attempt_state
|
15
|
+
case status_code
|
16
|
+
when 200..299
|
17
|
+
attempt.update!(state: :success)
|
18
|
+
else
|
19
|
+
attempt.update!(state: :error)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def response=(response)
|
24
|
+
self.status_code = response.status
|
25
|
+
self.headers = response.headers
|
26
|
+
self.body = response.body
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Webhooks</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<!-- This example requires Tailwind CSS v2.0+ -->
|
11
|
+
<div class="h-screen flex overflow-hidden bg-gray-100">
|
12
|
+
<%= render 'webhooks/shared/navigation' %>
|
13
|
+
<div class="flex flex-col w-0 flex-1 overflow-hidden">
|
14
|
+
<div class="md:hidden pl-1 pt-1 sm:pl-3 sm:pt-3">
|
15
|
+
<button class="-ml-0.5 -mt-0.5 h-12 w-12 inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
|
16
|
+
<span class="sr-only">Open sidebar</span>
|
17
|
+
<!-- Heroicon name: outline/menu -->
|
18
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
19
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
20
|
+
</svg>
|
21
|
+
</button>
|
22
|
+
</div>
|
23
|
+
<main class="flex-1 relative z-0 overflow-y-auto focus:outline-none">
|
24
|
+
<%= yield %>
|
25
|
+
</main>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</body>
|
29
|
+
</html>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<tr>
|
2
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
3
|
+
<% if attempt.success? %>
|
4
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
|
5
|
+
Success
|
6
|
+
</span>
|
7
|
+
<% elsif attempt.error? %>
|
8
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800">
|
9
|
+
Error <%= '(Limit)' if attempt.max_attempts? %>
|
10
|
+
</span>
|
11
|
+
<% else %>
|
12
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800">
|
13
|
+
Queued
|
14
|
+
</span>
|
15
|
+
<% end %>
|
16
|
+
</td>
|
17
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
18
|
+
<%= attempt.event.event_type %>
|
19
|
+
</td>
|
20
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
21
|
+
<%= link_to attempt.endpoint, attempt.endpoint %>
|
22
|
+
</td>
|
23
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
24
|
+
<%= link_to attempt.created_at, attempt %>
|
25
|
+
</td>
|
26
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-right">
|
27
|
+
<% if attempt.error? %>
|
28
|
+
<%= attempt.retry_at %>
|
29
|
+
<%= button_to 'Resend', reattempt_attempt_path(attempt), class: 'text-blue-600 hover:text-blue-900 bg-transparent cursor-pointer' %>
|
30
|
+
<% end %>
|
31
|
+
</td>
|
32
|
+
</tr>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<div class="py-6">
|
2
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 md:flex md:justify-between md:space-x-5">
|
3
|
+
<h1 class="text-2xl font-semibold text-gray-900">Attempt</h1>
|
4
|
+
</div>
|
5
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
6
|
+
<div class="py-4">
|
7
|
+
<div class="flex flex-col">
|
8
|
+
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
9
|
+
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8 space-y-6">
|
10
|
+
<div>
|
11
|
+
<%= @attempt.endpoint %>
|
12
|
+
Attempt: <%= @attempt.attempt %>
|
13
|
+
<%= @attempt.state %>
|
14
|
+
<%= @attempt.retry_at %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<% if @attempt.request.present? %>
|
18
|
+
<%= render @attempt.request %>
|
19
|
+
<% else %>
|
20
|
+
No request.
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<% if @attempt.response.present? %>
|
24
|
+
<%= render @attempt.response %>
|
25
|
+
<% else %>
|
26
|
+
No response.
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</div>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<tr>
|
2
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
3
|
+
<%= link_to endpoint, endpoint %>
|
4
|
+
</td>
|
5
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
6
|
+
<% if endpoint.enabled? %>
|
7
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
|
8
|
+
Enabled
|
9
|
+
</span>
|
10
|
+
<% elsif endpoint.disabled? %>
|
11
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800">
|
12
|
+
Disabled
|
13
|
+
</span>
|
14
|
+
<% else %>
|
15
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800">
|
16
|
+
Error
|
17
|
+
</span>
|
18
|
+
<% end %>
|
19
|
+
</td>
|
20
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
21
|
+
<% if endpoint.event_types.blank? %>
|
22
|
+
All events.
|
23
|
+
<% else %>
|
24
|
+
<%= pluralize endpoint.event_types.length, 'event' %>
|
25
|
+
<% end %>
|
26
|
+
</td>
|
27
|
+
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium sm:flex sm:items-center sm:justify-end space-x-3">
|
28
|
+
<%= link_to 'Edit', edit_endpoint_path(endpoint), class: 'text-indigo-600 hover:text-indigo-900' %>
|
29
|
+
<%= button_to 'Delete', endpoint_path(endpoint), method: 'delete', class: 'text-red-600 hover:text-red-900 bg-transparent cursor-pointer' %>
|
30
|
+
</td>
|
31
|
+
</tr>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%= form_with model: @endpoint do |form| %>
|
2
|
+
<div class="space-y-6">
|
3
|
+
<div>
|
4
|
+
<%= form.label :url, 'URL', class: 'block text-sm font-medium text-gray-700' %>
|
5
|
+
<div class="mt-1">
|
6
|
+
<%= form.url_field :url, class: 'block w-full shadow-sm focus:ring-light-blue-500 focus:border-light-blue-500 sm:text-sm border-gray-300 rounded-md py-2 px-4', placeholder: 'https://example.com/webhook' %>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div class="space-y-4">
|
11
|
+
<div>
|
12
|
+
<h2 class="text-lg leading-6 font-medium text-gray-900">Event Types</h2>
|
13
|
+
<p class="mt-1 text-sm text-gray-500">
|
14
|
+
Select the events you'd like to subscribe to for this endpoint. If no events are subscribed to, you will receive all events.
|
15
|
+
</p>
|
16
|
+
</div>
|
17
|
+
<div class="max-w-lg space-y-4">
|
18
|
+
<%= form.collection_check_boxes :event_types, Rails.application.config.webhooks.events.types, :to_s, :to_s, include_hidden: false do |b| %>
|
19
|
+
<div>
|
20
|
+
<div class="relative flex items-start">
|
21
|
+
<div class="flex items-center h-5">
|
22
|
+
<%= b.check_box class: 'focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded' %>
|
23
|
+
</div>
|
24
|
+
<div class="ml-3 text-sm">
|
25
|
+
<%= b.label class: 'font-medium text-gray-700' %>
|
26
|
+
<p class="text-gray-500">
|
27
|
+
<%= t b.text, scope: %i[webhooks events types] %>
|
28
|
+
</p>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
<%= form.hidden_field :event_types, multiple: true, value: '' %>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<div class="flex justify-end">
|
38
|
+
<%= link_to 'Cancel', endpoints_path, class: 'bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500' %>
|
39
|
+
<%= form.submit class: 'cursor-pointer ml-3 inline-flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500' %>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div class="py-6">
|
2
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
3
|
+
<h1 class="text-2xl font-semibold text-gray-900">Edit Endpoint</h1>
|
4
|
+
</div>
|
5
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
6
|
+
<div class="py-4">
|
7
|
+
<div class="flex flex-col">
|
8
|
+
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
9
|
+
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
10
|
+
<%= render 'form' %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<div class="py-6">
|
2
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 md:flex md:justify-between md:space-x-5">
|
3
|
+
<h1 class="text-2xl font-semibold text-gray-900">Endpoints</h1>
|
4
|
+
<div class="mt-6 flex flex-col-reverse justify-stretch space-y-4 space-y-reverse sm:flex-row-reverse sm:justify-end sm:space-x-reverse sm:space-y-0 sm:space-x-3 md:mt-0 md:flex-row md:space-x-3">
|
5
|
+
<%= link_to 'New Endpoint', new_endpoint_path, class: 'inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-blue-500' %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
9
|
+
<div class="py-4">
|
10
|
+
<div class="flex flex-col">
|
11
|
+
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
12
|
+
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
13
|
+
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
|
14
|
+
<table class="min-w-full divide-y divide-gray-200">
|
15
|
+
<thead class="bg-gray-50">
|
16
|
+
<tr>
|
17
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
18
|
+
URL
|
19
|
+
</th>
|
20
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
21
|
+
State
|
22
|
+
</th>
|
23
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
24
|
+
Event Types
|
25
|
+
</th>
|
26
|
+
<th scope="col" class="relative px-6 py-3">
|
27
|
+
<span class="sr-only">Edit</span>
|
28
|
+
</th>
|
29
|
+
</tr>
|
30
|
+
</thead>
|
31
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
32
|
+
<%= render @endpoints %>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div class="py-6">
|
2
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
3
|
+
<h1 class="text-2xl font-semibold text-gray-900">New Endpoint</h1>
|
4
|
+
</div>
|
5
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
6
|
+
<div class="py-4">
|
7
|
+
<div class="flex flex-col">
|
8
|
+
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
9
|
+
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
10
|
+
<%= render 'form' %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,102 @@
|
|
1
|
+
<div class="py-6">
|
2
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
|
3
|
+
<div class="py-4">
|
4
|
+
<div class="flex flex-col">
|
5
|
+
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
6
|
+
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8 space-y-6">
|
7
|
+
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
|
8
|
+
<div class="px-4 py-5 sm:px-6 sm:flex sm:items-center sm:justify-between">
|
9
|
+
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
10
|
+
<%= @endpoint %>
|
11
|
+
</h3>
|
12
|
+
<div class="mt-3 sm:mt-0 sm:ml-4">
|
13
|
+
<%= link_to 'Edit', edit_endpoint_path(@endpoint), class: 'inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500' %>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
<div class="border-t border-gray-200 px-4 py-5 sm:p-0">
|
17
|
+
<dl class="sm:divide-y sm:divide-gray-200">
|
18
|
+
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
19
|
+
<dt class="text-sm font-medium text-gray-500">
|
20
|
+
State
|
21
|
+
</dt>
|
22
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
23
|
+
<% if @endpoint.enabled? %>
|
24
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">
|
25
|
+
Enabled
|
26
|
+
</span>
|
27
|
+
<% elsif @endpoint.disabled? %>
|
28
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800">
|
29
|
+
Disabled
|
30
|
+
</span>
|
31
|
+
<% else %>
|
32
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800">
|
33
|
+
Error
|
34
|
+
</span>
|
35
|
+
<% end %>
|
36
|
+
</dd>
|
37
|
+
</div>
|
38
|
+
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
39
|
+
<dt class="text-sm font-medium text-gray-500">
|
40
|
+
Event types
|
41
|
+
</dt>
|
42
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
43
|
+
<% if @endpoint.event_types.blank? %>
|
44
|
+
All events.
|
45
|
+
<% else %>
|
46
|
+
<%= @endpoint.event_types.to_sentence %>
|
47
|
+
<% end %>
|
48
|
+
</dd>
|
49
|
+
</div>
|
50
|
+
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
51
|
+
<dt class="text-sm font-medium text-gray-500">
|
52
|
+
Secret
|
53
|
+
</dt>
|
54
|
+
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
55
|
+
<%= @endpoint.secret %>
|
56
|
+
</dd>
|
57
|
+
</div>
|
58
|
+
</dl>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div>
|
63
|
+
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
64
|
+
Attempts
|
65
|
+
</h3>
|
66
|
+
<p class="mt-2 max-w-4xl text-sm text-gray-500">
|
67
|
+
All webhook delivery attempts and their status.
|
68
|
+
</p>
|
69
|
+
</div>
|
70
|
+
|
71
|
+
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
|
72
|
+
<table class="min-w-full divide-y divide-gray-200">
|
73
|
+
<thead class="bg-gray-50">
|
74
|
+
<tr>
|
75
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
76
|
+
State
|
77
|
+
</th>
|
78
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
79
|
+
Event Type
|
80
|
+
</th>
|
81
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
82
|
+
Endpoint
|
83
|
+
</th>
|
84
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
85
|
+
Created
|
86
|
+
</th>
|
87
|
+
<th scope="col" class="relative px-6 py-3">
|
88
|
+
<span class="sr-only">Edit</span>
|
89
|
+
</th>
|
90
|
+
</tr>
|
91
|
+
</thead>
|
92
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
93
|
+
<%= render @endpoint.attempts.order(created_at: :desc) %>
|
94
|
+
</tbody>
|
95
|
+
</table>
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
</div>
|
101
|
+
</div>
|
102
|
+
</div>
|