karafka-web 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +8 -1
  5. data/Gemfile.lock +3 -3
  6. data/karafka-web.gemspec +1 -1
  7. data/lib/karafka/web/pro/ui/app.rb +35 -0
  8. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +29 -0
  9. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +65 -0
  10. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +84 -0
  11. data/lib/karafka/web/pro/ui/views/explorer/_partition_option.erb +10 -2
  12. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +1 -1
  13. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +30 -0
  14. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +84 -0
  15. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +28 -0
  16. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +72 -0
  17. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +33 -0
  18. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +21 -0
  19. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +11 -0
  20. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +38 -0
  21. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +48 -0
  22. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +1 -0
  23. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +10 -0
  24. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +3 -1
  25. data/lib/karafka/web/ui/base.rb +1 -1
  26. data/lib/karafka/web/ui/controllers/base_controller.rb +18 -3
  27. data/lib/karafka/web/ui/helpers/application_helper.rb +21 -7
  28. data/lib/karafka/web/ui/helpers/paths_helper.rb +18 -0
  29. data/lib/karafka/web/ui/models/recurring_tasks/log.rb +0 -11
  30. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +0 -11
  31. data/lib/karafka/web/ui/models/recurring_tasks/task.rb +0 -11
  32. data/lib/karafka/web/ui/public/javascripts/application.min.js +1 -1
  33. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  34. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  35. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +15 -0
  36. data/lib/karafka/web/ui/public/stylesheets/application.min.css +1 -1
  37. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  38. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  39. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +1 -1
  40. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  41. data/lib/karafka/web/ui/views/shared/_navigation.erb +10 -0
  42. data/lib/karafka/web/ui/views/shared/icons/_calendar.erb +3 -0
  43. data/lib/karafka/web/version.rb +1 -1
  44. data.tar.gz.sig +0 -0
  45. metadata +19 -5
  46. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40794ee9c8b084cf75de0403b904134cbc6a762dbfa338bb9ce574b56e46ac36
4
- data.tar.gz: dedefe087c54e118abb90e819b36b29aa253c4351aa18bd8a78d01e2c096ce79
3
+ metadata.gz: d471de1bcc756c234f8db2345c269b878863759fb5deb195ac8579e57365efde
4
+ data.tar.gz: 12d1348a0b83353dabeeea7a5ae164be7ff834d84088cfadb7b32c7343470f66
5
5
  SHA512:
6
- metadata.gz: 88b9b6ed8082b0484dcd32a20b2cee2b77d4df762b65d0487325e03ef375e1e7ac621d612f81b3f4a6870aa4352e07286979863d656161ca7d8d880e5709d108
7
- data.tar.gz: f9350f68d872c76d289933fbf2548b692179bae30fb2c0fccf923cdefca7131bbf3e6bf362e21a442c424fc4b43472e8334115b90c32449e80ef45a3518c3228
6
+ metadata.gz: 3f3eab846d445aa01714c8cea282874f9228f69af2475408d19a34b3ce43793b235f32c4484b640fad3b36ae29c90a2a8112dfd0b46685159528672355945f4c
7
+ data.tar.gz: f44a24702afe474270232a1cd5d785737fbd3e6d3b3e574b3eeb1cba5680147000092ec564ad5da7c663d6de124c7b59d9c3bd6c4e51ec80fc249eb90627fb5c
checksums.yaml.gz.sig CHANGED
@@ -1 +1,3 @@
1
- ��[����St���Y�Ě�D��������1�#�]; Xły}�)ҙ�*��A ��uѭȚܟ��
1
+ @��)oEe۫�15��Ƣ�h�){
2
+ R�
3
+ �O�ljJ�F�B�F�R+u��G���������ev����y ~�D�����>�%�LikH��K���}S�[�>k�uM����
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.3.4
1
+ 3.3.5
data/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Karafka Web Changelog
2
2
 
3
- ## 0.10.1 (Unreleased)
3
+ ## 0.10.2 (2024-09-03)
4
+ - **[Feature]** Support Future Messages management (Pro).
5
+ - [Enhancement] Do not live-reload when form active.
6
+ - [Fix] Undefined method `deep_merge` for an instance of Hash.
7
+ - [Fix] Prevent live-polling on elements wrapped in a button.
8
+ - [Fix] Fix errors extractor failure on first message-less tick / eofed
9
+
10
+ ## 0.10.1 (2024-08-23)
4
11
  - **[Feature]** Support Recurring Tasks management (Pro).
5
12
  - [Enhancement] Optimize command buttons so they occupy less space.
6
13
  - [Enhancement] Improve tables headers capitalization.
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.10.1)
4
+ karafka-web (0.10.2)
5
5
  erubi (~> 1.4)
