Skip to content

feat: implement inline-editable fields and star rating widget#25

Merged
PascalRepond merged 1 commit intostagingfrom
rep-dev
Dec 28, 2025
Merged

feat: implement inline-editable fields and star rating widget#25
PascalRepond merged 1 commit intostagingfrom
rep-dev

Conversation

@PascalRepond
Copy link
Copy Markdown
Owner

  • Added inline-editable fields for review date, review text, score, and status in media item templates.
  • Created a star rating widget for user reviews.
  • Removed obsolete score-edit and score-readonly partials, replacing them with score-editable.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 28, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a star rating widget component and implements HTMX-based inline editing for media attributes. It adds four new views that handle score, status, review, and review-date updates, replaces static display elements with editable partials, and removes deprecated templates.

Changes

Cohort / File(s) Summary
Star Rating Widget
src/core/forms.py, src/core/templates/widgets/star_rating.html, src/theme/static_src/src/styles.css
Introduced StarRatingWidget class that renders a custom star rating input using "widgets/star_rating.html" template. Injected score_choices into template context. Added CSS for star button hover/active states. Replaced MediaForm.Meta.widgets["score"] with new widget.
HTMX Inline Edit Views
src/core/views.py
Added four new view functions with login_required decorator: media_update_score_htmx, media_update_status_htmx, media_update_review_htmx, media_update_review_date_htmx. Each validates input against model field choices and returns updated partial template.
URL Routing
src/core/urls.py
Added four new URL patterns mapping to HTMX views: media/<int:pk>/update-score/, media/<int:pk>/update-status/, media/<int:pk>/update-review/, media/<int:pk>/update-review-date/.
Editable Partial Templates
src/templates/partials/score-editable.html, src/templates/partials/status-editable.html, src/templates/partials/review-editable.html, src/templates/partials/review-date-editable.html
Created four new interactive partials with display/edit mode toggles. Each integrates HTMX POST handlers, client-side JavaScript for mode switching and interactions, and Django i18n translations. Templates coordinate with corresponding backend views.
Updated Media Grid/Table Display
src/templates/partials/media-items.html
Replaced static score, status, review, and review-date displays in both grid and table views with corresponding editable partial includes. Removed references to deprecated readonly/edit templates.
Removed Templates
src/templates/partials/score-edit.html, src/templates/partials/score-readonly.html
Deleted deprecated score editing template (radio input variant) and readonly score display template (static star UI). Replaced by unified score-editable.html partial.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant MediaView as HTMX View
    participant Form as Form/Validation
    participant DB as Database
    participant PartialTemplate as Partial Template

    User->>Browser: Click edit or change value in partial
    Browser->>MediaView: POST request with new value<br/>(e.g., media_update_score_htmx)
    activate MediaView
    MediaView->>Form: Validate input against<br/>field choices
    alt Validation Success
        Form-->>MediaView: Valid data
        MediaView->>DB: Update media object
        DB-->>MediaView: Object saved
    else Validation Fails
        Form-->>MediaView: Invalid data
        MediaView-->>PartialTemplate: Render with error
    end
    MediaView->>PartialTemplate: Render updated partial<br/>with new value
    PartialTemplate-->>Browser: Return updated HTML
    deactivate MediaView
    Browser->>Browser: HTMX swaps outerHTML
    User->>User: Sees updated display/edit state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: introducing inline-editable fields and a star rating widget across the codebase.
Description check ✅ Passed The description is directly related to the changeset, covering the key additions (inline-editable fields, star rating widget) and removals (obsolete partials).
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rep-dev

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
src/core/templates/widgets/star_rating.html (2)

39-42: Consider simplifying the value comparison.

The nested loop with stringformat filter to find the matching label could be simplified. Since widget.value and score are both integers, you can compare them directly:

-    {% for score, label in score_choices %}
-      {% if widget.value|stringformat:"s" == score|stringformat:"s" %}{{ label }}{% endif %}
-    {% endfor %}
+    {% for score, label in score_choices %}
+      {% if widget.value == score %}{{ label }}{% endif %}
+    {% endfor %}

47-54: Add defensive checks for missing DOM elements.

The script assumes all DOM elements exist. If the template structure changes or the widget fails to render properly, accessing properties on null elements will throw uncaught errors.

