Skip to content

Commit c141309

Browse files
committed
save and load config from local storage
1 parent 558124d commit c141309

7 files changed

Lines changed: 83 additions & 23 deletions

File tree

apps/dashboard/assets/css/custom.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ body {
6969
position: relative;
7070
top: -4px;
7171
padding-right: 2px;
72+
cursor: pointer;
7273
}
7374

7475
.mysql-label {

apps/dashboard/assets/css/live_view.scss

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55
display: block;
66
}
77

8-
.phx-no-feedback.invalid-feedback, .phx-no-feedback .invalid-feedback {
9-
display: none;
10-
}
8+
/*
9+
Any DOM container with the phx-feedback-for attribute will receive a phx-no-feedback class in cases where the
10+
form fields has yet to receive user input/focus, in such cases we hide the error.
11+
12+
In our case if still show the errors always
13+
*/
14+
// .phx-no-feedback.invalid-feedback, .phx-no-feedback .invalid-feedback {
15+
// display: none;
16+
// }
1117

1218
.phx-click-loading {
1319
opacity: 0.5;

apps/dashboard/assets/js/app.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,27 @@ let hooks = {
1313
// Initialize bootstrap tooltips
1414
// Ref: https://getbootstrap.com/docs/5.2/components/tooltips/#enable-tooltips
1515
new bootstrap.Tooltip(this.el);
16+
17+
this.handleEvent("save-config", ({ config }) => {
18+
console.log("write to local", JSON.stringify(config))
19+
localStorage.setItem("config", JSON.stringify(config))
20+
}
21+
)
1622
}
1723
}
1824
};
1925

20-
let liveSocket = new LiveSocket("/live", Socket, { hooks, params: { _csrf_token: csrfToken } });
26+
let liveSocket = new LiveSocket(
27+
"/live",
28+
Socket,
29+
{
30+
hooks,
31+
params: {
32+
_csrf_token: csrfToken,
33+
localConfig: (JSON.parse(localStorage.getItem('config') || '{}'))
34+
}
35+
});
36+
2137
liveSocket.connect();
2238
window.liveSocket = liveSocket;
2339

@@ -35,6 +51,6 @@ window.addEventListener(
3551
"phx:scroll-into-view",
3652
e => {
3753
const element = document.getElementById(e.detail.id);
38-
element.scrollIntoView({behavior: "smooth", block: "nearest"});
54+
element.scrollIntoView({ behavior: "smooth", block: "nearest" });
3955
}
4056
)

apps/dashboard/lib/dashboard/config.ex

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# This is required so that changesets can be serialized and stored in browser local storage
2+
# We are using only changes on a changeset
3+
defimpl Jason.Encoder, for: Ecto.Changeset do
4+
def encode(changeset, opts) do
5+
Jason.Encode.map(changeset.changes, opts)
6+
end
7+
end
8+
19
defmodule DashBoard.Config do
210
use Ecto.Schema
311
import Ecto.Changeset
@@ -37,20 +45,41 @@ defmodule DashBoard.Config do
3745
embeds_many(:date_time_patterns, DashBoard.DateTimePattern, on_replace: :delete)
3846
end
3947

40-
def changeset(params) do
48+
def get_defaults do
49+
%__MODULE__{
50+
db_type: :mysql,
51+
db_worker_count: 10,
52+
drop_existing_tables: false,
53+
insert_data: true,
54+
insert_schema: true,
55+
insertion_chunk_size: 100,
56+
log: false,
57+
ordered: false,
58+
parse_datetime: true,
59+
remove_illegal_characters: false,
60+
schema_infer_chunk_size: 100,
61+
varchar_limit: 200,
62+
worker_count: System.schedulers_online()
63+
}
64+
end
65+
66+
def changeset(params), do: changeset(%__MODULE__{}, params)
67+
68+
def changeset(%__MODULE__{} = config, params) do
4169
attrs_to_cast =
4270
:fields
4371
|> __MODULE__.__schema__()
72+
# Reject nested attributes from cast, they will be loaded via cast_embed/2
4473
|> Enum.reject(fn
4574
field when field in ~w[db_attrs date_patterns date_time_patterns]a -> true
4675
_field -> false
4776
end)
4877

