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

Use hx-preserve with table checkboxes #148

Merged
merged 14 commits into from
Oct 16, 2024
Merged

Use hx-preserve with table checkboxes #148

merged 14 commits into from
Oct 16, 2024

Conversation

cc-a
Copy link
Contributor

@cc-a cc-a commented Oct 11, 2024

Description

This PR exempts the table checkboxes from being updated by HTMX requests. The main benefits:

  • removes issues with flickering checkboxes
  • allows removal of all server side handling of checkbox state

It does add the need to handle the header checkbox state to the client side but this is handled with a simple hyperscript snippet. For consistency I've also replaced the vanilla javascript with hyperscript to set row checkboxes when the header is clicked.

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature (non-breaking change which adds functionality)
  • Optimization (non-breaking, back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Key checklist

  • All tests pass (eg. python -m pytest)
  • The documentation builds and looks OK (eg. python -m sphinx -b html docs docs/build)
  • Pre-commit hooks run successfully (eg. pre-commit run --all-files)

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added or an issue has been opened to tackle that in the future. (Indicate issue here: # (issue))

@codecov-commenter
Copy link

codecov-commenter commented Oct 11, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 80.55%. Comparing base (9790d73) to head (939dae2).
Report is 15 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #148      +/-   ##
==========================================
+ Coverage   79.54%   80.55%   +1.01%     
==========================================
  Files          26       26              
  Lines         308      324      +16     
==========================================
+ Hits          245      261      +16     
  Misses         63       63              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@dalonsoa dalonsoa left a comment

Choose a reason for hiding this comment

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

It looks ok and it works, so approving. Having said that, I've lots of questions.

)

def render_select(self, value: str) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's value here? Is the uuid of the column? Whatever it is, maybe add it to the docstring.

Also, I'm not sure when this method is called, or by whom.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks good catch. I wish there was a way to get automatic checks for this but I've never been able to find one.

It's called during table rendering. It's detected by class magicness and called in place of the render method of the column.

Copy link
Contributor

Choose a reason for hiding this comment

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

mkdocs gives warnings about malformed docstrings (=errors if you pass --strict), but I don't know if it warns about missing args. Were we going to add API documentation at some point?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Planning to add it for next sprint.

"th__input": {
"id": "header-checkbox",
"hx-preserve": "true",
"_": header_checkbox_hyperscript,
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does this underscore represent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is the html attribute that hyperscript uses to store its scripts on individual elements.

@@ -1,4 +1,4 @@
{% load render_table from django_tables2 %}
<div hx-post="{% url 'process_manager:process_table' %}"
hx-trigger="load delay:1s, click from:input"
<div hx-get="{% url 'process_manager:process_table' %}"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it get now because we are no longer sending data (the selected rows) to the backend?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right.

Comment on lines 34 to 35
if <input.row-checkbox:not(:checked)/> is empty
set #header-checkbox.checked to true
Copy link
Collaborator

Choose a reason for hiding this comment

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

In plain(er) English, this means that if the list of rows that are not checked is empty, then the header checkbox should be checked - as all the rows are checked - right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct.

@cc-a
Copy link
Contributor Author

cc-a commented Oct 15, 2024

This has been up for a little while now so I'll merge by the end of the day unless anyone else has any feedback/questions.

Copy link
Contributor

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

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

LGTM insofar as I understand it 😉

)

def render_select(self, value: str) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

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

mkdocs gives warnings about malformed docstrings (=errors if you pass --strict), but I don't know if it warns about missing args. Were we going to add API documentation at some point?

tests/process_manager/views/test_partial_views.py Outdated Show resolved Hide resolved
Copy link
Contributor

@jamesturner246 jamesturner246 left a comment

Choose a reason for hiding this comment

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

Looks good. Just questions.

Args:
value: uuid from the table row data
"""
return mark_safe(
Copy link
Contributor

Choose a reason for hiding this comment

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

So render_select is magically called when rendering self.select = tables.CheckBoxCol..., and creates a custom id for the row checkbox, so that hx-preserve can preserve each row cbox on refresh.

What is mark_safe doing here exactly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

https://docs.djangoproject.com/en/5.1/ref/utils/#django.utils.safestring.mark_safe It tells the Django templating system that the html generated is safe and isn't vurnerable to injection attacks so it can just be rendered directly. Otherwise the templating system by default will try to escape everything.

process_manager/tables.py Outdated Show resolved Hide resolved
@cc-a cc-a enabled auto-merge October 16, 2024 11:07
@cc-a cc-a merged commit 90ab208 into main Oct 16, 2024
4 checks passed
@cc-a cc-a deleted the preserve-checkboxes branch October 16, 2024 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants