Skip to content

feat(modtools): UI refactoring and shared component library (Part 2/3)#2985

Merged
dcschreiber merged 39 commits intofeature/sc-36475/modtools-pr1-backendfrom
feature/sc-36475/modtools-pr2-ui-refactor
Mar 22, 2026
Merged

feat(modtools): UI refactoring and shared component library (Part 2/3)#2985
dcschreiber merged 39 commits intofeature/sc-36475/modtools-pr1-backendfrom
feature/sc-36475/modtools-pr2-ui-refactor

Conversation

@dcschreiber
Copy link
Copy Markdown
Contributor

@dcschreiber dcschreiber commented Jan 8, 2026

Part 2 of 3: UI Refactoring

Related PRs:

Stacked PR chain: PR3 → PR2 → PR1 → master (merge in reverse order: PR1 first, then PR2, then PR3)


Summary

This PR refactors the ModeratorToolsPanel with:

  • New shared component library (ModToolsSection, HelpButton, StatusMessage)
  • Extraction of existing tools into separate component files
  • Modtools styles added to s2.css (search for "ModTools Design System")
  • Consistent patterns for state management, validation, and error display

ModeratorToolsPanel Refactoring (static/js/ModeratorToolsPanel.jsx)

The existing ModeratorToolsPanel was refactored in two phases:

Phase 1 - UI Integration:

  • Wrapped existing tools in ModToolsSection for consistent collapsible UI
  • Added help content constants for each tool

Phase 2 - Component Extraction:

Extracted 6 pre-existing tools into separate component files (~1373 → ~98 lines):

Component Source
BulkDownloadText.jsx Extracted from inline render, converted to functional component
BulkUploadCSV.jsx Extracted from inline render, converted to functional component
WorkflowyModeratorTool.jsx Extracted existing class component
UploadLinksFromCSV.jsx Extracted existing class component
DownloadLinks.jsx Extracted existing function (renamed from GetLinks)
RemoveLinksFromCsv.jsx Extracted existing function component

Logic Preserved: All existing API calls and behavior unchanged.

Key patterns in new code:

  • Uses Sefaria.apiRequestWithBody instead of jQuery/fetch (no jQuery dependency)
  • MESSAGE_TYPES enum for type-safe status messages
  • Proactive validation (button disabled when invalid, no click required)
  • Uses existing String.prototype.stripHtml() for HTML sanitization (from sefaria/util.js)

Shared Components (static/js/modtools/components/shared/)

Four reusable components extracted for consistency across modtools:

ModToolsSection.jsx (~137 lines)

  • Collapsible section wrapper with consistent styling
  • Header with collapse/expand chevron icon
  • Optional HelpButton integration via helpContent prop
  • Bilingual title support (title and titleHe)
  • Keyboard accessible (Enter/Space to toggle)
  • All sections collapsed by default (controlled via collapsed state)

HelpButton.jsx (~98 lines)

  • Question mark icon button that opens modal with documentation
  • Modal overlay with close button and backdrop click to dismiss
  • ESC key support for accessibility
  • Focus trap management (focuses modal on open, returns focus on close)
  • Accepts helpContent prop with JSX documentation

StatusMessage.jsx (~51 lines)

  • Consistent message display with type-based styling
  • Exports MESSAGE_TYPES enum (SUCCESS, ERROR, WARNING, INFO)
  • Accepts string (defaults to 'info') or {type, message} object
  • Shows nothing when message is empty

CSS Styles (in static/css/s2.css)

Modtools styles (~1650 lines) added to s2.css (search for "ModTools Design System"):

  • Styling for all shared components (ModToolsSection, HelpButton, StatusMessage)
  • Form input styles with RTL support
  • Validation error display
  • Collapsible section animations
  • Modal overlay for help content
  • Field clearing visual feedback (greyed-out disabled inputs)

Note: CSS has not been thoroughly reviewed as this is internal tooling. Styling prioritizes functionality over polish.


Files Changed

Frontend (React/JS):

  • static/js/ModeratorToolsPanel.jsx - Refactored (now imports extracted components)
  • static/js/modtools/components/BulkDownloadText.jsx - Extracted from ModeratorToolsPanel
  • static/js/modtools/components/BulkUploadCSV.jsx - Extracted from ModeratorToolsPanel
  • static/js/modtools/components/WorkflowyModeratorTool.jsx - Extracted from ModeratorToolsPanel
  • static/js/modtools/components/UploadLinksFromCSV.jsx - Extracted from ModeratorToolsPanel
  • static/js/modtools/components/DownloadLinks.jsx - Extracted from ModeratorToolsPanel (was GetLinks)
  • static/js/modtools/components/RemoveLinksFromCsv.jsx - Extracted from ModeratorToolsPanel
  • static/js/modtools/components/shared/ModToolsSection.jsx - Shared component
  • static/js/modtools/components/shared/HelpButton.jsx - Shared component
  • static/js/modtools/components/shared/StatusMessage.jsx - Shared component
  • static/js/modtools/components/shared/index.js - Exports
  • static/js/modtools/index.js - Exports