4978
changeset =
50-
%__MODULE__{}
79+
config
5180
|> cast(params, attrs_to_cast)
5281
|> validate_source_directory()
53-
|> validate_path(:schema_path)
82+
|> validate_path(:schema_path, true)
5483
|> cast_embed(:db_attrs)
5584
|> cast_embed(:date_patterns)
5685
|> cast_embed(:date_time_patterns)
@@ -65,14 +94,19 @@ defmodule DashBoard.Config do
6594
|> add_csv_count()
6695
end
6796

68-
defp validate_path(changeset, field) do
69-
changeset
70-
|> get_change(field, "")
71-
|> File.dir?()
72-
|> if(
73-
do: changeset,
74-
else: add_error(changeset, field, "Invalid path, enter a path to a valid directory")
75-
)
97+
defp validate_path(changeset, field, allow_blank \\ false) do
98+
value = get_change(changeset, field, "")
99+
100+
if allow_blank && value == "" do
101+
changeset
102+
else
103+
value
104+
|> File.dir?()
105+
|> if(
106+
do: changeset,
107+
else: add_error(changeset, field, "Invalid path, enter a path to a valid directory")
108+
)
109+
end
76110
end
77111

78112
defp add_csv_count(%Ecto.Changeset{valid?: true} = changeset) do

apps/dashboard/lib/dashboard_web/live/config_live.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,12 @@ defmodule DashboardWeb.Live.ConfigLive do
278278
279279
<%= if @modal != "add-date-time-patterns" do %>
280280
<%= inputs_for f, :date_time_patterns, fn assoc_form -> %>
281-
<%= hidden_input(assoc_form, :id) %>w
281+
<%= hidden_input(assoc_form, :id) %>
282282
<%= hidden_input(assoc_form, :pattern) %>
283283
<% end %>
284284
285285
<%= inputs_for f, :date_patterns, fn assoc_form -> %>
286-
<%= hidden_input(assoc_form, :id) %>w
286+
<%= hidden_input(assoc_form, :id) %>
287287
<%= hidden_input(assoc_form, :pattern) %>
288288
<% end %>
289289
<% end %>

apps/dashboard/lib/dashboard_web/live/main_live.ex

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@ defmodule DashboardWeb.Live.MainLive do
88

99
@impl true
1010
def mount(_params, _session, socket) do
11+
localstorage_config = (get_connect_params(socket) || %{}) |> Map.get("localConfig", %{})
12+
# Check for DB connection on config load from local storage
13+
timer_ref = Process.send_after(self(), :check_db_connection, @debounce_time)
14+
1115
{:ok,
1216
assign(socket,
1317
page: "config",
1418
modal: false,
1519
path_validator_debouncer: nil,
16-
db_connection_debouncer: nil,
20+
db_connection_debouncer: timer_ref,
1721
db_connection_established: false,
18-
changeset: Ecto.Changeset.change(%DashBoard.Config{}),
22+
changeset: Config.get_defaults() |> Config.changeset(localstorage_config),
1923
matching_date_time: nil
2024
)}
2125
end
@@ -50,7 +54,7 @@ defmodule DashboardWeb.Live.MainLive do
5054
|> db_connection_checker(args)
5155
|> update_matching_date_time(attrs)
5256

53-
{:noreply, socket}
57+
{:noreply, socket |> push_event("save-config", %{config: socket.assigns.changeset})}
5458
end
5559

5660
@impl true
@@ -172,7 +176,6 @@ defmodule DashboardWeb.Live.MainLive do
172176

173177
case match_date_time(assigns.changeset, date_time_sample) do
174178
{type, index} ->
175-
176179
socket
177180
|> assign(matching_date_time: {type, index})
178181
|> push_event("scroll-into-view", %{

apps/dashboard/lib/dashboard_web/live/ui.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ defmodule DashboardWeb.Live.UI do
113113
"""
114114
end
115115

116-
@doc """
116+
@doc """
117117
Generates tag for inlined form input errors.
118118
"""
119119
def error_tag(form, field) do

0 commit comments

Comments
 (0)