Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add display timezone switcher, remove local timezone toggle #2092

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions assets/js/LogEventsChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,10 @@ const LogEventsChart = ({
loading,
chart_data_shape_id: chartDataShapeId,
chart_period: chartPeriod,
use_local_time: useLocalTime,
user_local_timezone: userTz,
display_timezone: userTz,
pushEvent,
}) => {
const tz = useLocalTime ? userTz : "Etc/UTC";
const tz = userTz
const onClick = (event) => {
pushEvent("soft_pause", {});
const utcDatetime = event.data.datetime;
Expand Down
3 changes: 1 addition & 2 deletions lib/logflare/logs/search/logs_search_operation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ defmodule Logflare.Logs.SearchOperation do
field :chart_rules, [ChartRule.t()], default: []
field :error, term()
field :stats, :map
field :use_local_time, boolean
field :user_local_timezone, String.t()
field :search_timezone, String.t()
field :chart_data_shape_id, atom(), default: nil, enforce: true
field :type, :events | :aggregates
field :status, {atom(), String.t() | [String.t()]}
Expand Down
45 changes: 18 additions & 27 deletions lib/logflare/logs/search/logs_search_operations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -334,30 +334,26 @@ defmodule Logflare.Logs.SearchOperations do
@spec apply_local_timestamp_correction(SO.t()) :: SO.t()
def apply_local_timestamp_correction(%SO{} = so) do
lql_ts_filters =
if so.use_local_time do
so.lql_ts_filters
|> Enum.map(fn
%{path: "timestamp", values: values, operator: :range} = pvo ->
values =
for value <- values do
value
|> Timex.to_datetime(so.user_local_timezone || "Etc/UTC")
|> Timex.Timezone.convert("Etc/UTC")
end

%{pvo | values: values}

%{path: "timestamp", value: value} = pvo ->
value =
so.lql_ts_filters
|> Enum.map(fn
%{path: "timestamp", values: values, operator: :range} = pvo ->
values =
for value <- values do
value
|> Timex.to_datetime(so.user_local_timezone || "Etc/UTC")
|> Timex.to_datetime(so.search_timezone || "Etc/UTC")
|> Timex.Timezone.convert("Etc/UTC")
end

%{pvo | value: value}
end)
else
so.lql_ts_filters
end
%{pvo | values: values}

%{path: "timestamp", value: value} = pvo ->
value =
value
|> Timex.to_datetime(so.search_timezone || "Etc/UTC")
|> Timex.Timezone.convert("Etc/UTC")

%{pvo | value: value}
end)

%{so | lql_ts_filters: lql_ts_filters}
end
Expand All @@ -372,12 +368,7 @@ defmodule Logflare.Logs.SearchOperations do
|> Lql.EctoHelpers.apply_filter_rules_to_query(so.lql_meta_and_msg_filters)
|> order_by([t, ...], desc: 1)

query =
if chart_period == :day and so.use_local_time and so.user_local_timezone do
select_timestamp(query, chart_period, so.user_local_timezone)
else
select_timestamp(query, chart_period)
end
query = select_timestamp(query, chart_period)

query =
case chart_rules do
Expand Down
2 changes: 1 addition & 1 deletion lib/logflare/utils/datetime_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ defmodule Logflare.DateTimeUtils do

minutes = "#{minutes_prefix}#{minutes}"

"(#{hours}:#{minutes})"
"#{hours}:#{minutes}"
end
end
95 changes: 41 additions & 54 deletions lib/logflare_web/live/search_live/logs_search_lv.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ defmodule LogflareWeb.Source.SearchLV do
user: user,
team_user: team_user,
search_tip: gen_search_tip(),
user_local_timezone: Map.get(params, "tz", "Etc/UTC"),
user_timezone_from_connect_params: nil,
use_local_time: true,
display_timezone: Map.get(params, "tz", "Etc/UTC"),
search_timezone: Map.get(params, "tz", "Etc/UTC"),
# loading states
loading: true,
chart_loading: true,
Expand Down Expand Up @@ -173,6 +173,10 @@ defmodule LogflareWeb.Source.SearchLV do
logs_search(assigns)
end

def handle_event("results-action-change", %{"display_timezone" => tz}, socket) do
{:noreply, socket |> assign(:display_timezone, tz)}
end

def handle_event(
"start_search" = ev,
%{"search" => %{"querystring" => qs}},
Expand Down Expand Up @@ -214,28 +218,23 @@ defmodule LogflareWeb.Source.SearchLV do

{:noreply, socket}
else
tz = Timex.Timezone.get(socket.assigns.search_timezone)

timestamp_rules =
if socket.assigns.use_local_time do
user_local_timezone = socket.assigns.user_local_timezone
tz = Timex.Timezone.get(user_local_timezone)

Enum.map(timestamp_rules, fn
lql_rule ->
if Lql.Utils.timestamp_filter_rule_is_shorthand?(lql_rule) do
Map.replace!(
lql_rule,
:values,
for value <- lql_rule.values do
Timex.shift(value, seconds: Timex.diff(value, tz))
end
)
else
lql_rule
end
end)
else
timestamp_rules
end
Enum.map(timestamp_rules, fn
lql_rule ->
if Lql.Utils.timestamp_filter_rule_is_shorthand?(lql_rule) do
Map.replace!(
lql_rule,
:values,
for value <- lql_rule.values do
Timex.shift(value, seconds: Timex.diff(value, tz))
end
)
else
lql_rule
end
end)

rules = Lql.Utils.update_timestamp_rules(rules, timestamp_rules)
new_rules = Lql.Utils.jump_timestamp(rules, String.to_atom(direction))
Expand Down Expand Up @@ -357,22 +356,6 @@ defmodule LogflareWeb.Source.SearchLV do
{:noreply, socket}
end

def handle_event("toggle_local_time", _metadata, socket) do
source = socket.assigns.source
maybe_cancel_tailing_timer(socket)
SearchQueryExecutor.maybe_cancel_query(source.token)

socket =
socket
|> assign(:use_local_time, not socket.assigns.use_local_time)
|> assign_new_search_with_qs(
%{querystring: socket.assigns.querystring, tailing?: socket.assigns.tailing?},
socket.assigns.source.bq_table_schema
)

{:noreply, socket}
end

def handle_event("save_search" = ev, _, socket) do
%{
source: source,
Expand Down Expand Up @@ -429,18 +412,15 @@ defmodule LogflareWeb.Source.SearchLV do
def handle_info({:search_result, %{aggregates: _aggs} = search_result}, socket) do
log_lv_received_event("search_result", socket.assigns.source)

timezone =
if socket.assigns.use_local_time do
socket.assigns.user_local_timezone
else
"Etc/UTC"
end

log_aggregates =
search_result.aggregates.rows
|> Enum.reverse()
|> Enum.map(fn la ->
Map.update!(la, "timestamp", &BqSchemaHelpers.format_timestamp(&1, timezone))
Map.update!(
la,
"timestamp",
&BqSchemaHelpers.format_timestamp(&1, socket.assigns.display_timezone)
)
end)

aggs =
Expand Down Expand Up @@ -604,44 +584,51 @@ defmodule LogflareWeb.Source.SearchLV do
cond do
tz_param != nil ->
socket
|> assign(:user_local_timezone, tz_param)
|> assign(:search_timezone, tz_param)
|> assign(:display_timezone, tz_param)

team_user && team_user.preferences ->
assign(socket, :user_local_timezone, team_user.preferences.timezone)
socket
|> assign(:search_timezone, team_user.preferences.timezone)
|> assign(:display_timezone, team_user.preferences.timezone)

team_user && is_nil(team_user.preferences) ->
{:ok, team_user} =
Users.update_user_with_preferences(team_user, %{preferences: %{timezone: tz_connect}})

socket
|> assign(:team_user, team_user)
|> assign(:user_local_timezone, tz_connect)
|> assign(:search_timezone, tz_connect)
|> assign(:display_timezone, tz_connect)
|> put_flash(
:info,
"Your timezone setting for team #{team_user.team.name} sources was set to #{tz_connect}. You can change it using the 'timezone' link in the top menu."
)

user.preferences ->
assign(socket, :user_local_timezone, user.preferences.timezone)
socket
|> assign(:search_timezone, user.preferences.timezone)
|> assign(:display_timezone, user.preferences.timezone)

is_nil(user.preferences) ->
{:ok, user} =
Users.update_user_with_preferences(user, %{preferences: %{timezone: tz_connect}})

socket
|> assign(:user_local_timezone, tz_connect)
|> assign(:search_timezone, tz_connect)
|> assign(:display_timezone, tz_connect)
|> assign(:user, user)
|> put_flash(
:info,
"Your timezone was set to #{tz_connect}. You can change it using the 'timezone' link in the top menu."
)
end
|> then(fn
%{assigns: %{uri_params: %{"tz" => tz}, user_local_timezone: local_tz}} = socket
%{assigns: %{uri_params: %{"tz" => tz}, search_timezone: local_tz}} = socket
when tz != local_tz ->
push_patch_with_params(socket, %{"tz" => local_tz})

%{assigns: %{uri_params: params, user_local_timezone: local_tz}} = socket
%{assigns: %{uri_params: params, search_timezone: local_tz}} = socket
when not is_map_key(params, "tz") and local_tz != "Etc/UTC" ->
push_patch_with_params(socket, %{"tz" => local_tz})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
<!-- TODO: TO BE DELETED WHEN UNDERLYING ISSUE IS FOUND -->
<% %{"timestamp" => timestamp, "event_message" => message} = log.body

formatted_timestamp =
if @use_local_time do
format_timestamp(timestamp, @user_local_timezone)
else
format_timestamp(timestamp) <> " UTC"
end %>
tz_part = DateTimeUtils.humanize_timezone_offset(Timex.Timezone.get(@display_timezone).offset_utc)
formatted_timestamp = format_timestamp(timestamp, @display_timezone) <> "#{tz_part}" %>
<li id={"log-event_#{log.id || log.body["timestamp"]}"} class="tw-group">
<span class="tw-whitespace-pre-wrap"><mark class="log-datestamp" data-timestamp={timestamp}><%= formatted_timestamp %></mark>&nbsp;<%= message %></span>
<span class="tw-inline-block tw-text-[0.65rem] tw-align-text-bottom tw-inline-flex tw-flex-row tw-gap-2">
Expand Down
49 changes: 24 additions & 25 deletions lib/logflare_web/live/search_live/templates/logs_search.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
return_to: @modal.body.return_to
) %>
<% end %>
<div id="user-preferences" data-user-local-timezone={@user_local_timezone} data-use-local-time={@use_local_time}></div>
<div id="source-logs-search-control" class="subhead " phx-hook="SourceLogsSearch">
<div class="container mx-auto">
<h5>
Expand All @@ -38,25 +37,10 @@
<%= LqlHelpers.bq_source_schema_modal_link() %>
</li>
<li>
<a href="#" phx-click="toggle_local_time" id="toggle_local_time" phx-value-use_local_time={@use_local_time}>
<span>
<%= if @use_local_time do %>
<i class="fa fa-toggle-on pointer-cursor" aria-hidden="true"></i>
<% else %>
<i class="fa fa-toggle-off pointer-cursor" aria-hidden="true"></i>
<% end %>
</span>
<span class="hide-on-mobile">local time</span>
</a>
</li>
<li>
<%= live_modal_show_link(component: Search.UserPreferencesComponent, modal_id: :user_preferences, title: "Preferences", return_to: @uri.path <> "?querystring=c:count(*) c:group_by(t::minute)") do %>
<%= live_modal_show_link(component: Search.UserPreferencesComponent, modal_id: :user_preferences, title: "Preferences", return_to: @uri.path <> "?" <> (@uri.query || "")) do %>
<i class="fas fa-globe"></i>
<span class="hide-on-mobile">
timezone
<%= if @user_local_timezone do %>
<%= DateTimeUtils.humanize_timezone_offset(Timex.Timezone.get(@user_local_timezone).offset_utc) %>
<% end %>
timezone <%= DateTimeUtils.humanize_timezone_offset(Timex.Timezone.get(@search_timezone).offset_utc) %>
</span>
<% end %>
</li>
Expand Down Expand Up @@ -90,15 +74,31 @@
<% end %>
</ul>
</div>
<div>
<ul>
<li>
<.form :let={f} for={%{}} phx-change="results-action-change" id="results-actions">
<label class="sr-only" for="display_timezone">Display Timezone</label>
<div class="input-group input-group-sm">
<div class="input-group-prepend">
<div class="input-group-text tw-bg-transparent tw-text-black tw-text-xs">display timezone</div>
</div>
<%= select(f, :display_timezone, LogflareWeb.Search.UserPreferencesComponent.build_timezones_select_form_options(), selected: @display_timezone, class: "form-control form-control-sm tw-w-64 tw-text-xs") %>
<button type="button" class="btn btn-link tw-text-xs" phx-click="results-action-change" phx-value-display_timezone="Etc/UTC">UTC</button>
</div>
</.form>
</li>
</ul>
</div>
</div>
</div>
<div class="container source-logs-search-container console-text">
<div id="logs-list-container">
<%= Phoenix.View.render(SearchView, "logs_list.html",
search_op_log_events: @search_op_log_events,
last_query_completed_at: @last_query_completed_at,
user_local_timezone: @user_local_timezone,
use_local_time: @use_local_time,
search_timezone: @search_timezone,
display_timezone: @display_timezone,
loading: @loading,
source: @source
) %>
Expand All @@ -110,8 +110,7 @@
data: if(@search_op_log_aggregates, do: @search_op_log_aggregates.rows, else: []),
loading: @chart_loading,
chart_period: get_chart_period(@lql_rules, "minute"),
user_local_timezone: @user_local_timezone,
use_local_time: @use_local_time,
display_timezone: @display_timezone,
chart_data_shape_id:
if(@search_op_log_aggregates,
do: @search_op_log_aggregates.chart_data_shape_id,
Expand All @@ -131,10 +130,10 @@
class: "form-control form-control-margin",
list: "matches"
) %>
<%= text_input(f, :user_local_timezone,
<%= text_input(f, :search_timezone,
class: "d-none",
value: @user_local_timezone,
id: "user-local-timezone"
value: @search_timezone,
id: "search-timezone"
) %>
<datalist id="matches">
<%= for s <- @search_history do %>
Expand Down
Loading