Skip to content

Conversation

CJs0800
Copy link
Collaborator

@CJs0800 CJs0800 commented Jun 18, 2025

feature

Description

This PR implements URL synchronization for the exercise index page:

  • Sorting (by category, skill, difficulty) is now reflected in the #sort=... URL fragment.
  • Expanding/collapsing exercise groups updates the #expand=... fragment.
  • Pasting or navigating to a URL with these fragments updates the view automatically.
  • Internal signals (exercise_sort_signal, expand_state) stay in sync with the URL.

This enables sharing direct links to specific filtered or expanded states.


Known issue:
Group expansions from URL fragments (#expand=...) are not applied correctly.

@CJs0800 CJs0800 requested a review from erikmd June 18, 2025 15:25
Copy link
Collaborator

@erikmd erikmd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @CJs0800 ! thanks for preparing this PR.

it is a good start 👍
I didn't test the feature yet: I made a first pass on your code, suggesting some simplifications and asking a few questions.

I'll do another pass soonish

Comment on lines 93 to 102
let encode str =
Re.Pcre.substitute ~rex:(Re.Pcre.regexp ",") ~subst:(fun _ -> "-c") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "&") ~subst:(fun _ -> "-a") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "=") ~subst:(fun _ -> "-e") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-") ~subst:(fun _ -> "--") str)))
let decode str =
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "--") ~subst:(fun _ -> "-") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-e") ~subst:(fun _ -> "=") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-a") ~subst:(fun _ -> "&") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-c") ~subst:(fun _ -> ",") str)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is correct, but it's possible to make it shorter/simpler, by applying these ideas:

  1. locally open the Re.Pcre module : let open Re.Pcre in and replace Re.Pcre.substitute with substitute, Re.Pcre.regexp with regexp;
  2. reduce the need of parentheses by using the @@ operator → FYI, f @@ g @@ h etc = f (g (h etc))

Hence:

Suggested change
let encode str =
Re.Pcre.substitute ~rex:(Re.Pcre.regexp ",") ~subst:(fun _ -> "-c") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "&") ~subst:(fun _ -> "-a") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "=") ~subst:(fun _ -> "-e") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-") ~subst:(fun _ -> "--") str)))
let decode str =
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "--") ~subst:(fun _ -> "-") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-e") ~subst:(fun _ -> "=") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-a") ~subst:(fun _ -> "&") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-c") ~subst:(fun _ -> ",") str)))
let encode str =
let open Re.Pcre in
substitute ~rex:(regexp ",") ~subst:(fun _ -> "-c")
@@ substitute ~rex:(regexp "&") ~subst:(fun _ -> "-a")
@@ substitute ~rex:(regexp "=") ~subst:(fun _ -> "-e")
@@ substitute ~rex:(regexp "-") ~subst:(fun _ -> "--")
@@ str

And likewise for decode !

| By_skill -> "skill"
| By_difficulty -> "difficulty"
in
update_fragment "sort" sort_value;set_exercise_sort sort;true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: add spaces here

Suggested change
update_fragment "sort" sort_value;set_exercise_sort sort;true);
update_fragment "sort" sort_value; set_exercise_sort sort; true);

let (exercise_sort_signal: exercise_ordering React.signal), set_exercise_sort =
React.S.create By_category

let (expand_state: string list React.signal), set_expand_state =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for uniformity, you could add the _signal suffix here as well:

Suggested change
let (expand_state: string list React.signal), set_expand_state =
let (expand_state_signal: string list React.signal), set_expand_state =

Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-a") ~subst:(fun _ -> "&") (
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "-c") ~subst:(fun _ -> ",") str)))

let rec update_expand ?value fragment =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears in your PR, there is no additional (* comments *) while IMO it'd be a good idea to:

  1. Add a small global comment, for example before encode, that briefly explains the feature added in the PR, its design, and the need to add the encode/decode mutual bijections…

  2. Add individual comments of one line or so just before each new function, to explain their usefulness (except if their semantics is trivial, e.g., no need to document the join local function):

    • if the new function at stake is public (it has a val … in the .mli): document the function in the .mli only is OK
    • if the new function at stake is private (only in the .ml): document the function in the .ml

let update_fragment key value =
let fragment = Js_utils.parse_fragment () in
let filtered_fragment =
if (key = "expand") then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
if (key = "expand") then
if key = "expand" then


let update_sort value fragment =
let filtered_fragment = List.remove_assoc "sort" (update_expand fragment) in
filtered_fragment@[("sort",value)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
filtered_fragment@[("sort",value)]
filtered_fragment @ [("sort", value)]

] ]
in
let update_expand_class id ids =
if (List.mem id ids) then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
if (List.mem id ids) then
if List.mem id ids then

| [] -> []
| [_] ->
let expand_ids = React.S.value expand_state in
if (expand_ids = []) then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
if (expand_ids = []) then
if expand_ids = [] then

update_expand_class id expand_ids
| _ ->
let expand_ids = React.S.value expand_state in
if (expand_ids = []) then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
if (expand_ids = []) then
if expand_ids = [] then

Comment on lines +371 to +372
ignore (Manip.toggleClass title "collapsed");
false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This two lines were untouched by your PR except the indentation (spaces),
it might be better to restore the previous indentation so that the diff is not ambiguous (i.e., suggesting that the lines changed, while they didn't)

@erikmd erikmd self-assigned this Sep 7, 2025
@erikmd erikmd added the kind: enhancement Enhancement to an existing user-facing feature. label Sep 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind: enhancement Enhancement to an existing user-facing feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants