karafka-web 0.10.1 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  3. data/CHANGELOG.md +15 -1
  4. data/Gemfile.lock +13 -11
  5. data/config/locales/pro_errors.yml +7 -1
  6. data/docker-compose.yml +1 -1
  7. data/karafka-web.gemspec +10 -2
  8. data/lib/karafka/web/pro/commanding/commands/{probe.rb → trace.rb} +3 -3
  9. data/lib/karafka/web/pro/commanding/listener.rb +1 -1
  10. data/lib/karafka/web/pro/commanding/manager.rb +2 -2
  11. data/lib/karafka/web/pro/commanding.rb +1 -1
  12. data/lib/karafka/web/pro/loader.rb +4 -2
  13. data/lib/karafka/web/pro/ui/app.rb +47 -2
  14. data/lib/karafka/web/pro/ui/controllers/commanding_controller.rb +4 -4
  15. data/lib/karafka/web/pro/ui/controllers/routing_controller.rb +18 -1
  16. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/base_controller.rb +29 -0
  17. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/explorer_controller.rb +65 -0
  18. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/messages_controller.rb +60 -0
  19. data/lib/karafka/web/pro/ui/controllers/scheduled_messages/schedules_controller.rb +84 -0
  20. data/lib/karafka/web/pro/ui/lib/branding/config.rb +40 -0
  21. data/lib/karafka/web/pro/ui/lib/branding/contracts/config.rb +56 -0
  22. data/lib/karafka/web/pro/ui/lib/branding.rb +36 -0
  23. data/lib/karafka/web/pro/ui/views/commands/_command.erb +1 -1
  24. data/lib/karafka/web/pro/ui/views/consumers/_consumer_controls.erb +3 -3
  25. data/lib/karafka/web/pro/ui/views/consumers/consumer/_commands.erb +4 -4
  26. data/lib/karafka/web/pro/ui/views/explorer/_partition_option.erb +10 -2
  27. data/lib/karafka/web/pro/ui/views/recurring_tasks/_actions.erb +2 -2
  28. data/lib/karafka/web/pro/ui/views/recurring_tasks/_not_active.erb +1 -1
  29. data/lib/karafka/web/pro/ui/views/routing/_consumer_group.erb +2 -0
  30. data/lib/karafka/web/pro/ui/views/routing/_topic.erb +10 -0
  31. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_breadcrumbs.erb +30 -0
  32. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_key.erb +9 -0
  33. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_message.erb +122 -0
  34. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/_messages.erb +28 -0
  35. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/partition.erb +72 -0
  36. data/lib/karafka/web/pro/ui/views/scheduled_messages/explorer/topic.erb +33 -0
  37. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_breadcrumbs.erb +21 -0
  38. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/_no_groups.erb +11 -0
  39. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/index.erb +38 -0
  40. data/lib/karafka/web/pro/ui/views/scheduled_messages/schedules/show.erb +48 -0
  41. data/lib/karafka/web/pro/ui/views/search/_breadcrumbs.erb +1 -0
  42. data/lib/karafka/web/pro/ui/views/shared/_navigation.erb +29 -14
  43. data/lib/karafka/web/pro/ui/views/shared/branding/_label.erb +20 -0
  44. data/lib/karafka/web/pro/ui/views/shared/branding/_notice.erb +13 -0
  45. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +3 -1
  46. data/lib/karafka/web/ui/base.rb +1 -1
  47. data/lib/karafka/web/ui/controllers/base_controller.rb +18 -3
  48. data/lib/karafka/web/ui/helpers/application_helper.rb +21 -7
  49. data/lib/karafka/web/ui/helpers/paths_helper.rb +18 -0
  50. data/lib/karafka/web/ui/helpers/tailwind_helper.rb +5 -4
  51. data/lib/karafka/web/ui/models/recurring_tasks/log.rb +0 -11
  52. data/lib/karafka/web/ui/models/recurring_tasks/schedule.rb +0 -11
  53. data/lib/karafka/web/ui/models/recurring_tasks/task.rb +0 -11
  54. data/lib/karafka/web/ui/public/javascripts/application.js +1 -0
  55. data/lib/karafka/web/ui/public/javascripts/application.min.js +3 -3
  56. data/lib/karafka/web/ui/public/javascripts/application.min.js.br +0 -0
  57. data/lib/karafka/web/ui/public/javascripts/application.min.js.gz +0 -0
  58. data/lib/karafka/web/ui/public/javascripts/components/btn_toggle_manager.js +16 -6
  59. data/lib/karafka/web/ui/public/javascripts/components/live_poll.js +15 -0
  60. data/lib/karafka/web/ui/public/stylesheets/application.css +21 -0
  61. data/lib/karafka/web/ui/public/stylesheets/application.min.css +1 -1
  62. data/lib/karafka/web/ui/public/stylesheets/application.min.css.br +0 -0
  63. data/lib/karafka/web/ui/public/stylesheets/application.min.css.gz +0 -0
  64. data/lib/karafka/web/ui/public/stylesheets/libs/tailwind.css +70 -3
  65. data/lib/karafka/web/ui/views/layout.erb +5 -2
  66. data/lib/karafka/web/ui/views/shared/_brand.erb +3 -2
  67. data/lib/karafka/web/ui/views/shared/_breadcrumbs.erb +1 -1
  68. data/lib/karafka/web/ui/views/shared/_navigation.erb +28 -14
  69. data/lib/karafka/web/ui/views/shared/alerts/_error.erb +3 -1
  70. data/lib/karafka/web/ui/views/shared/alerts/_info.erb +1 -1
  71. data/lib/karafka/web/ui/views/shared/alerts/_primary.erb +3 -1
  72. data/lib/karafka/web/ui/views/shared/alerts/_secondary.erb +3 -1
  73. data/lib/karafka/web/ui/views/shared/alerts/_success.erb +3 -1
  74. data/lib/karafka/web/ui/views/shared/alerts/_warning.erb +3 -1
  75. data/lib/karafka/web/ui/views/shared/icons/_calendar.erb +3 -0
  76. data/lib/karafka/web/ui/views/shared/icons/_chevron.erb +4 -0
  77. data/lib/karafka/web/version.rb +1 -1
  78. data/package-lock.json +3 -3
  79. data.tar.gz.sig +0 -0
  80. metadata +28 -16
  81. metadata.gz.sig +0 -0
  82. data/.coditsu/ci.yml +0 -3
  83. data/.diffend.yml +0 -3
  84. data/.github/FUNDING.yml +0 -1
  85. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -50
  86. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  87. data/.github/workflows/ci.yml +0 -133
  88. data/.gitignore +0 -71
  89. data/.rspec +0 -1
  90. data/.ruby-gemset +0 -1
  91. data/.ruby-version +0 -1