CSS:

  • static/css/s2.css - Added modtools styles (search for "ModTools Design System")

🤖 Generated with Claude Code


Next PR

➡️ Part 3: #2986 - Merge after this PR is merged.

@dcschreiber dcschreiber force-pushed the feature/sc-36475/modtools-pr2-ui-refactor branch from c2f79bb to 0513b32 Compare January 8, 2026 13:20
@dcschreiber dcschreiber changed the base branch from feature/sc-36475/modtools-pr1-backend to master January 8, 2026 13:27
@dcschreiber dcschreiber marked this pull request as draft January 8, 2026 13:37
@dcschreiber dcschreiber changed the base branch from master to feature/sc-36475/modtools-pr1-backend January 12, 2026 07:09
@dcschreiber dcschreiber force-pushed the feature/sc-36475/modtools-pr2-ui-refactor branch from cece9f2 to 99f5d70 Compare January 12, 2026 07:11
@dcschreiber dcschreiber marked this pull request as ready for review January 12, 2026 07:27
dcschreiber and others added 6 commits January 13, 2026 11:03
…, StatusMessage)

Add reusable UI components for the modtools panel:

- ModToolsSection: Collapsible section wrapper with consistent styling
- HelpButton: Question mark icon that opens modal with documentation
- StatusMessage: Type-based message display (success, error, warning, info)

These components provide a consistent UI pattern for all modtools.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive stylesheet (~1600 lines) for modtools components:
- Styling for shared components (ModToolsSection, HelpButton, StatusMessage)
- Form input styles with RTL support
- Collapsible section animations
- Modal overlay for help content

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract 6 tools from ModeratorToolsPanel.jsx to individual files:
- BulkDownloadText, BulkUploadCSV, WorkflowyModeratorTool
- UploadLinksFromCSV, DownloadLinks (renamed from GetLinks), RemoveLinksFromCsv

Changes:
- Create utils/stripHtmlTags.js for shared HTML sanitization
- Main file reduced from ~681 to ~92 lines
- Modernized BulkDownloadText and BulkUploadCSV to functional components
- Updated modtools/index.js with new exports

All existing functionality preserved, just reorganized for maintainability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move CSS loading from JavaScript import (Webpack bundled) to a static
<link> tag in base.html. This ensures the CSS is collected by Django's
collectstatic and served properly in CI environments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adjusted design system tokens and component styles:
- Reduced spacing tokens by ~50% (xs: 2px, sm: 4px, md: 8px, lg: 12px, xl: 16px)
- Reduced input padding from 12px 16px to 8px 12px
- Reduced button padding from 12px 24px to 8px 16px
- Reduced font sizes (inputs: 13px, labels: 13px, buttons: 13px)
- Reduced input height from 48px to 36px
- Reduced section title font size from 24px to 18px
- Reduced page header font size from 28px to 22px
- Reduced checkbox size from 18px to 14px
- Made border radius smaller (sm instead of md for most elements)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace inline styles with design system classes (fieldGroup, hasError, fieldError)
- Remove <br /> tags between form fields
- Wrap form sections with fieldGroupSection class
- Reduce gap spacing in legacy form CSS
- Make fieldset and fieldGroupSection more compact

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@dcschreiber dcschreiber force-pushed the feature/sc-36475/modtools-pr2-ui-refactor branch from 1b541f8 to 0a61d4c Compare January 13, 2026 09:03
dcschreiber and others added 6 commits January 13, 2026 11:03
- Add IndexSelector component for card-based index selection grid
- Add VERSION_FIELD_METADATA for BulkVersionEditor field definitions
- Add INDEX_FIELD_METADATA for future BulkIndexEditor use

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add BulkVersionEditor for bulk editing Version metadata
- Supports editing license, status, priority, notes, and other fields
- Integration with IndexSelector for version selection
- Export from modtools module and render in main panel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add modtools_test.py for version bulk edit API testing
- Add fieldMetadata.test.js for field metadata validation
- Add stripHtmlTags.test.js for HTML utility function tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MODTOOLS_GUIDE.md for quick reference and usage
- Add COMPONENT_LOGIC.md for detailed implementation flows

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Note: These components are disabled and do not need review.
Open tickets exist to reintroduce them:
- BulkIndexEditor: Bulk edit index metadata
- AutoLinkCommentaryTool: Auto-link commentaries to base texts
- NodeTitleEditor: Edit node titles within Index schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* COLOR PALETTE
* Warm scholarly tones with clear semantic meaning
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should be able to use Sefaria colors. I'm pretty sure we should have similar colors for almost all of these cases. Also, I don't think it's necessary to have a special file for modtools.css. It seems like static.css is appropriate

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

