Skip to content

Commit

Permalink
Provide calendar for offset lookups (#109)
Browse files Browse the repository at this point in the history
* provide calendar for offset lookups

* remarks
  • Loading branch information
mensfeld authored Sep 8, 2023
1 parent e3404bd commit 073d73a
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 3 deletions.
7 changes: 6 additions & 1 deletion lib/karafka/web/ui/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,16 @@ class Base < Roda

plugin :class_matchers

# Time matcher with optional hours, minutes and seconds
TIME_MATCHER = %r{(\d{4}-\d{2}-\d{2}/?(\d{2})?(:\d{2})?(:\d{2})?)}

private_constant :TIME_MATCHER

# Match a date-time. Useful for time-related routes
# @note In case the date-time is invalid, raise and render 404
# @note The time component is optional as `Time#parse` will fallback to lowest time
# available, so we can build only date based lookups
class_matcher(Time, %r{(\d{4}-\d{2}-\d{2}/?(\d{2})?(:\d{2})?(:\d{2})?)}) do |datetime|
class_matcher(Time, TIME_MATCHER) do |datetime|
[Time.parse(datetime)]
rescue ArgumentError
raise Errors::Ui::NotFoundError
Expand Down
15 changes: 14 additions & 1 deletion lib/karafka/web/ui/pro/views/explorer/partition/_details.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@
<div class="row">
<div class="col-sm-6 ms-0 ps-0">
<% if @messages && !@messages.empty? %>
<a href="<%= explorer_path(@topic_id, @partition_id, 'recent') %>" class="btn btn-secondary btn-sm" title="Display the most recent message for this partition">
<a
href="<%= explorer_path(@topic_id, @partition_id, 'recent') %>"
class="btn btn-secondary btn-sm"
title="Display the most recent message for this partition"
>
&#x2192; Recent
</a>
<% end %>

<% closest_path = explorer_path(@topic_id, @partition_id) %>
<input
type="button"
class="btn-secondary btn btn-sm"
id="offset-lookup-datepicker"
value="&#128198;"
data-target="<%= closest_path %>"
/>
</div>

<div class="col-sm-6 text-end me-0 pe-0">
Expand Down
1 change: 1 addition & 0 deletions lib/karafka/web/ui/public/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function addListeners() {
manageTabs();
manageCharts();
bindActionsConfirmations();
loadOffsetLookupDatePicker();
displayUi();
}

Expand Down
6 changes: 6 additions & 0 deletions lib/karafka/web/ui/public/javascripts/datepicker.js

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion lib/karafka/web/ui/public/javascripts/live_poll.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

var livePollTimer = null;
var oldDOM = null;
var datePicker = null;

// Check is there is any text selected in the Web-UI
// It drives me crazy when I'm selecting things in Sidekiq Web-UI and the page is refreshed
Expand All @@ -23,6 +24,15 @@ function isAnyTextSelected() {
return(text != "");
}

// We should not poll and update if we have any text selected and we should not do it as well, when
// datetime picker with time selection is present
function isPollingPossible(){
if (isAnyTextSelected()) { return false }
if (isOffsetLookupCalendarVisible()) { return false }

return true
}

function bindPollingButtonClick() {
var selector = document.getElementById("live-poll");

Expand Down Expand Up @@ -113,7 +123,7 @@ function livePollCallback() {
clearTimeout(livePollTimer);
livePollTimer = null;

if (isAnyTextSelected()) {
if (!isPollingPossible()) {
setPollingListener();
return;
}
Expand Down
74 changes: 74 additions & 0 deletions lib/karafka/web/ui/public/javascripts/offset_datetime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// JS code for calendar that allows us to select moment in time for which we should find
// the offset via our closest url

offsetLookupDatePicker = null;

function loadOffsetLookupDatePicker() {
let options = {
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: true,
onSelect: ({ date, datepicker, formattedDate }) => {
// Make sure that date-time selection does not fill the picker button value
// we want to preserve this
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(dp) {
return 'Go to offset'
},
onClick(dp) {
let viewDate = dp.selectedDates[0] || new Date;
let target = dp.$el.dataset.target
dp.hide()
location.href = target + '/' + formatRedirectDateTime(viewDate)
}
}
]
};

// do not leak calendars between reloads
if (offsetLookupDatePicker != undefined) { offsetLookupDatePicker.destroy() }

if (document.getElementById('offset-lookup-datepicker') == null) { return }

offsetLookupDatePicker = new AirDatepicker('#offset-lookup-datepicker', options);

offsetLookupDatePicker.maxDate = new Date
offsetLookupDatePicker.selectDate(new Date().getTime())
}

function formatRedirectDateTime(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // Month is 0-based
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');

return `${year}-${month}-${day}/${hour}:${minute}`;
}

// Informs if calendar is open. We do not refresh UI if it is open
function isOffsetLookupCalendarVisible() {
if (offsetLookupDatePicker == undefined) { return false }

return offsetLookupDatePicker.visible
}
12 changes: 12 additions & 0 deletions lib/karafka/web/ui/public/stylesheets/datepicker.min.css

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/karafka/web/ui/views/shared/_header.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<link href="<%= asset_path('stylesheets/bootstrap.min.css') %>" rel="stylesheet">
<link href="<%= asset_path('stylesheets/highlight.min.css') %>" rel="stylesheet">
<link href="<%= asset_path('stylesheets/datepicker.min.css') %>" rel="stylesheet">
<link href="<%= asset_path('stylesheets/application.css') %>" rel="stylesheet">

<script type="module" src="<%= asset_path('javascripts/chart.min.js') %>"></script>
Expand All @@ -17,6 +18,8 @@
<script type="text/javascript" src="<%= asset_path('javascripts/live_poll.js') %>"></script>
<script type="text/javascript" src="<%= asset_path('javascripts/tabs.js') %>"></script>
<script type="text/javascript" src="<%= asset_path('javascripts/charts.js') %>"></script>
<script type="text/javascript" src="<%= asset_path('javascripts/datepicker.js') %>"></script>
<script type="text/javascript" src="<%= asset_path('javascripts/offset_datetime.js') %>"></script>
<script type="text/javascript" src="<%= asset_path('javascripts/application.js') %>"></script>

<link rel="icon" href="<%= asset_path('images/favicon.ico') %>">
Expand Down

0 comments on commit 073d73a

Please sign in to comment.