@@ -0,0 +1,56 @@
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 Lib
19
+ module Branding
20
+ # Contracts for checking branding related setup
21
+ module Contracts
22
+ # Makes sure, all the expected UI branding config is defined as it should be
23
+ class Config < ::Karafka::Contracts::Base
24
+ configure do |config|
25
+ config.error_messages = YAML.safe_load(
26
+ File.read(
27
+ File.join(Karafka::Web.gem_root, 'config', 'locales', 'pro_errors.yml')
28
+ )
29
+ ).fetch('en').fetch('validations').fetch('config')
30
+ end
31
+
32
+ nested(:ui) do
33
+ nested(:branding) do
34
+ required(:type) do |val|
35
+ # Type of branding style wrapping needs to align with what we support
36
+ # in other places
37
+ ::Karafka::Web::Ui::Helpers::TailwindHelper::TYPES.include?(val)
38
+ end
39
+
40
+ required(:label) do |val|
41
+ val == false || (val.is_a?(String) && val.size.positive?)
42
+ end
43
+
44
+ required(:notice) do |val|
45
+ val == false || (val.is_a?(String) && val.size.positive?)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,36 @@
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 Lib
19
+ # Namespace for UI branding related stuff
20
+ # Branding allows users to set an extra label and notice per env so users won't be
21
+ # confused by dev vs prod etc.
22
+ module Branding
23
+ class << self
24
+ # Validates that the UI branding config is correct
25
+ #
26
+ # @param config [Karafka::Core::Configurable::Node] web config
27
+ def post_setup(config)
28
+ Branding::Contracts::Config.new.validate!(config.to_h)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -15,7 +15,7 @@
15
15
  <td>
