karafka-web 0.10.3 → 0.10.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5790e7352a06e0a780810c40aac53e9b5c878a84990c70b28bdc4d49d3ab921d
4
- data.tar.gz: e5ef8e226602ad0388b138b676d705f9dbda06363a0001b2c5e483abab9f2bed
3
+ metadata.gz: 13c431e0fa6d1b8927bd419298bc0ea522f0e823f91197fe989f72a9a08479ad
4
+ data.tar.gz: 6424f804a013bc34d1393fa79962cfacab6e6d5028726b7e90e93ada457b7a48
5
5
  SHA512:
6
- metadata.gz: a645ae9fbbe73c045562b38f744e923e3bb4ac7be47f5c49dd664a1b61513ab07706348461ef7858d3c5518a0c70c5f31addf66e146cd76e91579590e7baa268
7
- data.tar.gz: 4e5a11cd6d5333b1dff7f95856818cbe14a7a7fa172dc5cbf6d4a1409883b862dc97dc9a4799cf247023e12fdaecbae749e2d44647783af770ce3ca0cd95e51c
6
+ metadata.gz: e3ccb77dcf9624e1ca23473a963ea59cd8efc227feae098c7a80898b45c573eb70b564fd963abc6d3b0dd01a4b9e0577c1708bc2904afa6c5523360fc3880362
7
+ data.tar.gz: 60f20e2ed98fb8818164157e91ce117c5fb2d6b60f5c1371abef787f0f637269f27ed378a0ca8ffe7e95c43defddfc4749cfe1c06cbf905c8e591f8b171c2c36
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Karafka Web Changelog
2
2
 
3
+ ## 0.10.4 (2024-11-26)
4
+ - **[Breaking]** Drop Ruby `3.0` support according to the EOL schedule.
5
+ - [Enhancement] Extract producers tracking `sync_threshold` into an internal config.
6
+ - [Enhancement] Support complex Pro license loading strategies (Pro).
7
+ - [Enhancement] Change default `retention.ms` for the metrics topic to support Redpanda Cloud defaults (#450).
8
+ - [Enhancement] Include subscription group id in the consumers error tracking metadata.
9
+ - [Enhancement] Collect metadata details of low level client errors when error tracking.
10
+ - [Enhancement] Collect metadata details of low level listener errors when error tracking.
11
+ - [Fix] Toggle menu button post-turbo refresh stops working.
12
+
3
13
  ## 0.10.3 (2024-09-17)
4
14
  - **[Feature]** Introduce ability to brand Web UI with environment (Pro).
5
15
  - [Enhancement] Provide assignment status in the routing (Pro).
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.10.3)
4
+ karafka-web (0.10.4)
5
5
  erubi (~> 1.4)
6
6
  karafka (>= 2.4.10, < 2.5.0)
7
7
  karafka-core (>= 2.4.0, < 2.5.0)
@@ -56,7 +56,7 @@ GEM
56
56
  logger (1.6.1)
57
57
  mini_portile2 (2.8.7)
58
58
  minitest (5.25.1)
59
- ostruct (0.6.0)
59
+ ostruct (0.6.1)
60
60
  raabro (1.4.0)
61
61
  rack (3.1.4)
62
62
  rack-test (2.1.0)
data/karafka-web.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_development_dependency 'rackup', '~> 0.2'
26
26
 
27
- spec.required_ruby_version = '>= 3.0.0'
27
+ spec.required_ruby_version = '>= 3.1.0'
28
28
 
29
29
  if $PROGRAM_NAME.end_with?('gem')
30
30
  spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
@@ -41,8 +41,6 @@ Gem::Specification.new do |spec|
41
41
  .reject { |f| f.start_with?('.') }
42
42
  .reject { |f| f.end_with?('.map') }
43
43
 