🔎 Suggested defensive initialization
 (function() {
   // Initialize star rating for this widget instance
   const widgetName = "{{ widget.name }}";
   const ratingContainer = document.querySelector(`.rating[data-widget-name="${widgetName}"]`);
+  if (!ratingContainer) return;
+
   const hiddenInput = document.getElementById(`id_${widgetName}`);
   const labelDisplay = document.querySelector(`.star-label[data-widget-name="${widgetName}"]`);
   const clearBtn = document.querySelector(`.star-clear-btn[data-widget-name="${widgetName}"]`);
+  if (!hiddenInput || !labelDisplay || !clearBtn) return;
+
   const stars = ratingContainer.querySelectorAll('.star-btn');
src/templates/partials/status-editable.html (1)

21-36: Consider adding escape-to-cancel functionality.

The widget switches to edit mode on click but doesn't provide a way to cancel editing without making a change. Users may accidentally click and then want to dismiss the edit mode without selecting a different status.

Consider adding an escape key handler or blur event to restore display mode, similar to the pattern used in review-date-editable.html (lines 48-56).

🔎 Suggested enhancement
   // Show edit mode on click
   display.addEventListener('click', function() {
     display.classList.add('hidden');
     edit.classList.remove('hidden');
     select.focus();
   });
+
+  // Cancel editing on escape or blur
+  select.addEventListener('keydown', function(event) {
+    if (event.key === 'Escape') {
+      edit.classList.add('hidden');
+      display.classList.remove('hidden');
+    }
+  });
+
+  select.addEventListener('blur', function() {
+    // Delay to allow HTMX change to process first
+    setTimeout(() => {
+      if (edit && !edit.classList.contains('hidden')) {
+        edit.classList.add('hidden');
+        display.classList.remove('hidden');
+      }
+    }, 300);
+  });
 })();
src/templates/partials/score-editable.html (2)

6-15: Consider reducing repetition in star button attributes.

Each of the 10 star buttons shares identical hx-post, hx-target, and hx-swap attributes, with only data-score, data-label, hx-vals, and the conditional aria-current differing. While functional, this repetition makes the template harder to maintain.

Possible approaches to reduce repetition
  1. Use a template loop with a list of score/label pairs
  2. Move the common HTMX attributes to the container and use event delegation
  3. Accept the current approach for explicitness and clarity

Given the static nature of the 10-star scale, the current explicit approach is acceptable, but consider refactoring if the rating scale becomes configurable.


42-85: Inline JavaScript is duplicated for each media item.

The script block is embedded directly in the template and will be repeated for every media item rendered on the page. With many items, this could impact page size and parsing performance.

Suggested optimization

Consider moving the hover interaction logic to a shared external JavaScript file that uses event delegation on a common parent or data attributes to identify the target widget. This would:

  • Reduce HTML payload
  • Improve browser caching
  • Simplify maintenance

However, for typical list sizes, the current approach is acceptable and keeps the component self-contained.

src/templates/partials/review-editable.html (1)

48-121: Inline JavaScript duplicated per widget.

Similar to the score widget, this script block is repeated for each media item. For pages with many items, consider extracting to a shared JavaScript file with event delegation.

However, the current self-contained approach is acceptable for typical list sizes and keeps the component easy to understand.

src/core/views.py (1)

284-303: Silent error suppression may hide unexpected issues.

Lines 298-299 use contextlib.suppress(ValueError, TypeError) to handle invalid date formats, which silently ignores errors. While this prevents the widget from breaking on invalid input, it provides no feedback to the user and could mask unexpected bugs (e.g., a malformed POST payload).

Suggested improvement

Consider explicit error handling with logging or user feedback:

-        with contextlib.suppress(ValueError, TypeError):
-            media.review_date = review_date_value
+        try:
+            media.review_date = review_date_value
+        except (ValueError, TypeError) as e:
+            # Log the error for debugging
+            # Optionally: add error message to response context
+            pass  # Keep existing date on invalid input

This maintains the same user experience while improving observability for debugging.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddda38f and a61573e.

📒 Files selected for processing (14)
  • pyproject.toml
  • src/core/forms.py
  • src/core/models.py
  • src/core/templates/widgets/star_rating.html
  • src/core/urls.py
  • src/core/views.py
  • src/templates/partials/media-items.html
  • src/templates/partials/review-date-editable.html
  • src/templates/partials/review-editable.html
  • src/templates/partials/score-edit.html
  • src/templates/partials/score-editable.html
  • src/templates/partials/score-readonly.html
  • src/templates/partials/status-editable.html
  • src/theme/static_src/src/styles.css