16
16
  <%
17
17
  color = case command[:command][:name]
18
- when 'probe'
18
+ when 'trace'
19
19
  'info'
20
20
  when 'quiet'
21
21
  'warning'
@@ -45,11 +45,11 @@
45
45
 
46
46
  <td class="commands-inline-3">
47
47
  <%
48
- probe_path = root_path('commanding', process.id, 'probe')
48
+ trace_path = root_path('commanding', process.id, 'trace')
49
49
  disabled_class = process.status != 'stopped' ? '' : 'btn-disabled'
50
50
  %>
51
- <form action="<%= probe_path %>" method="post" class="inline" title="Probe">
52
- <%== csrf_tag(probe_path) %>
51
+ <form action="<%= trace_path %>" method="post" class="inline" title="Trace">
52
+ <%== csrf_tag(trace_path) %>
53
53
 
54
54
  <button type="submit" class="btn btn-info btn-sm <%= disabled_class %>">
55
55
  <%== icon(:gear) %>
@@ -1,21 +1,21 @@
1
1
  <% if Karafka::Web.config.commanding.active && !process.tags.include?('embedded') %>
2
2
  <div class="col-span-12 flex justify-end space-x-2 mb-6">
3
3
  <%
4
- probe_path = root_path('commanding', process.id, 'probe')
4
+ trace_path = root_path('commanding', process.id, 'trace')
5
5
  disabled_class = process.status != 'stopped' ? '' : 'btn-disabled'
6
6
  %>
7
7
  <form
8
- action="<%= probe_path %>"
8
+ action="<%= trace_path %>"
9
9
  method="post"
10
10
  class="inline-flex items-center"
11
11
  >
12
- <%== csrf_tag(probe_path) %>
12
+ <%== csrf_tag(trace_path) %>
13
13
  <button
14
14
  type="submit"
15
15
  class="btn btn-info btn-sm <%= disabled_class %>"
16
16
  >
17
17
  <%== icon(:gear) %>
18
- Probe
18
+ Trace
19
19
  </button>
20
20
  </form>
21
21
 
@@ -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>
@@ -30,7 +30,7 @@
30
30
  <%== csrf_tag(enable_path) %>
31
31
  <button
32
32
  type="submit"
33
- class="btn btn-success btn-sm <%= disabled_class %>"
33
+ class="btn btn-success btn-sm <%= disabled_class %>"
34
34
  >
35
35
  <%== icon(:check) %>
36
36
  </button>
@@ -50,7 +50,7 @@
50
50
  <%== csrf_tag(disable_path) %>
51
51
  <button
52
52
  type="submit"
53
- class="btn btn-warning btn-sm <%= disabled_class %>"
53
+ class="btn btn-warning btn-sm <%= disabled_class %>"
54
54
 
55
55
  >
56
56
  <%== icon(:pause) %>
@@ -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 %>
@@ -10,6 +10,7 @@
10
10
  <th>Subscription group</th>
11
11
  <th><%== sort_link('Topic', :name) %></th>
12
12
  <th>Type</th>
13
+ <th>Assigned</th>
13
14
  <th><%== sort_link(:active?) %></th>
14
15
  <th></th>
15
16
  </tr>
@@ -21,6 +22,7 @@
21
22
  'routing/topic',
22
23
  locals: {
23
24
  subscription_group: topic.subscription_group,
25
+ consumer_group: consumer_group.id,
24
26
  topic: topic
25
27
  }
26
28
  )
@@ -20,6 +20,16 @@
20
20
  <% end %>
21
21
  </td>
22
22
 
23
+ <td>
24
+ <% assigned = @assigned[consumer_group].include?(topic.name) %>
25
+
26
+ <% if assigned %>
27
+ <%== badge_success assigned %>
28
+ <% else %>
29
+ <%== badge_secondary assigned %>
30
+ <% end %>
31
+ </td>
32
+
23
33
  <td>
24
34
  <% if topic.active? %>
25
35
  <%== badge_success topic.active? %>
