karafka-web 0.10.0 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
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>