💤 Files with no reviewable changes (2)
  • src/templates/partials/score-edit.html
  • src/templates/partials/score-readonly.html
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 21
File: src/templates/accounts/profile_edit.html:23-58
Timestamp: 2025-12-26T15:18:46.932Z
Learning: In Django projects, when form field widgets have HTMX attributes added via `field.widget.attrs.update()` in the form's `__init__` method (as in src/accounts/forms.py), those attributes are automatically rendered when using `{{ form.field }}` in templates. This is a valid pattern and does not require explicit attribute definitions in the template.
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 23
File: src/templates/partials/score-readonly.html:2-33
Timestamp: 2025-12-27T17:59:56.022Z
Learning: In src/templates/partials/score-readonly.html, the DaisyUI read-only rating pattern correctly uses `aria-current="true"` on the selected star and applies the same color class (bg-orange-400) to all star elements. DaisyUI's CSS automatically handles which stars are visually filled based on the aria-current position.
📚 Learning: 2025-12-26T15:18:46.932Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 21
File: src/templates/accounts/profile_edit.html:23-58
Timestamp: 2025-12-26T15:18:46.932Z
Learning: In Django projects, attributes added to a form field's widget via field.widget.attrs.update(...) in the form's __init__ are rendered when using {{ form.field }} in templates. No explicit attribute definitions are needed in the template. This applies to templates under src/templates in Django apps; ensure you update attrs in __init__ for consistent HTMX behavior.

Applied to files:

  • src/templates/partials/media-items.html
  • src/templates/partials/review-editable.html
  • src/templates/partials/review-date-editable.html
  • src/templates/partials/status-editable.html
  • src/templates/partials/score-editable.html
📚 Learning: 2025-12-27T17:59:56.022Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 23
File: src/templates/partials/score-readonly.html:2-33
Timestamp: 2025-12-27T17:59:56.022Z
Learning: In src/templates/partials/score-readonly.html, the DaisyUI read-only rating pattern correctly uses `aria-current="true"` on the selected star and applies the same color class (bg-orange-400) to all star elements. DaisyUI's CSS automatically handles which stars are visually filled based on the aria-current position.

Applied to files:

  • src/core/templates/widgets/star_rating.html
  • src/theme/static_src/src/styles.css
  • src/templates/partials/score-editable.html
📚 Learning: 2025-12-26T15:18:46.932Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 21
File: src/templates/accounts/profile_edit.html:23-58
Timestamp: 2025-12-26T15:18:46.932Z
Learning: In Django projects, when form field widgets have HTMX attributes added via `field.widget.attrs.update()` in the form's `__init__` method (as in src/accounts/forms.py), those attributes are automatically rendered when using `{{ form.field }}` in templates. This is a valid pattern and does not require explicit attribute definitions in the template.

Applied to files:

  • src/core/templates/widgets/star_rating.html
  • src/core/forms.py
  • src/core/views.py
🧬 Code graph analysis (4)
src/templates/partials/review-editable.html (1)
src/core/migrations/0003_media_review_media_review_date_media_score_and_more.py (1)
  • Migration (9-41)
src/core/urls.py (1)
src/core/views.py (4)
  • media_update_score_htmx (224-247)
  • media_update_status_htmx (251-268)
  • media_update_review_htmx (272-281)
  • media_update_review_date_htmx (285-303)
src/core/forms.py (1)
src/core/models.py (1)
  • Media (107-210)
src/core/views.py (2)
src/tests/conftest.py (1)
  • media (20-31)
src/core/models.py (2)
  • Media (107-210)
  • save (197-210)
🔇 Additional comments (14)
src/core/models.py (1)

206-206: Inline suppression removal relies on global SLF001 ignore.

The removal of the # noqa: SLF001 comment here only works because SLF001 was added to the global ignore list in pyproject.toml. Accessing self.cover._file is intentional and documented, making it a good candidate for an inline suppression rather than global rule disabling.

