karafka-web 0.6.2 → 0.6.3

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 (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +2 -8
  4. data/Gemfile.lock +1 -1
  5. data/lib/karafka/web/config.rb +0 -2
  6. data/lib/karafka/web/ui/base.rb +2 -6
  7. data/lib/karafka/web/ui/controllers/base.rb +0 -17
  8. data/lib/karafka/web/ui/controllers/cluster.rb +2 -5
  9. data/lib/karafka/web/ui/controllers/consumers.rb +1 -3
  10. data/lib/karafka/web/ui/controllers/errors.rb +6 -19
  11. data/lib/karafka/web/ui/controllers/jobs.rb +1 -3
  12. data/lib/karafka/web/ui/controllers/requests/params.rb +0 -10
  13. data/lib/karafka/web/ui/lib/paginate_array.rb +38 -0
  14. data/lib/karafka/web/ui/models/message.rb +38 -114
  15. data/lib/karafka/web/ui/models/status.rb +1 -3
  16. data/lib/karafka/web/ui/pro/app.rb +3 -11
  17. data/lib/karafka/web/ui/pro/controllers/consumers.rb +1 -3
  18. data/lib/karafka/web/ui/pro/controllers/dlq.rb +2 -1
  19. data/lib/karafka/web/ui/pro/controllers/errors.rb +10 -43
  20. data/lib/karafka/web/ui/pro/controllers/explorer.rb +7 -52
  21. data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +6 -8
  22. data/lib/karafka/web/ui/pro/views/errors/_error.erb +1 -1
  23. data/lib/karafka/web/ui/pro/views/errors/_partition_option.erb +1 -1
  24. data/lib/karafka/web/ui/pro/views/errors/index.erb +56 -9
  25. data/lib/karafka/web/ui/pro/views/explorer/_breadcrumbs.erb +1 -1
  26. data/lib/karafka/web/ui/pro/views/explorer/_message.erb +2 -8
  27. data/lib/karafka/web/ui/pro/views/explorer/_partition_option.erb +1 -1
  28. data/lib/karafka/web/ui/pro/views/explorer/_topic.erb +1 -1
  29. data/lib/karafka/web/ui/pro/views/explorer/partition/_messages.erb +0 -1
  30. data/lib/karafka/web/ui/pro/views/explorer/partition.erb +1 -1
  31. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +1 -1
  32. data/lib/karafka/web/ui/views/cluster/_partition.erb +1 -1
  33. data/lib/karafka/web/ui/views/errors/_error.erb +1 -1
  34. data/lib/karafka/web/ui/views/shared/_pagination.erb +12 -16
  35. data/lib/karafka/web/version.rb +1 -1
  36. data.tar.gz.sig +0 -0
  37. metadata +2 -17
  38. metadata.gz.sig +0 -0
  39. data/lib/karafka/web/ui/lib/paginations/base.rb +0 -61
  40. data/lib/karafka/web/ui/lib/paginations/offset_based.rb +0 -96
  41. data/lib/karafka/web/ui/lib/paginations/page_based.rb +0 -70
  42. data/lib/karafka/web/ui/lib/paginations/paginators/arrays.rb +0 -33
  43. data/lib/karafka/web/ui/lib/paginations/paginators/base.rb +0 -23
  44. data/lib/karafka/web/ui/lib/paginations/paginators/partitions.rb +0 -52
  45. data/lib/karafka/web/ui/lib/paginations/paginators/sets.rb +0 -85
  46. data/lib/karafka/web/ui/lib/ttl_cache.rb +0 -74
  47. data/lib/karafka/web/ui/models/cluster_info.rb +0 -59
  48. data/lib/karafka/web/ui/pro/views/errors/_table.erb +0 -21
  49. data/lib/karafka/web/ui/pro/views/errors/_title_with_select.erb +0 -31
  50. data/lib/karafka/web/ui/pro/views/errors/partition.erb +0 -17
  51. data/lib/karafka/web/ui/pro/views/explorer/topic/_empty.erb +0 -3
  52. data/lib/karafka/web/ui/pro/views/explorer/topic/_limited.erb +0 -4
  53. data/lib/karafka/web/ui/pro/views/explorer/topic/_partitions.erb +0 -11
  54. data/lib/karafka/web/ui/pro/views/explorer/topic.erb +0 -49
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- # Namespace for commands that build paginated resources based on the provided page
9
- module Paginators
10
- # A simple wrapper for paginating array related data structures
11
- # We call this with plural (same with `Sets`) to avoid confusion with Ruby classes
12
- class Arrays < Base
13
- class << self
14
- # @param array [Array] array we want to paginate
15
- # @param current_page [Integer] page we want to be on
16
- # @return [Array<Array, Boolean>] Array with two elements: first is the array with
17
- # data of the given page and second is a boolean flag with info if the elements we got
18
- # are from the last page
19
- def call(array, current_page)
20
- slices = array.each_slice(per_page).to_a
21
- current_data = slices[current_page - 1] || []
22
- last_page = !(slices.count >= current_page - 1 && current_data.size >= per_page)
23
-
24
- [current_data, last_page]
25
- end
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Base paginator
10
- class Base
11
- class << self
12
- # @return [Integer] number of elements per page
13
- def per_page
14
- ::Karafka::Web.config.ui.per_page
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Paginator for selecting proper range of partitions for each page
10
- # For topics with a lot of partitions we cannot get all the data efficiently, that
11
- # is why we limit number of partitions per page and reduce the operations
12
- # that way. This allows us to effectively display more while not having to fetch
13
- # more partitions then the number of messages per page.
14
- # In cases like this we distribute partitions evenly part of partitions on each of
15
- # the pages. This may become unreliable for partitions that are not evenly
16
- # distributed but this allows us to display data for as many partitions as we want
17
- # without overloading the system
18
- class Partitions < Base
19
- class << self
20
- # Computers the partitions slice, materialized page and the limitations status
21
- # for a given page
22
- # @param partitions_count [Integer] number of partitions for a given topic
23
- # @param current_page [Integer] current page
24
- # @return [Array<Array<Integer>, Integer, Boolean>] list of partitions that should
25
- # be active on a given page, materialized page for them and info if we had to
26
- # limit the partitions number on a given page
27
- def call(partitions_count, current_page)
28
- # How many "chunks" of partitions we will have
29
- slices_count = (partitions_count / per_page.to_f).ceil
30
- # How many partitions in a single slice should we have
31
- in_slice = (partitions_count / slices_count.to_f).ceil
32
- # Which "chunked" page do we want to get
33
- materialized_page = (current_page / slices_count.to_f).ceil
34
- # Which slice is the one we are operating on
35
- active_slice_index = (current_page - 1) % slices_count
36
- # All available slices so we can pick one that is active
37
- partitions_slices = (0...partitions_count).each_slice(in_slice).to_a
38
- # Select active partitions only
39
- active_partitions = partitions_slices[active_slice_index]
40
- # Are we limiting ourselves because of partition count
41
- limited = slices_count > 1
42
-
43
- [active_partitions, materialized_page, limited]
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Lib
7
- module Paginations
8
- module Paginators
9
- # Paginator that allows us to take several lists/sets and iterate over them in a
10
- # round-robin fashion.
11
- #
12
- # It does not have to iterate over all the elements from each set for higher pages
13
- # making it much more effective than the naive implementation.
14
- class Sets < Base
15
- class << self
16
- # @param counts [Array<Integer>] sets elements counts
17
- # @param current_page [Integer] page number
18
- # @return [Hash<Integer, Range>] hash with integer keys indicating the count
19
- # location and the range needed to be taken of elements (counting backwards) for
20
- # each partition
21
- def call(counts, current_page)
22
- return {} if current_page < 1
23
-
24
- lists = counts.dup.map.with_index { |el, i| [i, el] }
25
-
26
- curr_item_index = 0
27
- curr_list_index = 0
28
- items_to_skip_count = per_page * (current_page - 1)
29
-
30
- loop do
31
- lists_count = lists.length
32
- return {} if lists_count.zero?
33
-
34
- shortest_list_count = lists.map(&:last).min
35
- mover = (shortest_list_count - curr_item_index)
36
- items_we_are_considering_count = lists_count * mover
37
-
38
- if items_we_are_considering_count >= items_to_skip_count
39
- curr_item_index += items_to_skip_count / lists_count
40
- curr_list_index = items_to_skip_count % lists_count
41
- break
42
- else
43
- curr_item_index = shortest_list_count
44
- lists.delete_if { |x| x.last == shortest_list_count }
45
- items_to_skip_count -= items_we_are_considering_count
46
- end
47
- end
48
-
49
- page_items = []
50
- largest_list_count = lists.map(&:last).max
51
-
52
- while page_items.length < per_page && curr_item_index < largest_list_count
53
- curr_list = lists[curr_list_index]
54
-
55
- if curr_item_index < curr_list.last
56
- page_items << [curr_list.first, curr_item_index]
57
- end
58
-
59
- curr_list_index += 1
60
- if curr_list_index == lists.length
61
- curr_list_index = 0
62
- curr_item_index += 1
63
- end
64
- end
65
-
66
- hashed = Hash.new { |h, k| h[k] = [] }
67
-
68
- page_items.each do |el|
69
- hashed[el.first] << el.last
70
- end
71
-
72
- hashed.each do |key, value|
73
- hashed[key] = (value.first..value.last)
74
- end
75
-
76
- hashed
77
- end
78
- end
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- # Non info related extra components used in the UI
7
- module Lib
8
- # Ttl Cache for caching things in-memory
9
- # @note It **is** thread-safe
10
- class TtlCache
11
- include ::Karafka::Core::Helpers::Time
12
-
13
- # @param ttl [Integer] time in ms how long should this cache keep data
14
- def initialize(ttl)
15
- @ttl = ttl
16
- @times = {}
17
- @values = {}
18
- @mutex = Mutex.new
19
- end
20
-
21
- # Reads data from the cache
22
- #
23
- # @param key [String, Symbol] key for the cache read
24
- # @return [Object] anything that was cached
25
- def read(key)
26
- @mutex.synchronize do
27
- evict
28
- @values[key]
29
- end
30
- end
31
-
32
- # Writes to the cache
33
- #
34
- # @param key [String, Symbol] key for the cache
35
- # @param value [Object] value we want to cache
36
- # @return [Object] value we have written
37
- def write(key, value)
38
- @mutex.synchronize do
39
- @times[key] = monotonic_now + @ttl
40
- @values[key] = value
41
- end
42
- end
43
-
44
- # Reads from the cache and if value not present, will run the block and store its result
45
- # in the cache
46
- #
47
- # @param key [String, Symbol] key for the cache read
48
- # @return [Object] anything that was cached or yielded
49
- def fetch(key)
50
- @mutex.synchronize do
51
- evict
52
-
53
- return @values[key] if @values.key?(key)
54
-
55
- @values[key] = yield
56
- end
57
- end
58
-
59
- private
60
-
61
- # Removes expired elements from the cache
62
- def evict
63
- @times.each do |key, time|
64
- next if time >= monotonic_now
65
-
66
- @times.delete(key)
67
- @values.delete(key)
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Ui
6
- module Models
7
- # Wraps around the `Karafka::Admin#cluster_info` with caching and some additional aliases
8
- # so we can reference relevant information easily
9
- class ClusterInfo
10
- class << self
11
- # Gets us all the cluster metadata info
12
- #
13
- # @param cached [Boolean] should we use cached data (true by default)
14
- # @return [Rdkafka::Metadata] cluster metadata info
15
- def fetch(cached: true)
16
- cache = ::Karafka::Web.config.ui.cache
17
-
18
- cluster_info = cache.read(:cluster_info)
19
-
20
- if cluster_info.nil? || !cached
21
- cluster_info = cache.write(:cluster_info, Karafka::Admin.cluster_info)
22
- end
23
-
24
- cluster_info
25
- end
26
-
27
- # Returns us all the info about available topics from the cluster
28
- #
29
- # @param cached [Boolean] should we use cached data (true by default)
30
- # @return [Array<Ui::Models::Topic>] topics details
31
- def topics(cached: true)
32
- fetch(cached: cached)
33
- .topics
34
- .map { |topic| Topic.new(topic) }
35
- end
36
-
37
- # Fetches us details about particular topic
38
- #
39
- # @param topic_name [String] name of the topic we are looking for
40
- # @param cached [Boolean] should we use cached data (true by default)
41
- # @return [Ui::Models::Topic] topic details
42
- def topic(topic_name, cached: true)
43
- topics(cached: cached)
44
- .find { |topic_data| topic_data.topic_name == topic_name }
45
- .tap { |topic| topic || raise(Web::Errors::Ui::NotFoundError, topic_name) }
46
- end
47
-
48
- # @param topic_name [String] name of the topic we are looking for
49
- # @param cached [Boolean] should we use cached data (true by default)
50
- # @return [Integer] number of partitions in a given topic
51
- def partitions_count(topic_name, cached: true)
52
- topic(topic_name, cached: cached).partition_count
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,21 +0,0 @@
1
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
2
- <thead>
3
- <tr class="align-middle">
4
- <th>Origin</th>
5
- <th>Process name</th>
6
- <th>Error</th>
7
- <th>Occurred at</th>
8
- <th></th>
9
- </tr>
10
- </thead>
11
-
12
- <tbody>
13
- <%==
14
- each_partial(
15
- @error_messages,
16
- 'errors/error',
17
- local: :error_msg
18
- )
19
- %>
20
- </tbody>
21
- </table>
@@ -1,31 +0,0 @@
1
- <div class="container mb-4">
2
- <div class="row">
3
- <div class="col">
4
- <h3>
5
- Errors
6
- </h3>
7
- </div>
8
-
9
- <div class="col">
10
- <div class="col-auto text-end">
11
- <label class="col-form-label">Partition</label>
12
- </div>
13
- </div>
14
-
15
- <div class="col pt-1 mb-0 pb-0">
16
- <div class="col-auto">
17
- <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
- <%==
19
- each_partial(
20
- [nil] + @partitions_count.times.to_a,
21
- 'errors/partition_option',
22
- local: :partition
23
- )
24
- %>
25
- </select>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <hr>
31
- </div>
@@ -1,17 +0,0 @@
1
- <%== partial('errors/title_with_select') %>
2
-
3
- <div class="container">
4
- <div class="row mb-5">
5
- <div class="col-sm-12">
6
- <%== partial('explorer/partition/watermark_offsets') %>
7
-
8
- <% if @watermark_offsets.empty? %>
9
- <%== partial 'errors/no_errors' %>
10
- <% elsif @watermark_offsets.cleaned? %>
11
- <%== partial 'errors/cleaned' %>
12
- <% else %>
13
- <%== partial 'errors/table' %>
14
- <% end %>
15
- </div>
16
- </div>
17
- </div>
@@ -1,3 +0,0 @@
1
- <div class="alert alert-info mt-4" role="alert">
2
- This topic is empty and does not contain any data in any of the partitions.
3
- </div>
@@ -1,4 +0,0 @@
1
- <div class="alert alert-info mt-4 mb-4" role="alert">
2
- Due to many partitions, only part of the data is visible on each page.
3
- Please navigate through the pages to view all data.
4
- </div>
@@ -1,11 +0,0 @@
1
- <p class="text-end mb-4">
2
- Partitions:
3
- <span class="badge bg-secondary mt-1 mb-1">
4
- total: <%= @partitions_count %>
5
- </span>
6
-
7
- <span class="badge bg-secondary mt-1 mb-1">
8
- visible:
9
- <%= [@active_partitions.first, @active_partitions.last].uniq.join(' to ') %>
10
- </span>
11
- </p>
@@ -1,49 +0,0 @@
1
- <div class="container mb-4">
2
- <div class="row">
3
- <div class="col">
4
- <h3>
5
- <%= @topic_id %>
6
- </h3>
7
- </div>
8
-
9
- <div class="col">
10
- <div class="col-auto text-end">
11
- <label class="col-form-label">Partition</label>
12
- </div>
13
- </div>
14
-
15
- <div class="col pt-1 mb-0 pb-0">
16
- <div class="col-auto">
17
- <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
- <%==
19
- each_partial(
20
- [nil] + @partitions_count.times.to_a,
21
- 'explorer/partition_option',
22
- local: :partition
23
- )
24
- %>
25
- </select>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <hr>
31
- </div>
32
-
33
- <div class="container">
34
- <div class="row mb-5">
35
- <div class="col-sm-12">
36
- <%== partial('explorer/topic/partitions') %>
37
-
38
- <% if @limited %>
39
- <%== partial('explorer/topic/limited') %>
40
- <% end %>
41
-
42
- <% if @messages.empty? && params.current_page == 1 %>
43
- <%== partial 'explorer/topic/empty' %>
44
- <% else %>
45
- <%== partial('explorer/partition/messages') %>
46
- <% end %>
47
- </div>
48
- </div>
49
- </div>