6
- karafka (>= 2.4.9, < 2.5.0)
6
+ karafka (>= 2.4.10, < 2.5.0)
7
7
  karafka-core (>= 2.4.0, < 2.5.0)
8
8
  roda (~> 3.68, >= 3.69)
9
9
  tilt (~> 2.0)
@@ -40,7 +40,7 @@ GEM
40
40
  raabro (~> 1.4)
41
41
  i18n (1.14.5)
42
42
  concurrent-ruby (~> 1.0)
43
- karafka (2.4.9)
43
+ karafka (2.4.10)
44
44
  base64 (~> 0.2)
45
45
  karafka-core (>= 2.4.3, < 2.5.0)
46
46
  karafka-rdkafka (>= 0.17.2)
data/karafka-web.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.licenses = %w[LGPL-3.0-only Commercial]
18
18
 
19
19
  spec.add_dependency 'erubi', '~> 1.4'
20
- spec.add_dependency 'karafka', '>= 2.4.9', '< 2.5.0'
20
+ spec.add_dependency 'karafka', '>= 2.4.10', '< 2.5.0'
21
21
  spec.add_dependency 'karafka-core', '>= 2.4.0', '< 2.5.0'
22
22
  spec.add_dependency 'roda', '~> 3.68', '>= 3.69'
23
23
  spec.add_dependency 'tilt', '~> 2.0'
@@ -272,6 +272,41 @@ module Karafka
272
272
  end
273
273
  end
274
274
 
275
+ r.on 'scheduled_messages' do
276
+ r.on 'schedules' do
277
+ controller = Controllers::ScheduledMessages::SchedulesController.new(params)
278
+
279
+ r.get String do |topic_id|
280
+ controller.show(topic_id)
281
+ end
282
+
283
+ r.get do
284
+ controller.index
285
+ end
286
+ end
287
+
288
+ r.on 'explorer' do
289
+ controller = Controllers::ScheduledMessages::ExplorerController.new(params)
290
+
291
+ r.get String do |topic_id|
292
+ controller.topic(topic_id)
293
+ end
294
+
295
+ r.get String, Integer do |topic_id, partition_id|
296
+ controller.partition(topic_id, partition_id)
297
+ end
298
+
299
+ # Jumps to offset matching the expected time
300
+ r.get String, Integer, Time do |topic_id, partition_id, time|
301
+ controller.closest(topic_id, partition_id, time)
302
+ end
303
+ end
304
+
305
+ r.get do
306
+ r.redirect root_path('scheduled_messages/schedules')
307
+ end
308
+ end
309
+
275
310
  r.on 'health' do
276
311
  controller = Controllers::HealthController.new(params)