If the global SLF001 ignore in pyproject.toml is reverted (as suggested in that file's review), restore the inline suppression here.

src/theme/static_src/src/styles.css (1)

16-28: LGTM!

The star rating widget styles provide appropriate visual feedback with smooth transitions. The scale transforms (1.1 on hover, 0.95 on active) create an intuitive interactive experience.

src/core/templates/widgets/star_rating.html (1)

68-132: LGTM!

The event handlers are well-structured:

  • Click updates the value and triggers HTMX validation via the input event (consistent with the project's HTMX patterns per learnings).
  • Hover effects provide immediate visual feedback without persisting changes.
  • The clear button properly resets all state.
  • preventDefault() is correctly used to prevent default button behavior.
src/core/urls.py (1)

17-22: LGTM!

The new HTMX endpoint URL patterns follow consistent naming conventions and align with the views implemented in src/core/views.py. The URL structure is RESTful and the naming scheme (media_update_{field}_htmx) is clear and maintainable.

src/core/forms.py (2)

14-31: LGTM!

The StarRatingWidget implementation is clean and follows Django widget conventions:

  • Uses the standard get_context method to inject score_choices into the template.
  • Leverages Django's _meta API to retrieve field choices from the model, ensuring consistency.
  • The template path correctly references the new widget template.

54-54: LGTM!

The integration of StarRatingWidget into the MediaForm replaces the previous select widget with the new star rating interface. The validator class is correctly preserved to maintain HTMX validation behavior.

src/templates/partials/review-date-editable.html (2)

11-24: LGTM! The blur delay coordination is well-designed.

The combination of hx-trigger="blur delay:200ms" on the input and the Today button's use of htmx.trigger(input, 'blur') creates a smooth UX. The delay allows the Today button click to complete before the blur event fires, ensuring the date is populated before submission.


27-66: LGTM! Comprehensive interaction handling.

The JavaScript provides excellent UX:

  • Escape key cancels editing without submission
  • Today button populates and submits in one action
  • Tooltip provides format guidance
  • Proper class toggling for visibility states
src/templates/partials/score-editable.html (1)

1-85: Implementation looks solid overall.

The star rating widget correctly:

  • Uses aria-current for accessibility (consistent with DaisyUI patterns per learnings)
  • Handles the Clear button for nullable scores
  • Provides immediate visual feedback via hover states
  • Uses escapejs-like output for JavaScript safety (line 80: media.score|default:"null")

The HTMX integration properly targets the widget for outerHTML replacement, maintaining state after updates.

src/templates/partials/media-items.html (1)

36-42: Clean integration of editable partials.

The replacement of static display elements with editable partials is well-structured:

  • Status includes status_choices context variable for the dropdown (lines 38, 80)
  • Each partial is properly isolated and reusable
  • The conditional rendering and loop structures remain intact

The modular approach makes it easy to maintain and update individual components independently.

Also applies to: 80-80, 84-87

src/templates/partials/review-editable.html (1)

33-36: Elegant single-save-path design.

The textarea auto-saves on blur (line 33: hx-trigger="blur delay:200ms"), and the Save button simply dispatches the blur event (line 109). This creates a consistent save mechanism with two intuitive triggers:

  • Implicit: clicking outside the textarea
  • Explicit: clicking Save

The 200ms delay prevents premature saves during rapid focus changes.

Also applies to: 106-111

src/core/views.py (3)

224-247: Score update validation is correct.

The function properly:

  • Handles empty string to clear the score (lines 232-234)
  • Validates against model choices before updating (lines 239-240)
  • Silently ignores invalid formats to prevent breaking the UI (lines 243-245)

This defensive approach ensures the widget remains functional even with unexpected input.


250-268: Status update includes required context.

Unlike score and review updates, this view passes status_choices in the context (line 266), which matches the template's need for the dropdown options in src/templates/partials/status-editable.html. Good consistency.


49-56: Good extraction of field choices helper.

The _get_field_choices() function (lines 49-56) centralizes access to model field choices and is consistently used in both index (line 100) and search_media (line 186) views. This ensures filter dropdowns and editable widgets have consistent options.

Also applies to: 186-186

Comment thread pyproject.toml Outdated
- Added inline-editable fields for review date, review text, score, and status in media item templates.
- Created a star rating widget for user reviews.
- Removed obsolete score-edit and score-readonly partials, replacing them with score-editable.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/templates/partials/score-editable.html (1)

6-15: Consider refactoring to reduce repetition.

The 10 star buttons have nearly identical markup with only the score value and label changing. Consider using a template loop for better maintainability.

🔎 Suggested refactor using template loop
{% for choice_value, choice_label in score_choices %}
  <button type="button" 
          class="mask mask-star-2 bg-orange-400 cursor-pointer transition-transform hover:scale-110 star-btn" 
          data-score="{{ choice_value }}" 
          data-label="{{ choice_label }}" 
          aria-label="{{ choice_value }} star{{ choice_value|pluralize }}"
          {% if media.score and choice_value <= media.score %}aria-current="true"{% endif %}
          hx-post="{% url 'media_update_score_htmx' media.id %}" 
          hx-vals='{"score": "{{ choice_value }}"}'
          hx-target="#score-widget-{{ media.id }}" 
          hx-swap="outerHTML"></button>
{% endfor %}

Note: You'll need to ensure score_choices is passed in the context (currently available via the StarRatingWidget.get_context method).

src/core/views.py (1)

234-243: Consider providing user feedback for validation errors.

When score validation fails (invalid format or out-of-range), the view silently ignores the error. While this is acceptable for an HTMX pattern (the widget simply doesn't update), consider adding visual feedback for better UX.

For example, you could return an error message in the template context and display it in the widget:

try:
    score = int(score_value)
    valid_scores = dict(Media.score.field.choices).keys()
    if score in valid_scores:
        media.score = score
        media.save()
    else:
        return render(request, "partials/score-editable.html", {
            "media": media,
            "error": _("Invalid score value")
        })
except ValueError:
    return render(request, "partials/score-editable.html", {
        "media": media,
        "error": _("Score must be a number")
    })
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a61573e and 3594c0d.

📒 Files selected for processing (12)
  • src/core/forms.py
  • src/core/templates/widgets/star_rating.html
  • src/core/urls.py
  • src/core/views.py
  • src/templates/partials/media-items.html
  • src/templates/partials/review-date-editable.html
  • src/templates/partials/review-editable.html
  • src/templates/partials/score-edit.html
  • src/templates/partials/score-editable.html
  • src/templates/partials/score-readonly.html
  • src/templates/partials/status-editable.html
  • src/theme/static_src/src/styles.css
💤 Files with no reviewable changes (2)
  • src/templates/partials/score-readonly.html
  • src/templates/partials/score-edit.html
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/core/urls.py
  • src/core/templates/widgets/star_rating.html
  • src/templates/partials/review-date-editable.html
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 23
File: src/templates/partials/score-readonly.html:2-33
Timestamp: 2025-12-27T17:59:56.022Z
Learning: In src/templates/partials/score-readonly.html, the DaisyUI read-only rating pattern correctly uses `aria-current="true"` on the selected star and applies the same color class (bg-orange-400) to all star elements. DaisyUI's CSS automatically handles which stars are visually filled based on the aria-current position.
📚 Learning: 2025-12-26T15:18:46.932Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 21
File: src/templates/accounts/profile_edit.html:23-58
Timestamp: 2025-12-26T15:18:46.932Z
Learning: In Django projects, when form field widgets have HTMX attributes added via `field.widget.attrs.update()` in the form's `__init__` method (as in src/accounts/forms.py), those attributes are automatically rendered when using `{{ form.field }}` in templates. This is a valid pattern and does not require explicit attribute definitions in the template.

Applied to files:

  • src/core/forms.py
  • src/core/views.py
📚 Learning: 2025-12-26T15:18:46.932Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 21
File: src/templates/accounts/profile_edit.html:23-58
Timestamp: 2025-12-26T15:18:46.932Z
Learning: In Django projects, attributes added to a form field's widget via field.widget.attrs.update(...) in the form's __init__ are rendered when using {{ form.field }} in templates. No explicit attribute definitions are needed in the template. This applies to templates under src/templates in Django apps; ensure you update attrs in __init__ for consistent HTMX behavior.

Applied to files:

  • src/templates/partials/media-items.html
  • src/templates/partials/score-editable.html
  • src/templates/partials/status-editable.html
  • src/templates/partials/review-editable.html
📚 Learning: 2025-12-27T17:59:56.022Z
Learnt from: PascalRepond
Repo: PascalRepond/datakult PR: 23
File: src/templates/partials/score-readonly.html:2-33
Timestamp: 2025-12-27T17:59:56.022Z
Learning: In src/templates/partials/score-readonly.html, the DaisyUI read-only rating pattern correctly uses `aria-current="true"` on the selected star and applies the same color class (bg-orange-400) to all star elements. DaisyUI's CSS automatically handles which stars are visually filled based on the aria-current position.

Applied to files:

  • src/templates/partials/score-editable.html
  • src/theme/static_src/src/styles.css
🧬 Code graph analysis (3)
src/core/forms.py (2)
src/core/models.py (1)
  • Media (107-210)
src/core/migrations/0007_alter_media_score.py (1)
  • Migration (6-18)
src/templates/partials/score-editable.html (3)
src/core/migrations/0005_media_cover_alter_media_score.py (1)
  • Migration (6-23)
src/core/migrations/0007_alter_media_score.py (1)
  • Migration (6-18)
src/tests/core/test_mediaform_htmx.py (1)
  • test_mediaform_htmx_attrs (7-20)
src/core/views.py (2)
src/tests/conftest.py (1)
  • media (20-31)
src/core/models.py (2)
  • Media (107-210)
  • save (197-210)
🪛 Ruff (0.14.10)
src/core/forms.py

28-28: Unused noqa directive (non-enabled: SLF001)

Remove unused noqa directive

(RUF100)

🔇 Additional comments (12)
src/theme/static_src/src/styles.css (1)

16-28: LGTM!

The star rating widget styles provide appropriate visual feedback with smooth transitions. The scale transforms on hover and active states enhance the user experience.

src/core/forms.py (2)

14-30: LGTM! Clean widget implementation.

The StarRatingWidget correctly injects score choices into the template context for rendering labels. The use of _meta.get_field() is a documented Django API pattern.


54-54: LGTM! Widget integration is correct.

The StarRatingWidget is properly configured in the MediaForm.Meta.widgets dictionary with the validator class.

src/templates/partials/status-editable.html (1)

1-55: LGTM! Status editing widget is well-implemented.

The widget correctly toggles between display and edit modes, handles keyboard events (Escape), and uses HTMX for inline updates. The 300ms blur delay appropriately allows HTMX request processing.

src/templates/partials/score-editable.html (1)

1-103: LGTM! Star rating widget is functional and well-integrated.

The widget provides good UX with hover previews, keyboard support (Escape key), and HTMX-based updates. The JavaScript correctly manages state transitions and visual feedback.

src/templates/partials/media-items.html (2)

36-42: LGTM! Clean integration of editable widgets in grid view.

The editable partials for status, score, review, and review-date are properly integrated, replacing the previous static displays.


80-87: LGTM! Clean integration of editable widgets in table view.

The editable partials are correctly integrated into the table cells, maintaining consistency with the grid view implementation.

src/templates/partials/review-editable.html (1)

1-131: LGTM! Review editing widget is well-implemented.

The widget handles both add and edit scenarios, includes truncation for long reviews, and properly uses the escapejs filter to prevent XSS. The HTMX integration with blur delay is appropriate.

src/core/views.py (4)

221-245: LGTM! Score update view is well-implemented.

The view correctly validates the score against model choices, handles empty values for clearing the score, and maintains data integrity with proper error handling.


248-266: LGTM! Status update view is correctly implemented.

The view validates status values against model choices and properly renders the updated widget with the necessary context.


269-279: LGTM! Review update view is straightforward and correct.

The view handles review text updates appropriately, trimming whitespace and persisting changes.


282-304: LGTM! Review date update handles PartialDateField correctly.

The view appropriately handles empty values for clearing the date and lets the PartialDateField handle string-to-date conversion with proper exception handling.

Comment thread src/core/forms.py
"""
context = super().get_context(name, value, attrs)
# Get the choices from the Media model's score field
score_field = Media._meta.get_field("score") # noqa: SLF001
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused noqa directive.

The # noqa: SLF001 directive is unnecessary because the SLF001 rule is not enabled in your Ruff configuration.

🔎 Proposed fix
-        score_field = Media._meta.get_field("score")  # noqa: SLF001
+        score_field = Media._meta.get_field("score")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
score_field = Media._meta.get_field("score") # noqa: SLF001
score_field = Media._meta.get_field("score")
🧰 Tools
🪛 Ruff (0.14.10)

28-28: Unused noqa directive (non-enabled: SLF001)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In src/core/forms.py around line 28, remove the unnecessary inline noqa comment
("# noqa: SLF001") after the score_field assignment; simply delete the trailing
noqa directive so the line reads only the assignment (score_field =
Media._meta.get_field("score")), ensuring no other changes are made to
formatting or logic.

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.

1 participant