karafka-web 0.10.0 → 0.10.2

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +12 -4
  7. data/certs/cert.pem +26 -0
  8. data/karafka-web.gemspec +2 -2
  9. data/lib/karafka/web/pro/ui/app.rb +75 -0
  10. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +4 -4
  11. data/lib/karafka/web/pro/ui/controllers/recurring_tasks_controller.rb +131 -0
  12. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +29 -0
  13. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +65 -0
  14. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +84 -0
  15. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +13 -12
  16. data/lib/karafka/web/pro/ui/views/explorer/_partition_option.erb +10 -2
  17. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +58 -0
  18. data/lib/karafka/web/pro/ui/views/recurring_tasks/_batch_actions.erb +45 -0
  19. data/lib/karafka/web/pro/ui/views/recurring_tasks/_breadcrumbs.erb +22 -0
  20. data/lib/karafka/web/pro/ui/views/recurring_tasks/_log.erb +26 -0
  21. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +12 -0
  22. data/lib/karafka/web/pro/ui/views/recurring_tasks/_tabs.erb +17 -0
  23. data/lib/karafka/web/pro/ui/views/recurring_tasks/_task.erb +46 -0
  24. data/lib/karafka/web/pro/ui/views/recurring_tasks/logs.erb +34 -0
  25. data/lib/karafka/web/pro/ui/views/recurring_tasks/schedule.erb +43 -0
  26. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +30 -0
  27. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +84 -0
  28. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +28 -0
  29. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +72 -0
  30. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +33 -0
  31. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +21 -0
  32. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +11 -0
  33. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +38 -0
  34. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +48 -0
  35. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +1 -0
  36. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +20 -0
  37. data/lib/karafka/web/pro/ui/views/topics/replication.erb +1 -1
  38. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +3 -1
  39. data/lib/karafka/web/ui/base.rb +1 -1
  40. data/lib/karafka/web/ui/controllers/base_controller.rb +18 -3
  41. data/lib/karafka/web/ui/helpers/application_helper.rb +29 -8
  42. data/lib/karafka/web/ui/helpers/paths_helper.rb +18 -0
  43. data/lib/karafka/web/ui/models/recurring_tasks/log.rb +15 -0
  44. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +75 -0
  45. data/lib/karafka/web/ui/models/recurring_tasks/task.rb +19 -0
  46. data/lib/karafka/web/ui/public/javascripts/application.js +1 -1
  47. data/lib/karafka/web/ui/public/javascripts/application.min.js +7 -7
  48. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  49. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  50. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +51 -0
  51. data/lib/karafka/web/ui/public/stylesheets/application.css +5 -1
  52. data/lib/karafka/web/ui/public/stylesheets/application.min.css +2 -2
  53. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  54. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  55. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +18 -6
  56. data/lib/karafka/web/ui/views/dashboard/_ranges_selector.erb +1 -1
  57. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  58. data/lib/karafka/web/ui/views/shared/_navigation.erb +21 -0
  59. data/lib/karafka/web/ui/views/shared/icons/_calendar.erb +3 -0
  60. data/lib/karafka/web/ui/views/shared/icons/_check.erb +3 -0
  61. data/lib/karafka/web/ui/views/shared/icons/_play.erb +3 -0
  62. data/lib/karafka/web/ui/views/status/info/_components.erb +48 -11
  63. data/lib/karafka/web/ui/views/ux/_data_table.erb +34 -4
  64. data/lib/karafka/web/ui/views/ux/_status_rows.erb +12 -0
  65. data/lib/karafka/web/version.rb +1 -1
  66. data.tar.gz.sig +0 -0
  67. metadata +56 -27
  68. metadata.gz.sig +0 -0
  69. data/certs/cert_chain.pem +0 -26