277
312
 
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ # Namespace for all controllers related to scheduled messages
20
+ module ScheduledMessages
21
+ # Base Pro controller for scheduled messages
22
+ class BaseController < Controllers::BaseController
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ module ScheduledMessages
20
+ # Allows for exploration of dispatch messages in a less generic form that via the
21
+ # explorer as different details are present
22
+ class ExplorerController < BaseController
23
+ # Displays aggregated messages from (potentially) all partitions of a topic
24
+ #
25
+ # @param topic_id [String]
26
+ def topic(topic_id)
27
+ response = Controllers::ExplorerController
28
+ .new(@params)
29
+ .topic(topic_id)
30
+
31
+ render(attributes: response.attributes)
32
+ end
33
+
34
+ # Shows messages available in a given partition
35
+ #
36
+ # @param topic_id [String]
37
+ # @param partition_id [Integer]
38
+ def partition(topic_id, partition_id)
39
+ response = Controllers::ExplorerController
40
+ .new(@params)
41
+ .partition(topic_id, partition_id)
42
+
43
+ render(attributes: response.attributes)
44
+ end
45
+
46
+ # Finds the closest offset matching the requested time and redirects to this location
47
+ # Note, that it redirects to closest but always younger.
48
+ #
49
+ # @param topic_id [String]
50
+ # @param partition_id [Integer]
51
+ # @param time [Time] time of the message
52
+ def closest(topic_id, partition_id, time)
53
+ response = Controllers::ExplorerController
54
+ .new(@params)
55
+ .closest(topic_id, partition_id, time)
56
+
57
+ redirect("scheduled_messages/#{response.path}")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Pro
17
+ module Ui
18
+ module Controllers
19
+ # Namespace for all controllers related to scheduled messages
20
+ module ScheduledMessages
21
+ # Controller to display list of schedules (groups) and details about each
22
+ class SchedulesController < BaseController
23
+ # Displays list of groups
24
+ def index
25
+ topics = Models::Topic.all
26
+
27
+ # Names of scheduled messages topics defined in the routing
28
+ # They may not exist (yet) so we filter them based on the existing topics in the
29
+ # cluster
30
+ candidates = Karafka::App
31
+ .routes
32
+ .map(&:topics)
33
+ .map(&:to_a)
34
+ .flatten
35
+ .select(&:scheduled_messages?)
36
+ .reject { |topic| topic.name.end_with?(states_postfix) }
37
+ .map(&:name)
38
+ .sort
39
+
40
+ @topics = topics.select { |topic| candidates.include?(topic.topic_name) }
41
+
42
+ render
43
+ end
44
+
45
+ # Displays all partitions statistics (if any) with number of messages to dispatch
46
+ # @param schedule_name [String] name of the schedules messages topic
47
+ def show(schedule_name)
48
+ @schedule_name = schedule_name
49
+ @stats_topic_name = "#{schedule_name}#{states_postfix}"
50
+ @stats_info = Karafka::Admin.topic_info(@stats_topic_name)
51
+
52
+ @states = {}
53
+ @stats_info[:partition_count].times { |i| @states[i] = false }
54
+
55
+ Karafka::Pro::Iterator.new({ @stats_topic_name => -1 }).each do |message|
56
+ @states[message.partition] = message.payload
57
+ end
58
+
59
+ # Sort by partition id
60
+ @states = @states.sort_by { |key, _| key.to_s }.to_h
61
+ # Sort daily from closest date
62
+ @states.each_value do |details|
63
+ # Skip false predefined values from sorting
64
+ next unless details
65
+
66
+ details[:daily] = details[:daily].sort_by { |key, _| key.to_s }.to_h
67
+ end
68
+
69
+ render
70
+ end
71
+
72
+ private
73
+
74
+ # @return [String] states topic postfix
75
+ def states_postfix
76
+ @states_postfix ||= Karafka::App.config.scheduled_messages.states_postfix
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,7 +1,15 @@
1
+ <%
2
+ path = if @selector_path_method
3
+ public_send(@selector_path_method, @topic_id, partition)
4
+ else
5
+ explorer_path(@topic_id, partition)
6
+ end
7
+ %>
8
+
1
9
  <% if @partition_id == partition %>
2
- <option value="<%= explorer_path(@topic_id, partition) %>" selected=selected>
10
+ <option value="<%= path %>" selected=selected>
3
11
  <% else %>
4
- <option value="<%= explorer_path(@topic_id, partition) %>">
12
+ <option value="<%= path %>">
5
13
  <% end %>
6
14
  <%= partition || 'All' %>
