Skip to content

Commit 61328f4

Browse files
committed
Add log sidebar
1 parent dea867d commit 61328f4

File tree

11 files changed

+617
-79
lines changed

11 files changed

+617
-79
lines changed

src/web/Main.re

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ let apply =
6464
~dynamics=true,
6565
)
6666
) {
67-
| _ =>
68-
print_endline("ERROR: Exception during calculate phase");
67+
| exc =>
68+
Printf.printf(
69+
"ERROR: Exception during calculate: %s\n",
70+
Printexc.to_string(exc),
71+
);
6972
{
7073
...model,
7174
replay_toggle: false,
@@ -180,6 +183,8 @@ let start = {
180183
JsUtil.focus_clipboard_shim();
181184
/* Setup scroll listener for floating elements (backpack) */
182185
FloatingElement.setup_scroll_listener();
186+
// Sync log count from database
187+
Log.sync_count();
183188
schedule_action(
184189
Assistant(AssistantUpdate.ChatAction(FilterLoadingMessages)),
185190
);
@@ -226,13 +231,7 @@ let start = {
226231
let%arr app_model = app_model
227232
and app_inject = app_inject;
228233
try(
229-
History.View.view(
230-
app_model,
231-
~inject=app_inject,
232-
~get_log_and=Log.get_and,
233-
~next_log=
234-
Util.ListUtil.hd_opt(app_model.future_log) |> Option.map(snd),
235-
)
234+
History.View.view(app_model, ~inject=app_inject, ~get_log_and=Log.get_and)
236235
) {
237236
| exc =>
238237
print_endline(

src/web/app/History.re

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,22 +106,21 @@ module Update = {
106106
);
107107
model |> Updated.return_quiet;
108108
| FinishImport(None) =>
109-
print_endline("Log import failed");
109+
LogSidebar.log_error("Log import failed");
110110
model |> Updated.return_quiet;
111111
| FinishImport(Some(data)) =>
112112
let of_data = (data: string): list((float, Page.Update.t)) =>
113113
Export.import_just_log(data)
114114
|> Sexplib.Sexp.of_string
115115
|> Log.Entry.s_of_sexp_opt
116116
|> List.filter_map(x => x);
117-
// |> List.filter(((ts, _action)) => ts > 1757794060000.0);
118117
let actions =
119118
data
120119
|> of_data
121120
|> Log.flatten_imports(~of_data)
122121
|> (
123122
x => {
124-
print_endline(
123+
LogSidebar.log_info(
125124
"Imported log entries: " ++ string_of_int(List.length(x)),
126125
);
127126
x;
@@ -135,15 +134,15 @@ module Update = {
135134
| NextLog =>
136135
switch (model.future_log) {
137136
| [] =>
138-
print_endline("No next log action to perform");
137+
LogSidebar.log_info("No next log action to perform");
139138
model |> Updated.return_quiet;
140139
| [(t, next), ...rest] =>
141-
print_endline(
142-
"Applying next log action: "
143-
++ JsUtil.print_timestamp(t)
144-
++ " :: "
145-
++ Page.Update.show(next),
140+
LogSidebar.log_action(
141+
"Applying next log action",
142+
Some(JsUtil.print_timestamp(t)),
146143
);
144+
// Keep full action expression in console for detailed debugging
145+
print_endline("Full action: " ++ Page.Update.show(next));
147146
try({
148147
let updated =
149148
Page.Update.update(
@@ -171,7 +170,7 @@ module Update = {
171170
};
172171
}) {
173172
| _ =>
174-
print_endline("Failed to apply log action");
173+
LogSidebar.log_error("Failed to apply log action");
175174
Model.{
176175
...model,
177176
future_log:
@@ -185,10 +184,10 @@ module Update = {
185184
};
186185
}
187186
| SkipLog =>
188-
print_endline("Skipping the next log entry");
187+
LogSidebar.log_action("Skipping the next log entry", None);
189188
switch (model.future_log) {
190189
| [] =>
191-
print_endline("No log entry to skip");
190+
LogSidebar.log_info("No log entry to skip");
192191
model |> return_quiet;
193192
| [(_, _), ...rest] =>
194193
{
@@ -198,7 +197,10 @@ module Update = {
198197
|> return_quiet
199198
};
200199
| SkipExercise =>
201-
print_endline("Skipping to the next exercise in the log");
200+
LogSidebar.log_action(
201+
"Skipping to the next exercise in the log",
202+
None,
203+
);
202204
let rec skip_to_next_exercise = (log: list((float, Page.Update.t))) =>
203205
switch (log) {
204206
| [] => []
@@ -217,6 +219,10 @@ module Update = {
217219
replay_toggle: !model.replay_toggle,
218220
}
219221
|> return_quiet
222+
| ClearLog =>
223+
Log.DB.clear_and(() => ());
224+
LogSidebar.log_info("Log cleared");
225+
model |> return_quiet;
220226
}
221227
| action =>
222228
let current =

src/web/app/Log.re

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ module DB = {
2323
openDB(~upgrade, ~error, ~version=1, db_name, db => f(db));
2424
};
2525

26-
let add = (key: string, value: string): unit =>
26+
let add = (key: string, value: string): unit => {
27+
LogCount.increment();
2728
with_db(db =>
2829
Store.add(~key, ~callback=_key => (), kv_store(db), value)
2930
);
31+
};
3032

3133
let get = (key: string, f: option(string) => unit): unit => {
3234
let error = _ => Printf.printf("ERROR: Log.IDBKV.get");
@@ -40,6 +42,7 @@ module DB = {
4042

4143
let clear_and = (callback): unit => {
4244
let error = _ => Printf.printf("ERROR: Log.IDBKV.clear");
45+
LogCount.clear();
4346
with_db(db => Store.clear(~error, ~callback, kv_store(db)));
4447
};
4548
};
@@ -79,27 +82,39 @@ module Entry = {
7982
};
8083
};
8184

85+
let get_and = (f: string => unit): unit =>
86+
DB.get_all(entries => f("(" ++ String.concat(" ", entries) ++ ")"));
87+
88+
let get_count = (f: int => unit): unit =>
89+
DB.get_all(entries => f(List.length(entries)));
90+
91+
// Synchronously get the cached count (may be stale until sync_count is called)
92+
let get_count_sync = (): int => LogCount.get();
93+
94+
// Sync the cached count with the database
95+
let sync_count = (): unit =>
96+
DB.get_all(entries => LogCount.set(List.length(entries)));
97+
8298
let import = (data: string): unit =>
8399
/* Should be fine to fire saves concurrently? */
84-
DB.clear_and(() =>
100+
DB.clear_and(() => {
85101
try(
86102
data
87103
|> Sexplib.Sexp.of_string
88104
|> Entry.s_of_sexp
89105
|> List.iter(Entry.save)
90106
) {
91107
| _ => Printf.printf("Log.Entry.import: Deserialization error")
92-
}
93-
);
108+
};
109+
// Sync count after import completes
110+
sync_count();
111+
});
94112

95113
let update = (action: Page.Update.t, result: Updated.t('a)): unit =>
96114
if (result.logged) {
97115
Entry.save(Entry.mk(action));
98116
};
99117

100-
let get_and = (f: string => unit): unit =>
101-
DB.get_all(entries => f("(" ++ String.concat(" ", entries) ++ ")"));
102-
103118
let to_actions = () => {
104119
print_endline("HELLO??");
105120
let actions = ref([]);

src/web/app/LogCount.re

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* Cached log entry count to avoid async queries on every render */
2+
3+
let count = ref(0);
4+
5+
let get = (): int => count^;
6+
7+
let set = (n: int): unit => {
8+
count := n;
9+
};
10+
11+
let increment = (): unit => {
12+
count := count^ + 1;
13+
};
14+
15+
let clear = (): unit => {
16+
count := 0;
17+
};

src/web/app/Page.re

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Model = {
1717
editors: Editors.Model.t,
1818
explain_this: ExplainThisModel.t,
1919
assistant: AssistantModel.t,
20+
log_sidebar: LogSidebar.Model.t,
2021
selection,
2122
};
2223

@@ -33,11 +34,13 @@ module Store = {
3334
);
3435
let explain_this = ExplainThisModel.Store.load();
3536
let assistant = AssistantModel.Store.load();
37+
let log_sidebar = LogSidebar.Model.init();
3638
{
3739
editors,
3840
globals,
3941
explain_this,
4042
assistant,
43+
log_sidebar,
4144
selection: Editors.Selection.default_selection(editors),
4245
};
4346
};
@@ -632,13 +635,7 @@ module View = {
632635
);
633636
};
634637

635-
let top_bar =
636-
(
637-
~globals,
638-
~inject: Update.t => Ui_effect.t(unit),
639-
~editors,
640-
~next_log: option(Update.t),
641-
) =>
638+
let top_bar = (~globals, ~inject: Update.t => Ui_effect.t(unit), ~editors) =>
642639
div(
643640
~attrs=[Attr.id("top-bar")],
644641
[
@@ -661,37 +658,6 @@ module View = {
661658
),
662659
],
663660
),
664-
]
665-
@ (
666-
next_log
667-
|> Option.map(_ =>
668-
[
669-
Widgets.button(
670-
text("next"),
671-
_ => Ui_effect.Many([inject(Globals(Log(NextLog)))]),
672-
~tooltip="Play next action from imported log",
673-
),
674-
Widgets.button(
675-
text("skip"),
676-
_ => Ui_effect.Many([inject(Globals(Log(SkipLog)))]),
677-
~tooltip="Skip the rest of the imported log",
678-
),
679-
Widgets.button(
680-
text("skip exercise"),
681-
_ => Ui_effect.Many([inject(Globals(Log(SkipExercise)))]),
682-
~tooltip="Skip to the next exercise in the imported log",
683-
),
684-
]
685-
)
686-
|> Option.to_list
687-
|> List.flatten
688-
)
689-
@ [
690-
Widgets.button(
691-
text("play/pause"),
692-
_ => Ui_effect.Many([inject(Globals(Log(ToggleReplay)))]),
693-
~tooltip="Toggle replaying imported log automatically",
694-
),
695661
],
696662
);
697663

@@ -700,19 +666,22 @@ module View = {
700666
~get_log_and: (string => unit) => unit,
701667
~inject: Update.t => Ui_effect.t(unit),
702668
~cursor: Cursor.cursor(Editors.Update.t),
703-
~next_log: option(Update.t),
704669
{
705670
globals,
706671
editors,
707672
explain_this: explainThisModel,
708673
assistant: assistantModel,
674+
log_sidebar,
709675
selection,
710676
} as model: Model.t,
711677
) => {
678+
let log_count = LogCount.get();
712679
let globals = {
713680
...globals,
714681
inject_global: x => inject(Globals(x)),
715682
get_log_and,
683+
get_log_count: _ =>
684+
failwith("get_log_count is deprecated, use Log.get_count_sync"),
716685
export_all: Export.export_all,
717686
};
718687
let bottom_bar = CursorInspector.view(~globals, cursor);
@@ -727,6 +696,8 @@ module View = {
727696
| MakeActive(s) => inject(MakeActive(Scratch(s))),
728697
~explainThisModel,
729698
~assistantModel,
699+
~log_model=log_sidebar,
700+
~log_count,
730701
~editor=Update.get_editor(model),
731702
cursor.info,
732703
);
@@ -778,7 +749,7 @@ module View = {
778749
};
779750

780751
[
781-
top_bar(~globals, ~inject, ~editors, ~next_log),
752+
top_bar(~globals, ~inject, ~editors),
782753
div(
783754
~attrs=[
784755
Attr.id("main"),
@@ -794,17 +765,12 @@ module View = {
794765
};
795766

796767
let view =
797-
(
798-
~get_log_and,
799-
~inject: Update.t => Ui_effect.t(unit),
800-
~next_log: option(Update.t),
801-
model: Model.t,
802-
) => {
768+
(~get_log_and, ~inject: Update.t => Ui_effect.t(unit), model: Model.t) => {
803769
let cursor = Selection.get_cursor_info(~selection=model.selection, model);
804770
div(
805771
~attrs=[Attr.id("page"), ...handlers(~cursor, ~inject, model)],
806772
[FontSpecimen.view, JsUtil.clipboard_shim]
807-
@ main_view(~get_log_and, ~cursor, ~inject, ~next_log, model),
773+
@ main_view(~get_log_and, ~cursor, ~inject, model),
808774
);
809775
};
810776
};

src/web/app/editors/stepper/MissingStep.re

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ module Update = {
116116
cached_result: Some(result),
117117
}),
118118
}
119-
|> Updated.raise_invalid_action
119+
|> Updated.return_quiet(~logged=true)
120120
| (UpdateResult(_), _) => model |> Updated.raise_invalid_action
121121
| (AxiomBoxAction(action), AxiomsOpen(m)) =>
122122
let* updated = AxiomsBox.Update.update(~settings, action, m);

src/web/app/globals/Globals.re

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ module Action = {
5151
| NextLog
5252
| SkipLog
5353
| SkipExercise
54-
| ToggleReplay;
54+
| ToggleReplay
55+
| ClearLog;
5556

5657
[@deriving (show({with_path: false}), sexp, yojson)]
5758
type t =
@@ -86,6 +87,7 @@ module Model = {
8687
convenience to avoid having to pass it around everywhere. Can only
8788
be used in view functions. */
8889
get_log_and: (string => unit) => unit,
90+
get_log_count: (int => unit) => unit,
8991
export_all:
9092
(
9193
~settings: Language.CoreSettings.t,
@@ -112,6 +114,10 @@ module Model = {
112114
failwith(
113115
"Cannot use get_log_and outside of the main view or update functions!",
114116
),
117+
get_log_count: _ =>
118+
failwith(
119+
"Cannot use get_log_count outside of the main view or update functions!",
120+
),
115121
export_all: (~settings as _, ~instructor_mode as _, ~log as _) =>
116122
failwith(
117123
"Cannot use export_all outside of the main view or update functions!",

0 commit comments

Comments
 (0)