@@ -0,0 +1,58 @@
1
+ <%
2
+ trigger_path = root_path('recurring_tasks', task.id, 'trigger')
3
+ disabled_class = task.enabled? ? '' : 'btn-disabled'
4
+ %>
5
+ <form
6
+ action="<%= trigger_path %>"
7
+ method="post"
8
+ class="inline"
9
+ >
10
+ <%== csrf_tag(trigger_path) %>
11
+ <button
12
+ type="submit"
13
+ class="btn btn-primary btn-sm "
14
+ title="Trigger"
15
+ >
16
+ <%== icon(:play) %>
17
+ </button>
18
+ </form>
19
+
20
+ <%
21
+ enable_path = root_path('recurring_tasks', task.id, 'enable')
22
+ disabled_class = task.enabled? ? 'btn-disabled' : ''
23
+ %>
24
+ <form
25
+ action="<%= enable_path %>"
26
+ method="post"
27
+ class="inline"
28
+ title="Enable"
29
+ >
30
+ <%== csrf_tag(enable_path) %>
31
+ <button
32
+ type="submit"
33
+ class="btn btn-success btn-sm <%= disabled_class %>"
34
+ >
35
+ <%== icon(:check) %>
36
+ </button>
37
+ </form>
38
+
39
+ <%
40
+ disable_path = root_path('recurring_tasks', task.id, 'disable')
41
+ disabled_class = task.enabled? ? '' : 'btn-disabled'
42
+ %>
43
+ <form
44
+ action="<%= disable_path %>"
45
+ method="post"
46
+ class="inline"
47
+ title="Disable"
48
+
49
+ >
50
+ <%== csrf_tag(disable_path) %>
51
+ <button
52
+ type="submit"
53
+ class="btn btn-warning btn-sm <%= disabled_class %>"
54
+
55
+ >
56
+ <%== icon(:pause) %>
57
+ </button>
58
+ </form>
@@ -0,0 +1,45 @@
1
+ <div class="col-span-12 flex justify-end space-x-2 mb-6">
2
+ <%
3
+ trigger_all_path = root_path('recurring_tasks', 'trigger_all')
4
+ disable_class = @tasks.empty? ? 'btn-disabled' : ''
5
+ %>
6
+ <form
7
+ action="<%= trigger_all_path %>"
8
+ method="post"
9
+ class="inline-flex items-center"
10
+ >
11
+ <%== csrf_tag(trigger_all_path) %>
12
+ <button type="submit" class="btn btn-primary btn-sm <%= disable_class %>">
13
+ <%== icon(:play) %>
14
+ Trigger All
15
+ </button>
16
+ </form>
17
+
18
+ <%
19
+ enable_all_path = root_path('recurring_tasks', 'enable_all')
20
+ disable_class = @tasks.all?(&:enabled?) ? 'btn-disabled' : ''
21
+ %>
22
+ <form
23
+ action="<%= enable_all_path %>"
24
+ method="post"
25
+ class="inline-flex items-center"
26
+ >
27
+ <%== csrf_tag(enable_all_path) %>
28
+ <button type="submit" class="btn btn-success btn-sm <%= disable_class %>">
29
+ <%== icon(:check) %>
30
+ Enable All
31
+ </button>
32
+ </form>
33
+
34
+ <%
35
+ disable_all_path = root_path('recurring_tasks', 'disable_all')
36
+ disable_class = @tasks.none?(&:enabled?) ? 'btn-disabled' : ''
37
+ %>
38
+ <form action="<%= disable_all_path %>" method="post" class="inline-flex items-center">
39
+ <%== csrf_tag(disable_all_path) %>
40
+ <button type="submit" class="btn btn-warning btn-sm <%= disable_class %>">
41
+ <%== icon(:pause) %>
42
+ Disable All
43
+ </button>
44
+ </form>
45
+ </div>
@@ -0,0 +1,22 @@
1
+ <li>
2
+ <a href="<%= root_path('recurring_tasks') %>">
3
+ Recurring Tasks
4
+ </a>
5
+ </li>
6
+
7
+ <% if current_path.include?('/schedule') %>
8
+ <li>
9
+ <a href="<%= root_path('recurring_tasks/schedule') %>">
10
+ Schedule
11
+ <%= @schedule ? @schedule.schedule_version : '' %>
12
+ </a>
13
+ </li>
14
+ <% end %>
15
+
16
+ <% if current_path.include?('/logs') %>
17
+ <li>
18
+ <a href="<%= root_path('recurring_tasks/logs') %>">
19
+ Logs
20
+ </a>
21
+ </li>
22
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <% result = log.task[:result] == 'success' %>
2
+ <tr class="<%= result ? '' : 'status-row-error' %>">
3
+ <td>
4
+ <%= log.id %>
5
+ </td>
6
+ <td>
7
+ <% if result %>
8
+ <%== badge_success 'Success' %>
9
+ <% else %>
10
+ <%== badge_error 'Error' %>
11
+ <% end %>
12
+ </td>
13
+ <td>
14
+ <% if result %>
15
+ <%== log.task[:time_taken].round(2) %> ms
16
+ <% else %>
17
+ N/A
18
+ <% end %>
19
+ </td>
20
+ <td>
21
+ <%== relative_time log.dispatched_at %>
22
+ </td>
23
+ <td>
24
+ <%= log.schedule_version %>
25
+ </td>
26
+ </tr>
@@ -0,0 +1,12 @@
1
+ <% alert_box_info('Recurring Tasks Data Unavailable') do %>
2
+ <p class="mb-2">
3
+ We are unable to display data related to recurring tasks. Please ensure that:
4
+ </p>
5
+
6
+ <ul class="list-disc list-inside">
7
+ <li>Recurring Tasks are enabled in your routing configuration.</li>
8
+ <li>The necessary Kafka topics have been created.</li>
9
+ <li>A schedule has been defined.</li>
10
+ <li>Your Karafka server, with schedule awareness, is running and has persisted the state.</li>
11
+ </ul>
12
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <div class="col-span-12 mb-9">
2
+ <div class="tab-container">
3
+ <a
4
+ href="<%= root_path('recurring_tasks', 'schedule') %>"
5
+ class="custom-tab <%= nav_class(include: 'schedule') %>"
6
+ >
7
+ Schedules
8
+ </a>
9
+
10
+ <a
11
+ href="<%= root_path('recurring_tasks', 'logs') %>"
12
+ class="custom-tab <%= nav_class(include: '/logs') %>"
13
+ >
14
+ Logs
15
+ </a>
16
+ </div>
17
+ </div>
@@ -0,0 +1,46 @@
1
+ <tr class="<%= task.enabled? ? '' : 'status-row-warning text-muted' %>">
2
+ <td>
3
+ <%= task.id %>
4
+ </td>
5
+
6
+ <td>
7
+ <% if task.enabled? %>
8
+ <%== badge_success('Enabled') %>
9
+ <% else %>
10
+ <%== badge_warning('Disabled') %>
11
+ <% end %>
12
+ </td>
13
+
14
+ <td>
15
+ <code><%= task.cron %></code>
16
+ </td>
17
+
18
+ <td>
19
+ <% if task.previous_time.positive? %>
20
+ <%== relative_time task.previous_time %>
21
+ <% else %>
22
+ Never
23
+ <% end %>
24
+ </td>
25
+
26
+ <td>
27
+ <% if task.enabled? %>
28
+ <% if task.next_time < Time.now.to_i %>
29
+ Right now
30
+ <% else %>
31
+ <%== relative_time task.next_time %>
32
+ <% end %>
33
+ <% else %>
34
+ Never
35
+ <% end %>
36
+ </td>
37
+
38
+ <td class="commands-inline-3">
39
+ <%==
40
+ partial(
41
+ 'recurring_tasks/actions',
42
+ locals: { task: task }
43
+ )
44
+ %>
45
+ </td>
46
+ </tr>
@@ -0,0 +1,34 @@
1
+ <% view_title 'Logs' %>
2
+
3
+ <%== partial 'recurring_tasks/tabs' %>
4
+
5
+ <div class="col-span-12">
6
+ <% if @logs.empty? && params.current_page <= 1 %>
7
+ <%== alert_info('There are no available logs.') %>
8
+ <% elsif @logs.empty? %>
9
+ <%== partial 'shared/no_paginated_data' %>
10
+ <% else %>
11
+ <div class="data-table-wrapper">
12
+ <table class="data-table">
13
+ <thead>
14
+ <tr>
15
+ <th>Task ID</th>
16
+ <th>Result</th>
17
+ <th>Time Taken</th>
18
+ <th>Dispatched At</th>
19
+ <th>Schedule Version</th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <%==
24
+ render_each(
25
+ @logs,
26
+ 'recurring_tasks/_log',
27
+ local: :log
28
+ )
29
+ %>
30
+ </tbody>
31
+ </table>
32
+ </div>
33
+ <% end %>
34
+ </div>
@@ -0,0 +1,43 @@
1
+ <% if @schedule %>
2
+ <% view_title "Schedule #{@schedule.schedule_version}" %>
3
+ <% else %>
4
+ <% view_title 'Schedule' %>
5
+ <% end %>
6
+
7
+ <% if @schedule %>
8
+ <%== partial 'recurring_tasks/tabs' %>
9
+
10
+ <% unless @tasks.empty? %>
11
+ <%== partial 'recurring_tasks/batch_actions' %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <div class="col-span-12">
16
+ <% if @schedule && !@tasks.empty? %>
17
+ <div class="data-table-wrapper">
18
+ <table class="data-table">
19
+ <thead>
20
+ <tr>
21
+ <th><%== sort_link('Task ID', :id) %></th>
22
+ <th><%== sort_link('Status', :enabled) %></th>
23
+ <th><%== sort_link(:cron) %></th>
24
+ <th><%== sort_link(:previous_time) %></th>
25
+ <th><%== sort_link(:next_time) %></th>
26
+ <th></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <%==
31
+ render_each(
32
+ @tasks,
33
+ 'recurring_tasks/_task',
34
+ local: :task
35
+ )
36
+ %>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+ <% else %>
41
+ <%== partial 'recurring_tasks/not_active' %>
42
+ <% end %>
43
+ </div>
@@ -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>