7
15
  </option>
@@ -7,6 +7,6 @@
7
7
  <li>Recurring Tasks are enabled in your routing configuration.</li>
8
8
  <li>The necessary Kafka topics have been created.</li>
9
9
  <li>A schedule has been defined.</li>
10
- <li>our Karafka server, with schedule awareness, is running and has persisted the state.</li>
10
+ <li>Your Karafka server, with schedule awareness, is running and has persisted the state.</li>
11
11
  </ul>
12
12
  <% end %>
@@ -0,0 +1,30 @@
1
+ <li>
2
+ <a href="<%= root_path('scheduled_messages') %>">
3
+ Scheduled Messages
4
+ </a>
5
+ </li>
6
+
7
+ <% if current_path.include?('/explorer') %>
8
+ <li>
9
+ <a href="<%= root_path("scheduled_messages/explorer/#{@topic_id}") %>">
10
+ Messages
11
+ </a>
12
+ </li>
13
+ <% end %>
14
+
15
+ <% if @topic_id %>
16
+ <li>
17
+ <a href="<%= root_path("scheduled_messages/explorer/#{@topic_id}") %>">
18
+ <%= @topic_id %>
19
+ </a>
20
+ </li>
21
+ <% end %>
22
+
23
+ <% if @partition_id %>
24
+ <li>
25
+ <a href="<%= root_path("scheduled_messages/explorer/#{@topic_id}/#{@partition_id}") %>">
26
+ Partition
27
+ <%= @partition_id %>
28
+ </a>
29
+ </li>
30
+ <% end %>
@@ -0,0 +1,84 @@
1
+ <% safe_key = ::Karafka::Web::Pro::Ui::Lib::SafeRunner.new { message.key } %>
2
+
3
+ <% if message.is_a?(Array) %>
4
+ <tr>
5
+ <td class="text-muted">
6
+ <%= message[0] %>
7
+ </td>
8
+ <td class="text-muted">
9
+ <%= message[1] %>
10
+ </td>
11
+ <td colspan="8" class="text-center text-muted">
12
+ This offset does not contain any data. The message may have been compacted or is a system entry.
13
+ </td>
14
+ </tr>
15
+ <% else %>
16
+ <% type = message.headers['schedule_source_type'] %>
17
+ <tr>
18
+ <td>
19
+ <%= message.partition %>
20
+ </td>
21
+ <td>
22
+ <%= message.offset %>
23
+ </td>
24
+ <td>
25
+ <% if type == 'tombstone' %>
26
+ <%== badge_secondary type %>
27
+ <% end %>
28
+
29
+ <% if type == 'cancel' %>
30
+ <%== badge_warning type %>
31
+ <% end %>
32
+
33
+ <% if type == 'schedule' %>
34
+ <%== badge_primary type %>
35
+ <% end %>
36
+ </td>
37
+ <td>
38
+ <%= message.headers['schedule_schema_version'] %>
39
+ </td>
40
+
41
+ <% if type == 'cancel' %>
42
+ <td colspan="5" class="text-center text-muted">
43
+ Cancellation messages do not contain those details.
44
+ </td>
45
+ <% else %>
46
+ <td>
47
+ <%== relative_time(message.timestamp) %>
48
+ </td>
49
+ <td>
50
+ <%== relative_time message.headers['schedule_target_epoch'].to_i %>
51
+ </td>
52
+ <td>
53
+ <% if @visibility_filter.key?(message) %>
54
+ <% if safe_key.success? %>
55
+ <%= safe_key.result %>
56
+ <% else %>
57
+ <span class="text-muted">[Deserialization Failed]</span>
58
+ <% end %>
59
+ <% else %>
60
+ <span class="text-muted">[Filtered]</span>
61
+ <% end %>
62
+ </td>
63
+ <td>
64
+ <%= message.headers['schedule_target_topic'] %>
65
+ </td>
66
+ <td>
67
+ <% if @visibility_filter.key?(message) %>
68
+ <%= message.headers['schedule_target_key'] %>
69
+ <% else %>
70
+ <span class="text-muted">[Filtered]</span>
71
+ <% end %>
72
+ </td>
73
+ <% end %>
74
+
75
+ <td>
76
+ <%==
77
+ link_button_primary_sm(
78
+ 'Details',
79
+ explorer_path(message.topic, message.partition, message.offset)
80
+ )
81
+ %>
82
+ </td>
83
+ </tr>
84
+ <% end %>
@@ -0,0 +1,28 @@
1
+ <div class="data-table-wrapper">
2
+ <table class="data-table">
3
+ <thead>
4
+ <tr>
5
+ <th>Partition</th>
6
+ <th>Offset</th>
7
+ <th>Type</th>
8
+ <th>Schema</th>
9
+ <th>Created At</th>
10
+ <th>Dispatch At</th>
11
+ <th>Key</th>
12
+ <th>Target Topic</th>
13
+ <th>Target Key</th>
14
+ <th></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <%==
19
+ each_partial(
20
+ @messages,
21
+ 'scheduled_messages/explorer/message'
22
+ )
23
+ %>
24
+ </tbody>
25
+ </table>
26
+
27
+ <%== content_for :table_metadata %>
28
+ </div>
@@ -0,0 +1,72 @@
1
+ <% view_title "#{@topic_id} partition #{@partition_id}" %>
2
+
3
+ <% @selector_path_method = :scheduled_messages_explorer_path %>
4
+
5
+ <div class="col-span-4">
6
+ <section class="actions">
7
+ <% if @messages && !@messages.empty? %>
8
+ <a
9
+ href="<%= explorer_path(@topic_id, @partition_id, 'recent') %>"
10
+ class="btn-action"
11
+ title="Display the most recent message for this partition with auto-refresh"
12
+ >
13
+ <%== icon(:play_circle) %>
14
+ </a>
15
+
16
+ <a
17
+ href="<%= explorer_path(@topic_id, 'search', "?partition=#{@partition_id}") %>"
18
+ class="btn-action"
19
+ title="Search in this topic"
20
+ >
21
+ <%== icon(:magnifying_glass) %>
22
+ </a>
23
+
24
+ <% closest_path = scheduled_messages_explorer_path(@topic_id, @partition_id) %>
25
+ <input
26
+ type="image"
27
+ src="<%= asset_path('images/calendar.svg') %>"
28
+ width="45"
29
+ height="32"
30
+ class="btn-action p-1 opacity-60"
31
+ id="offset-lookup-datepicker"
32
+ value=""
33
+ data-target="<%= closest_path %>"
34
+ />
35
+ <% end %>
36
+ </section>
37
+ </div>
38
+
39
+ <div class="col-span-8 mb-3">
40
+ <section class="actions">
41
+ <%== partial 'explorer/selector' %>
42
+ </section>
43
+ </div>
44
+
45
+ <div class="col-span-12">
46
+ <% if @limited %>
47
+ <%== partial('explorer/topic/limited') %>
48
+ <% end %>
49
+
50
+ <% if @watermark_offsets.empty? && params.current_page == 1 %>
51
+ <%== partial 'explorer/partition/empty' %>
52
+ <% elsif @watermark_offsets.cleaned? && params.current_page == 1 %>
53
+ <%== partial 'explorer/partition/cleaned' %>
54
+ <% elsif @messages.empty? %>
55
+ <%== partial 'shared/no_paginated_data' %>
56
+ <% else %>
57
+ <% content_for :table_metadata do %>
58
+ <p class="table_metadata">
59
+ Watermark offsets:
60
+ <span class="badge badge-secondary mt-1 mb-1">
61
+ high: <%= @watermark_offsets.high %>
62
+ </span>
63
+
64
+ <span class="badge badge-secondary mt-1 mb-1">
65
+ low: <%= @watermark_offsets.low %>
66
+ </span>
67
+ </p>
68
+ <% end %>
69
+
70
+ <%== partial('scheduled_messages/explorer/messages') %>
71
+ <% end %>
72
+ </div>
@@ -0,0 +1,33 @@
1
+ <% view_title @topic_id %>
2
+
3
+ <% @selector_path_method = :scheduled_messages_explorer_path %>
4
+
5
+ <%== partial 'explorer/topic/actions' %>
6
+
7
+ <div class="col-span-12">
8
+ <% if @limited %>
9
+ <div class="mb-6">
10
+ <%== partial('explorer/topic/limited') %>
11
+ </div>
12
+ <% end %>
13
+
14
+ <% if @messages.empty? && params.current_page == 1 %>
15
+ <%== partial 'explorer/topic/empty' %>
16
+ <% elsif @messages.empty? %>
17
+ <%== partial 'shared/no_paginated_data' %>
18
+ <% else %>
19
+ <% content_for :table_metadata do %>
20
+ <p class="table_metadata">
21
+ Partitions:
22
+
23
+ <%== badge("total: #{@partitions_count}") %>
24
+ <%==
25
+ range = [@active_partitions.first, @active_partitions.last].uniq.join(' to ')
26
+ badge("visible: #{range}")
27
+ %>
28
+ </p>
29
+ <% end %>
30
+
31
+ <%== partial('scheduled_messages/explorer/messages') %>
32
+ <% end %>
33
+ </div>
@@ -0,0 +1,21 @@
1
+ <li>
2
+ <a href="<%= root_path('scheduled_messages') %>">
3
+ Scheduled Messages
4
+ </a>
5
+ </li>
6
+
7
+ <% if current_path.include?('/schedules') %>
8
+ <li>
9
+ <a href="<%= root_path('scheduled_messages/schedules') %>">
10
+ Schedules
11
+ </a>
12
+ </li>
13
+ <% end %>
14
+
15
+ <% if @schedule_name %>
16
+ <li>
17
+ <a href="<%= root_path("scheduled_messages/schedules/#{@schedule_name}") %>">
18
+ <%= @schedule_name %>
19
+ </a>
20
+ </li>
21
+ <% end %>
@@ -0,0 +1,11 @@
1
+ <% alert_box_info 'Scheduled Messages Data Not Available' do %>
2
+ <p class="mb-2">
3
+ We are unable to display data related to scheduled messages. Please ensure that:
4
+ </p>
5
+
6
+ <ul class="list-disc list-inside">
7
+ <li>Scheduled Messages are enabled in your routing configuration.</li>
8
+ <li>The necessary Kafka topics have been created.</li>
9
+ <li>Your Karafka server, with scheduled messages awareness, is running and has persisted the state.</li>
10
+ </ul>
11
+ <% end %>
@@ -0,0 +1,38 @@
1
+ <% view_title 'Schedules' %>
2
+
3
+ <div class="col-span-12">
4
+ <% if @topics.empty? %>
5
+ <%== partial 'scheduled_messages/schedules/no_groups' %>
6
+ <% else %>
7
+ <% @topics.each do |topic| %>
8
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
9
+ <div class="card-support">
10
+ <h3>
11
+ <%== icon(:calendar) %>
12
+ <span>
13
+ <%= topic.topic_name %>
14
+ /
15
+ <%= topic.partition_count %>
16
+ </span>
17
+ </h3>
18
+
19
+ <p class="flex justify-center space-x-2 mb-3">
20
+ <a
21
+ href="<%= root_path("scheduled_messages/schedules/#{topic.topic_name}") %>"
22
+ class="btn btn-primary btn-sm flex-1"
23
+ >
24
+ Planned
25
+ </a>
26
+
27
+ <a
28
+ href="<%= root_path("scheduled_messages/explorer/#{topic.topic_name}") %>"
29
+ class="btn btn-primary btn-sm flex-1"
30
+ >
31
+ Messages
32
+ </a>
33
+ </p>
34
+ </div>
35
+ </div>
36
+ <% end %>
37
+ <% end %>
38
+ </div>