@@ -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,9 @@
1
+ <% if @visibility_filter.key?(message) %>
2
+ <% if safe_key.success? %>
3
+ <%= safe_key.result %>
4
+ <% else %>
5
+ <span class="text-muted">[Deserialization Failed]</span>
6
+ <% end %>
7
+ <% else %>
8
+ <span class="text-muted">[Filtered]</span>
9
+ <% end %>
@@ -0,0 +1,122 @@
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>
43
+ <%== relative_time(message.timestamp) %>
44
+ </td>
45
+ <td class="text-center text-muted">
46
+ N/A
47
+ </td>
48
+ <td>
49
+ <%==
50
+ partial(
51
+ 'scheduled_messages/explorer/key',
52
+ locals: { message: message, safe_key: safe_key }
53
+ )
54
+ %>
55
+ </td>
56
+ <td colspan="2" class="text-center text-muted">
57
+ N/A
58
+ </td>
59
+ <% else %>
60
+ <td>
61
+ <%== relative_time(message.timestamp) %>
62
+ </td>
63
+ <td>
64
+ <%== relative_time message.headers['schedule_target_epoch'].to_i %>
65
+ </td>
66
+ <td>
67
+ <%==
68
+ partial(
69
+ 'scheduled_messages/explorer/key',
70
+ locals: { message: message, safe_key: safe_key }
71
+ )
72
+ %>
73
+ </td>
74
+ <td>
75
+ <%= message.headers['schedule_target_topic'] %>
76
+ </td>
77
+ <td>
78
+ <% if @visibility_filter.key?(message) %>
79
+ <%= message.headers['schedule_target_key'] %>
80
+ <% else %>
81
+ <span class="text-muted">[Filtered]</span>
82
+ <% end %>
83
+ </td>
84
+ <% end %>
85
+
86
+ <td>
87
+ <% if type == 'schedule' %>
88
+ <%
89
+ cancel_path = root_path(
90
+ "scheduled_messages/messages",
91
+ message.topic,
92
+ message.partition,
93
+ message.offset,
94
+ 'cancel'
95
+ )
96
+ %>
97
+ <form
98
+ action="<%= cancel_path %>"
99
+ method="post"
100
+ class="inline"
101
+ >
102
+ <%== csrf_tag(cancel_path) %>
103
+ <button
104
+ type="submit"
105
+ class="btn btn-error btn-sm confirm-action"
106
+ title="Cancel dispatch of this scheduled message"
107
+ >
108
+ <%== icon(:x_circle) %>
109
+ </button>
110
+ </form>
111
+ <% end %>
112
+
113
+ <%==
114
+ link_button_primary_sm(
115
+ icon(:info_circle),
116
+ explorer_path(message.topic, message.partition, message.offset),
117
+ title: 'Display details of this message'
118
+ )
119
+ %>
120
+ </td>
121
+ </tr>
122
+ <% 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>
@@ -0,0 +1,48 @@
1
+ <% view_title @schedule_name %>
2
+
3
+ <% @states.each do |partition, details| %>
4
+ <h3 class="h3">
5
+ Partition <%= partition %>
6
+ </h3>
7
+
8
+ <% if details %>
9
+ <div class="data-table-wrapper">
10
+ <table class="data-table">
11
+ <thead>
12
+ <tr>
13
+ <th>Date</th>
14
+ <th>For Dispatch</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <% details[:daily].each do |date, for_dispatch| %>
19
+ <tr>
20
+ <td><%= date %></td>
21
+ <td><%= for_dispatch %></td>
22
+ </tr>
23
+ <% end %>
24
+ </tbody>
25
+ </table>
26
+
27
+ <p class="table_metadata">
28
+ Metadata:
29
+ <span class="badge">
30
+ Schema version: <%= details[:schema_version] %>
31
+ </span>
32
+
33
+ <span class="badge">
34
+ Reported at:&nbsp;
35
+ <%== relative_time(details[:dispatched_at]) %>
36
+ </span>
37
+
38
+ <span class="badge badge-<%= details[:state] == 'loaded' ? 'success' : 'warning' %>">
39
+ State: <%= details[:state] %>
40
+ </span>
41
+ </p>
42
+ </div>
43
+ <% else %>
44
+ <div class="mb-4">
45
+ <%== alert_warning 'No state information for this partition is available.' %>
46
+ </div>
47
+ <% end %>
48
+ <% end %>
@@ -0,0 +1 @@
1
+ <%== partial 'explorer/breadcrumbs' %>