But don't you think it would be good to have a separate file to work towards splitting things up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I updated the colors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Really modtools are static pages so I think they should be in the static CSS file. I'm not sure if we should be splitting things up. But I would agree that the CSS of internal tools is not very important so I don't care too much either way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Although, precisely because the CSS here is not that important, it makes the case stronger not weaker for putting it into static.css.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🤖 Claude Code: Fixed! I've moved all the modtools.css content into static.css and removed the separate file. Also removed the <link> tag from base.html.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@stevekaplan123 although the modtools is a react page. Would it not be more correct to put it in S2?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah put it in s2.css thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

dcschreiber and others added 4 commits January 14, 2026 13:19
Replace custom color palette with Sefaria CSS variables from s2.css
for consistency with the rest of the application.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace custom color palette with Sefaria CSS variables from s2.css
for consistency with the rest of the application.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…omponent

Replaces the inline ChevronIcon component with an img tag referencing
the existing chevron-down.svg icon file, following the established
pattern for icon usage in the codebase.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…omponent

Replaces the inline ChevronIcon component with an img tag referencing
the existing chevron-down.svg icon file, following the established
pattern for icon usage in the codebase.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
dcschreiber and others added 4 commits January 14, 2026 14:27
Remove code that is only used by disabled tool components:
- check_index_dependencies_api from views.py (used by NodeTitleEditor)
- URL route for check-index-dependencies from urls.py
- TestCheckIndexDependenciesAPI from modtools_test.py
- INDEX_FIELD_METADATA from fieldMetadata.js (used by BulkIndexEditor)
- BASE_TEXT_MAPPING_OPTIONS from fieldMetadata.js (used by AutoLinkCommentaryTool)

This code will be added to the appropriate feature branches:
- sc-36477: NodeTitleEditor
- sc-36473: BulkIndexEditor
- sc-36476: AutoLinkCommentaryTool

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved conflicts:
- ModeratorToolsPanel.jsx: Keep pr2's UI refactor version
- base.html: Keep modtools.css include from pr2
Resolved conflicts:
- sefaria/urls.py: Took pr2's version (django-hosts structure with PR1 API routes)
@mergify
Copy link
Copy Markdown

mergify bot commented Jan 18, 2026

🧪 CI Insights

Here's what we observed from your CI run for 0d01b7b.

🟢 All jobs passed!

But CI Insights is watching 👀

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
dcschreiber and others added 5 commits January 19, 2026 18:21
…static.css

- Replace custom stripHtmlTags utility with existing String.prototype.stripHtml()
  from sefaria/util.js (addresses PR comment about duplicate code)
- Move modtools.css content into static.css and remove separate file
  (addresses PR comment about CSS file organization)
- Remove now-empty modtools/utils directory
- Update base.html to remove modtools.css link tag

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Set renderStatic=True in the modtools view so that static.css
(which now contains the modtools CSS) is loaded on the page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@dcschreiber
Copy link
Copy Markdown
Contributor Author

🤖 Claude Code: Added a fix — static.css is conditionally loaded only when renderStatic=True in the template context. Updated the modtools view to set this flag so the CSS is properly loaded.

dcschreiber and others added 3 commits January 20, 2026 12:22
Move modtools CSS to s2.css instead of static.css because:
- s2.css is the main React app CSS, always loaded for app pages
- static.css is only loaded when renderStatic=True (for static Django pages)
- modtools is a React component, not a static page, so s2.css is
  semantically correct

This also reverts the renderStatic=True workaround in the modtools view.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove stripHtmlTags from shared/index.js (use String.prototype.stripHtml() instead)
- Delete stripHtmlTags.test.js (testing built-in method not needed)
- Update MODTOOLS_GUIDE.md to reference s2.css instead of modtools.css

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@dcschreiber dcschreiber requested a review from yitzhakc January 26, 2026 10:48
dcschreiber and others added 8 commits January 29, 2026 13:03
Clarify that versionTitle is a database identifier and cannot be bulk
edited. Improve mark-for-deletion messaging to explain the two-step
process: marking adds a note, then a developer completes the deletion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ulk-version-editor

feat(modtools): BulkVersionEditor feature (Part 3/3)
@dcschreiber dcschreiber merged commit 1e3c289 into feature/sc-36475/modtools-pr1-backend Mar 22, 2026
8 of 10 checks passed
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.

3 participants