44
- p spec.files.select { |a| a.include?('.map')}
45
-
46
44
  spec.metadata = {
47
45
  'funding_uri' => 'https://karafka.io/#become-pro',
48
46
  'homepage_uri' => 'https://karafka.io',
@@ -76,7 +76,7 @@ module Karafka
76
76
  # Reports the metrics collected in the consumer sampler
77
77
  setting :reporter, default: Tracking::Consumers::Reporter.new
78
78
 
79
- # Minimum number of messages to produce to produce them in sync mode
79
+ # Minimum number of messages to produce them in sync mode
80
80
  # This acts as a small back-off not to overload the system in case we would have
81
81
  # extremely big number of errors and reports happening
82
82
  setting :sync_threshold, default: 50
@@ -98,6 +98,11 @@ module Karafka
98
98
  end
99
99
 
100
100
  setting :producers do
101
+ # Minimum number of messages to produce them in sync mode
102
+ # This acts as a small back-off not to overload the system in case we would have
103
+ # extremely big number of errors happening
104
+ setting :sync_threshold, default: 25
105
+
101
106
  # Reports the metrics collected in the producer sampler
102
107
  setting :reporter, default: Tracking::Producers::Reporter.new
103
108
 
@@ -41,6 +41,7 @@ module Karafka
41
41
  required(:reporter) { |val| !val.nil? }
42
42
  required(:sampler) { |val| !val.nil? }
43
43
  required(:listeners) { |val| val.is_a?(Array) }
44
+ required(:sync_threshold) { |val| val.is_a?(Integer) && val.positive? }
44
45
  end
45
46
  end
46
47
 
@@ -81,7 +81,7 @@ module Karafka
81
81
  replication_factor,
82
82
  {
83
83
  'cleanup.policy': 'compact',
84
- 'retention.ms': 60 * 60 * 1_000, # 1h
84
+ 'retention.ms': 24 * 60 * 60 * 1_000, # 1 day
85
85
  'segment.ms': 24 * 60 * 60 * 1_000, # 1 day
86
86
  'segment.bytes': 104_857_600 # 100MB
87
87
  }
@@ -17,6 +17,25 @@ module Karafka
17
17
  # Loader requires and loads all the pro components only when they are needed
18
18
  class Loader
19
19
  class << self
20
+ # This loads the pro components into memory in case someone required karafka-web prior
21
+ # to the license usage. This can happen for users with complex require flows, where
22
+ # Karafka license is not part of the standard flow
23
+ #
24
+ # In such cases Web may not notice that Karafka should operate in a Pro mode when it is
25
+ # being required via Zeitwerk. In such cases we load Pro components prior to the setup.
26
+ def load_on_late_setup
27
+ return if defined?(Karafka::Web::Pro::Commanding)
28
+
29
+ loader = Zeitwerk::Loader.new
30
+ loader.push_dir(
31
+ File.join(Karafka::Web.gem_root, 'lib/karafka/web/pro'),
32
+ namespace: Karafka::Web::Pro
33
+ )
34
+
35
+ loader.setup
36
+ loader.eager_load
37
+ end
38
+
20
39
  # Loads all the Web UI pro components and configures them wherever it is expected
21
40
  # @param config [Karafka::Core::Configurable::Node] web config that we can alter with pro
22
41
  # components
@@ -18,17 +18,24 @@ module Karafka
18
18
  #
19
19
  # @param event [Karafka::Core::Monitoring::Event]
20
20
  def on_error_occurred(event)
21
- track do |sampler|
22
- # Collect extra info if it was a consumer related error.
23
- # Those come from user code
24
- details = if event[:caller].is_a?(Karafka::BaseConsumer)
25
- extract_consumer_info(event[:caller])
26
- else
27
- {}
28
- end
21
+ caller_ref = event[:caller]
22
+
23
+ # Collect extra info if it was a consumer related error.
24
+ # Those come from user code
25
+ details = case caller_ref
26
+ when Karafka::BaseConsumer
27
+ extract_consumer_info(caller_ref)
28
+ when Karafka::Connection::Client
29
+ extract_client_info(caller_ref)
30
+ when Karafka::Connection::Listener
31
+ extract_listener_info(caller_ref)
32
+ else
33
+ {}
34
+ end
29
35
 
30
- error_class, error_message, backtrace = extract_error_info(event[:error])
36
+ error_class, error_message, backtrace = extract_error_info(event[:error])
31
37
 
38
+ track do |sampler|
32
39
  sampler.errors << {
33
40
  schema_version: SCHEMA_VERSION,
34
41
  type: event[:type],
@@ -70,6 +77,7 @@ module Karafka
70
77
  {
71
78
  topic: consumer.topic.name,
72
79
  consumer_group: consumer.topic.consumer_group.id,
80
+ subscription_group: consumer.topic.subscription_group.id,
73
81
  partition: consumer.partition,
74
82
  first_offset: consumer.messages.metadata.first_offset,
75
83
  last_offset: consumer.messages.metadata.last_offset,
@@ -80,6 +88,27 @@ module Karafka
80
88
  tags: consumer.tags
81
89
  }
82
90
  end
91
+
92
+ # @param client [::Karafka::Connection::Client]
93
+ # @return [Hash] hash with client specific info for details of error
94
+ def extract_client_info(client)
95
+ {
96
+ consumer_group: client.subscription_group.consumer_group.id,
97
+ subscription_group: client.subscription_group.id,
98
+ name: client.name,
99
+ id: client.id
100
+ }
101
+ end
102
+
103
+ # @param listener [::Karafka::Connection::Listener]
104
+ # @return [Hash] hash with listener specific info for details of error
105
+ def extract_listener_info(listener)
106
+ {
107
+ consumer_group: listener.subscription_group.consumer_group.id,
108
+ subscription_group: listener.subscription_group.id,
109
+ id: listener.id
110
+ }
111
+ end
83
112
  end
84
113
  end
85
114
  end
@@ -10,13 +10,6 @@ module Karafka
10
10
  # because there is no expectation on immediate status updates for producers and their
11
11
  # dispatch flow is always periodic based.
12
12
  class Reporter < Tracking::Reporter
13
- # Minimum number of messages to produce to produce them in sync mode
14
- # This acts as a small back-off not to overload the system in case we would have
15
- # extremely big number of errors happening
16
- PRODUCE_SYNC_THRESHOLD = 25
17
-
18
- private_constant :PRODUCE_SYNC_THRESHOLD
19
-
20
13
  # This mutex is shared between tracker and samplers so there is no case where metrics
21
14
  # would be collected same time tracker reports
22
15
  MUTEX = Mutex.new
@@ -82,7 +75,7 @@ module Karafka
82
75
  # normal operations we should not have that many messages to dispatch and it should not
83
76
  # slowdown any processing.
84
77
  def produce(messages)
85
- if messages.count >= PRODUCE_SYNC_THRESHOLD
78
+ if messages.count >= ::Karafka::Web.config.tracking.producers.sync_threshold
86
79
  ::Karafka::Web.producer.produce_many_sync(messages)
87
80
  else
88
81
  ::Karafka::Web.producer.produce_many_async(messages)
@@ -51,7 +51,7 @@ function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"f
51
51
  /*! Source: lib/karafka/web/ui/public/javascripts/charts/data_formatting_utility.js */
52
52
  let DataFormattingUtils={niceBytes(e,t=2){let i=0,s=parseInt(e,10)||0;for(;1024<=s&&++i;)s/=1024;return s.toFixed(s<10&&0<i?1:t)+" "+["bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][i]},formatLabelX(e,t){return"date"!==t?e:("00"+((t=new Date(1e3*e)).getMonth()+1)).slice(-2)+"/"+("00"+t.getDate()).slice(-2)+"/"+t.getFullYear()+" "+("00"+t.getHours()).slice(-2)+":"+("00"+t.getMinutes()).slice(-2)+":"+("00"+t.getSeconds()).slice(-2)},formatTooltip(e,t){var i=t.parsed.y,s=t.dataset.label;switch(e){case"percentage":return Math.floor(i)===i?s+": "+i+" %":s+": "+Math.round(100*i)/100+" %";case"memory":return s+": "+DataFormattingUtils.niceBytes(1024*i,2);default:return t.yLabel}},formatLabelY(e,t){switch(e){case"percentage":return Math.floor(t)===t?t+"%":Math.round(100*t)/100+"%";case"memory":return DataFormattingUtils.niceBytes(1024*t,1);default:return Math.floor(t)===t?t:Math.round(100*t)/100}},isFractionalPrecision(e){return e!==Math.floor(e)}};
53
53
  /*! Source: lib/karafka/web/ui/public/javascripts/charts/dataset_state_manager.js */class DatasetStateManager{constructor(){this.storageKey="karafkaDisabledDatasets"}readAll(){var e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):{}}saveAll(e){localStorage.setItem(this.storageKey,JSON.stringify(e))}saveCurrent(){var e=document.querySelectorAll(".chartjs"),t=window.location.href.split("?")[0];let i={};var s=this.readAll();e.forEach(e=>{var e=e.id,t=Chart.getChart(e);t&&t.legend&&t.legend.legendItems&&0<(t=t.legend.legendItems.map((e,t)=>e.hidden?t:null).filter(e=>null!==e)).length&&(i[e]=t)}),s[t]=i,this.saveAll(s)}getCurrentChart(e){var t=window.location.href.split("?")[0];return(this.readAll()[t]||{})[e]||[]}}
54
- /*! Source: lib/karafka/web/ui/public/javascripts/components/btn_toggle_manager.js */class BtnToggleManager{constructor(e=".btn-toggle",t="hidden"){this.btnClass=e,this.visibilityClass=t,this.init()}init(){document.querySelectorAll(this.btnClass).forEach(t=>{let i=t.getAttribute("data-toggle-target"),s=document.getElementById(i);s&&(this.restoreVisibility(t,s),t.addEventListener("click",()=>{var e=!s.classList.contains(this.visibilityClass);s.classList.toggle(this.visibilityClass),t.classList.toggle("active",!e),this.saveVisibility(i,!e)}))})}saveVisibility(e,t){localStorage.setItem(e+"_visibility",t)}restoreVisibility(e,t){var i=localStorage.getItem(t.id+"_visibility"),i=i?"true"===i:!t.classList.contains(this.visibilityClass);t.classList.toggle(this.visibilityClass,!i),e.classList.toggle("active",i)}}
54
+ /*! Source: lib/karafka/web/ui/public/javascripts/components/btn_toggle_manager.js */class BtnToggleManager{constructor(e=".btn-toggle",t="hidden"){this.btnClass=e,this.visibilityClass=t,this.init()}init(){document.querySelectorAll(this.btnClass).forEach(t=>{let i=t.getAttribute("data-toggle-target"),s=document.getElementById(i);s&&(this.restoreVisibility(t,s),t._isClickListenerAdded||(t.addEventListener("click",()=>{var e=!s.classList.contains(this.visibilityClass);s.classList.toggle(this.visibilityClass),t.classList.toggle("active",!e),this.saveVisibility(i,!e)}),t._isClickListenerAdded=!0))})}saveVisibility(e,t){localStorage.setItem(e+"_visibility",t)}restoreVisibility(e,t){var i=localStorage.getItem(t.id+"_visibility"),i=i?"true"===i:!t.classList.contains(this.visibilityClass);t.classList.toggle(this.visibilityClass,!i),e.classList.toggle("active",i)}}
55
55
  /*! Source: lib/karafka/web/ui/public/javascripts/components/charts.js */function refreshCharts(e){(new LineChartsManager).refreshAndRender(e,!0),(new BarChartManager).refreshAndRenderBarCharts(e,!0)}function manageCharts(){(new LineChartsManager).refreshAndRender(document,!1),(new BarChartManager).refreshAndRenderBarCharts(document,!1)}
56
56
  /*! Source: lib/karafka/web/ui/public/javascripts/components/live_poll.js */var livePollTimer=null,oldDOM=null,datePicker=null,startURL=window.location.href;let isHoveringOverClickable=!1;function initLivePolling(){document.addEventListener("mouseover",function(e){isElementClickable(e.target)&&(isHoveringOverClickable=!0)}),document.addEventListener("mouseout",function(e){isElementClickable(e.target)&&(isHoveringOverClickable=!1)}),null==localStorage.karafkaLivePoll&&(localStorage.karafkaLivePoll="enabled")}function isFormActive(){var e=document.activeElement;return["INPUT","TEXTAREA","SELECT","BUTTON","FIELDSET"].includes(e.tagName)}function isElementClickable(e){return!!("A"===e.tagName||"BUTTON"===e.tagName||"INPUT"===e.tagName&&("button"===e.type||"submit"===e.type)||e.hasAttribute("onclick")||"function"==typeof e.onclick||"SPAN"===e.tagName&&e.closest(".tab-container")||e.closest("button")||e.closest("a"))}function isUserHoveringOverClickable(){return isHoveringOverClickable}function isAnyTextSelected(){var e="";return void 0!==window.getSelection?e=window.getSelection().toString():void 0!==document.selection&&"Text"==document.selection.type&&(e=document.selection.createRange().text),""!=e}function isCollapsingHappening(){return 0<document.querySelectorAll(".collapsing").length}function isPollingPossible(e=!1){return!(isFormActive()||isUserHoveringOverClickable()||isAnyTextSelected()||isOffsetLookupCalendarVisible()||isAnyModalOpen()||isCollapsingHappening()||isTurboOperating()||e&&startURL!=window.location.href)}function isAnyModalOpen(){var e;for(e of document.querySelectorAll("dialog"))if(e.open)return!0;return!1}function bindPollingButtonClick(){var e=document.getElementById("live-poll");null!=e&&e.addEventListener("click",handleLivePollingButtonClick)}function handleLivePollingButtonClick(){toggleLivePollState(),setLivePollButton(),setPollingListener()}function toggleLivePollState(){"enabled"==localStorage.karafkaLivePoll?localStorage.karafkaLivePoll="disabled":localStorage.karafkaLivePoll="enabled"}function setLivePollButton(){null!=(selector=document.getElementById("live-poll"))&&("enabled"==localStorage.karafkaLivePoll?(selector.classList.add("text-base-content"),selector.classList.remove("text-gray-500")):(selector.classList.add("text-gray-500"),selector.classList.remove("text-base-content")))}function checkResponse(e){if(e.ok)return e;throw e}function refreshPage(e){if(!isPollingPossible())return!1;var t,e=(new DOMParser).parseFromString(e,"text/html"),i=e.getElementById("content");oldDOM!=i.innerHTML&&(t=document.querySelectorAll(".chartjs").length,0==i.querySelectorAll(".chartjs").length||0==t?(document.getElementById("content").replaceWith(i),addListeners()):(t=e.getElementById("refreshable"),document.getElementById("refreshable").replaceWith(t),refreshCharts(e)),oldDOM=i.innerHTML)}function showError(e){console.error(e)}function scheduleLivePoll(){null==oldDOM&&(oldDOM=document.getElementById("content").innerHTML);let e=parseInt(localStorage.karafkaTimeInterval)||5e3;e<1e3&&(localStorage.karafkaTimeInterval=5e3,e=5e3),livePollTimer=setTimeout(livePollCallback,e)}function livePollCallback(){clearTimeout(livePollTimer),livePollTimer=null,isPollingPossible(!1)?(startURL=window.location.href,fetch(window.location.href).then(checkResponse).then(e=>e.text()).then(refreshPage).catch(showError).finally(setPollingListener)):setPollingListener()}function setPollingListener(){var e=document.getElementById("live-poll"),t=localStorage.karafkaLivePoll;"disabled"==t||null==t||null==e?(clearTimeout(livePollTimer),livePollTimer=null):(clearTimeout(livePollTimer),scheduleLivePoll())}
57
57
  /*! Source: lib/karafka/web/ui/public/javascripts/components/offset_datetime.js */function loadOffsetLookupDatePicker(){var e={locale:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear",dateFormat:"yyyy-MM-dd",timeFormat:"HH:mm",firstDay:1},timepicker:!0,onSelect:({})=>{document.getElementById("offset-lookup-datepicker").value=""},onShow:function(){offsetLookupDatePicker.selectDate((new Date).getTime()),offsetLookupDatePicker.maxDate=new Date},onHide:function(){offsetLookupDatePicker.selectDate((new Date).getTime())},buttons:[{content(e){return"Go to offset"},onClick(e){var t=e.selectedDates[0]||new Date,i=e.$el.dataset.target;e.hide(),location.href=i+"/"+formatRedirectDateTime(t)}}]};null!=offsetLookupDatePicker&&offsetLookupDatePicker.destroy(),null!=document.getElementById("offset-lookup-datepicker")&&((offsetLookupDatePicker=new AirDatepicker("#offset-lookup-datepicker",e)).maxDate=new Date,offsetLookupDatePicker.selectDate((new Date).getTime()))}function formatRedirectDateTime(e){return e.getFullYear()+`-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}/${String(e.getHours()).padStart(2,"0")}:`+String(e.getMinutes()).padStart(2,"0")}function isOffsetLookupCalendarVisible(){return null!=offsetLookupDatePicker&&offsetLookupDatePicker.visible}
@@ -61,4 +61,5 @@ let DataFormattingUtils={niceBytes(e,t=2){let i=0,s=parseInt(e,10)||0;for(;1024<
61
61
  /*! Source: lib/karafka/web/ui/public/javascripts/components/turbo_tracker.js */let turboIsOperating=!1;function isTurboOperating(){return turboIsOperating}
62
62
  /*! Source: lib/karafka/web/ui/public/javascripts/application.js */function updateTimeAgo(){0!=(e=document.querySelectorAll("time")).length&&(timeago.render(e),timeago.cancel());for(var e=document.getElementsByClassName("time-title"),t=0;t<e.length;t++){var i=e[t],s=i.getAttribute("title");i.setAttribute("title",timeago.format(s))}}function refreshTitle(){var e=document.querySelectorAll(".breadcrumbs a"),e=Array.from(e).slice(1).map(e=>e.textContent.trim());0<e.length?document.title=e.join(" > ")+" - Karafka Web UI":document.title="Karafka Web UI"}function redirectToPartition(){var e=document.getElementById("current-partition");null!=e&&e.addEventListener("change",function(){Turbo.visit(this.value)})}function bindActionsConfirmations(){for(var t=document.getElementsByClassName("confirm-action"),i=0;i<t.length;i++){var s=t[i];let e="click";"FORM"===s.nodeName&&(e="submit"),s.addEventListener(e,function(e){window.confirm("Are you sure?")||e.preventDefault()})}}function bindLockableButtons(){document.querySelectorAll(".btn-lockable").forEach(function(i){i.addEventListener("click",function(e){var t=i.closest("form");t?t.addEventListener("submit",function(){i.disabled=!0,i.textContent+="...",document.querySelectorAll(".modal").forEach(function(e){e.classList.add("modal-locked")})},{once:!0}):(i.disabled=!0,i.textContent+="...")})})}function addListeners(){initLivePolling(),bindPollingButtonClick(),bindLockableButtons(),setLivePollButton(),setPollingListener(),hljs.highlightAll(),updateTimeAgo(),redirectToPartition(),(new TabsManager).manageTabs(),manageCharts(),bindActionsConfirmations(),loadOffsetLookupDatePicker(),new BtnToggleManager,new BtnToggleManager(".btn-toggle-nav-collapsed","collapsed"),new ThemeManager,refreshTitle(),new SearchMetadataVisibilityManager,new SearchModalManager}document.addEventListener("turbo:visit",function(){turboIsOperating=!0}),document.addEventListener("turbo:before-fetch-request",function(){turboIsOperating=!0}),document.addEventListener("turbo:before-fetch-response",function(){turboIsOperating=!0}),document.addEventListener("turbo:load",function(){turboIsOperating=!1}),document.addEventListener("turbo:frame-load",function(){turboIsOperating=!1}),document.addEventListener("turbo:frame-render",function(){turboIsOperating=!1}),document.addEventListener("turbo:load",addListeners),Turbo.setProgressBarDelay(100)
63
63
  /*! Source: lib/karafka/web/ui/public/javascripts/charts/types/bar.js */;class BarChartManager{constructor(){this.datasetStateManager=new DatasetStateManager}refreshAndRenderBarCharts(c,u=!1){(u?c:document).querySelectorAll(".chartjs-bar").forEach(e=>{var t=e.id,i=(u?c:document).getElementById(t),s=JSON.parse(i.dataset.datasets);let r=[],a=[],n=[];var o=i.dataset.label_type_y;let l=i.dataset.label_type_x,h=this.datasetStateManager.getCurrentChart(t);Object.entries(s).forEach(([e,t],i)=>{t.forEach(([e,t])=>{n.push(t),0===i&&r.push(DataFormattingUtils.formatLabelX(e,l))}),a.push({data:t.map(([,e])=>e),label:e,hidden:h.includes(i),borderWidth:2.5})});var i=Math.min(...n),s=Math.max(...n),i=Math.round(i-.1*i),s=Math.round(s+.005*s),d=Math.round(n.reduce((e,t)=>e+t,0)/n.length);a.push({type:"line",label:"Average",data:new Array(r.length).fill(d),borderWidth:2,fill:!1,pointRadius:0,hoverBorderWidth:3,pointHitRadius:20}),u?((d=Chart.getChart(t)).data.datasets=a,d.data.labels=r,d.options.scales.y.min=i,d.options.scales.y.max=s,d.update("none")):this.renderBarChart(e,r,a,i,s,o)})}renderBarChart(e,t,i,s,r,a){new Chart(e,{type:"bar",data:{labels:t,datasets:i},options:{responsive:!0,maintainAspectRatio:!1,aspectRatio:5,scales:{x:{display:!0},y:{beginAtZero:!1,min:s,max:r,ticks:{maxTicksLimit:8,callback:function(e,t,i){return DataFormattingUtils.formatLabelY(a,e,t,i)}}}},animation:!1,animations:{colors:!1,x:!1},transitions:{active:{animation:{duration:!1}}},plugins:{legend:{position:"hidden"},tooltip:{callbacks:{label:function(e){let t=e.dataset.label||"";return"Average"!==t?DataFormattingUtils.formatTooltip(a,e):t+=": "+e.formattedValue}}}}}})}}
64
- /*! Source: lib/karafka/web/ui/public/javascripts/charts/types/line.js */class LineChartsManager{constructor(){this.datasetStateManager=new DatasetStateManager}getLegendHeightPercentage(e){var t=e.chartArea,e=e.height,t=e-(t.bottom-t.top);return Math.round(t/e*100)}afterRenderPlugin(){let i=this;return{id:"afterRender",afterRender:function(e){var t=i.getLegendHeightPercentage(e),e=document.getElementById(e.canvas.id);50<t&&""==e.parentElement.style.height&&(e.parentElement.style.height="400px")}}}refreshAndRender(d,c=!1){(c?d:document).querySelectorAll(".chartjs-line").forEach(e=>{var t=e.id,i=(c?d:document).getElementById(t),s=JSON.parse(i.dataset.datasets);let r=[],a=[],n=0;var o=i.dataset.label_type_y;let l=i.dataset.label_type_x,h=this.datasetStateManager.getCurrentChart(t);Object.entries(s).forEach(([e,t],i)=>{t.forEach(([e,t])=>{0===i&&r.push(DataFormattingUtils.formatLabelX(e,l)),DataFormattingUtils.isFractionalPrecision(t)&&(n=2)}),a.push({data:t,label:e,hidden:h.includes(i),borderWidth:2.5,pointHitRadius:10})}),c?((i=Chart.getChart(t)).data.datasets=a,i.data.labels=r,i.update("none")):this.render(e,r,a,n,o)})}render(e,t,i,s,r){var a=null,a=10<i.length?"point":"x";new Chart(e,{type:"line",data:{labels:t,datasets:i},options:{responsive:!0,maintainAspectRatio:!1,aspectRatio:5,title:{display:!1},interaction:{mode:"nearest",axis:"x",intersect:!1},animation:!1,transitions:{active:{animation:{duration:!1}}},plugins:{legend:{position:"bottom",labels:{padding:20},onClick:(e,t,i)=>{var s=t.datasetIndex,i=i.chart;i.isDatasetVisible(s)?(i.hide(s),t.hidden=!0):(i.show(s),t.hidden=!1),this.datasetStateManager.saveCurrent()}},tooltip:{mode:a,filter:function(e,t,i){return t<10},callbacks:{label:function(e){return DataFormattingUtils.formatTooltip(r,e)}}}},scales:{x:{display:!1},y:{ticks:{precision:s,count:5,callback:function(e,t,i){return DataFormattingUtils.formatLabelY(r,e,t,i)}}}},elements:{point:{radius:0,style:!1},line:{style:"star",radius:0,spanGaps:!1}},hover:{mode:"index",intersect:!1}},plugins:[this.afterRenderPlugin()]})}}
64
+ /*! Source: lib/karafka/web/ui/public/javascripts/charts/types/line.js */class LineChartsManager{constructor(){this.datasetStateManager=new DatasetStateManager}getLegendHeightPercentage(e){var t=e.chartArea,e=e.height,t=e-(t.bottom-t.top);return Math.round(t/e*100)}afterRenderPlugin(){let i=this;return{id:"afterRender",afterRender:function(e){var t=i.getLegendHeightPercentage(e),e=document.getElementById(e.canvas.id);50<t&&""==e.parentElement.style.height&&(e.parentElement.style.height="400px")}}}refreshAndRender(d,c=!1){(c?d:document).querySelectorAll(".chartjs-line").forEach(e=>{var t=e.id,i=(c?d:document).getElementById(t),s=JSON.parse(i.dataset.datasets);let r=[],a=[],n=0;var o=i.dataset.label_type_y;let l=i.dataset.label_type_x,h=this.datasetStateManager.getCurrentChart(t);Object.entries(s).forEach(([e,t],i)=>{t.forEach(([e,t])=>{0===i&&r.push(DataFormattingUtils.formatLabelX(e,l)),DataFormattingUtils.isFractionalPrecision(t)&&(n=2)}),a.push({data:t,label:e,hidden:h.includes(i),borderWidth:2.5,pointHitRadius:10})}),c?((i=Chart.getChart(t)).data.datasets=a,i.data.labels=r,i.update("none")):this.render(e,r,a,n,o)})}render(e,t,i,s,r){var a=null,a=10<i.length?"point":"x";new Chart(e,{type:"line",data:{labels:t,datasets:i},options:{responsive:!0,maintainAspectRatio:!1,aspectRatio:5,title:{display:!1},interaction:{mode:"nearest",axis:"x",intersect:!1},animation:!1,transitions:{active:{animation:{duration:!1}}},plugins:{legend:{position:"bottom",labels:{padding:20},onClick:(e,t,i)=>{var s=t.datasetIndex,i=i.chart;i.isDatasetVisible(s)?(i.hide(s),t.hidden=!0):(i.show(s),t.hidden=!1),this.datasetStateManager.saveCurrent()}},tooltip:{mode:a,filter:function(e,t,i){return t<10},callbacks:{label:function(e){return DataFormattingUtils.formatTooltip(r,e)}}}},scales:{x:{display:!1},y:{ticks:{precision:s,count:5,callback:function(e,t,i){return DataFormattingUtils.formatLabelY(r,e,t,i)}}}},elements:{point:{radius:0,style:!1},line:{style:"star",radius:0,spanGaps:!1}},hover:{mode:"index",intersect:!1}},plugins:[this.afterRenderPlugin()]})}}
65
+ //# sourceMappingURL=application.min.js.map
@@ -6,6 +6,7 @@
6
6
  'hidden' class on their target elements (defined by the data attribute `data-toggle-target`)
7
7
  when clicked.
8
8
  */
9
+
9
10
  class BtnToggleManager {
10
11
  constructor(btnClass = '.btn-toggle', visibilityClass = 'hidden') {
11
12
  this.btnClass = btnClass;
@@ -23,13 +24,22 @@ class BtnToggleManager {
23
24
  // Establish initial state from local storage or based on visibility
24
25
  this.restoreVisibility(button, targetElement);
25
26
 
26
- // Add event listener to toggle visibility
27
- button.addEventListener('click', () => {
28
- const isVisible = !targetElement.classList.contains(this.visibilityClass);
29
- targetElement.classList.toggle(this.visibilityClass);
30
- button.classList.toggle('active', !isVisible);
31
- this.saveVisibility(targetId, !isVisible);
32
- });
27
+ // Check if the event listener has already been added
28
+ if (!button._isClickListenerAdded) {
29
+ // Define the event handler and store the flag to prevent duplicate listeners
30
+ const handleClick = () => {
31
+ const isVisible = !targetElement.classList.contains(this.visibilityClass);
32
+ targetElement.classList.toggle(this.visibilityClass);
33
+ button.classList.toggle('active', !isVisible);
34
+ this.saveVisibility(targetId, !isVisible);
35
+ };
36
+
37
+ // Add the event listener
38
+ button.addEventListener('click', handleClick);
39
+
40
+ // Set flag to indicate the listener has been added
41
+ button._isClickListenerAdded = true;
42
+ }
33
43
  });
34
44
  }
35
45