-
Notifications
You must be signed in to change notification settings - Fork 520
Add visual hierarchy for subcategories in category selects #633
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
base: main
Are you sure you want to change the base?
Add visual hierarchy for subcategories in category selects #633
Conversation
📝 WalkthroughWalkthroughAdds Category#name_with_indent and switches category option sources to hierarchy-aware ordering and indented labels across models, views, rule option builders, fixtures, tests, and localization keys. Changes
Sequence Diagram(s)(omitted — changes are view/model/localization focused and do not introduce new multi-component sequential control flow) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @app/views/transactions/bulk_updates/new.html.erb:
- Line 15: The collection_select call using form.collection_select (the
form.collection_select :category_id,
Current.family.categories.alphabetically_by_hierarchy, :id, :name_with_indent,
...) contains hardcoded user strings "Select a category" and "Category"; replace
these with i18n lookups via the t() helper (use descriptive translation keys,
add entries to your locale file for the prompt and label), e.g. change the
prompt option to t('...') and the label option to t('...'), and ensure the
chosen translation keys are added to the appropriate locale YAML so the UI text
is localized.
In @app/views/transfers/show.html.erb:
- Line 75: Replace the hardcoded user-facing strings in the collection_select
call with i18n lookups: update the label ("Category") and include_blank
("Uncategorized") options in the f.collection_select for :category_id to use
t(...) instead of literal strings (e.g., label: t('transfers.form.category') and
include_blank: t('transfers.form.uncategorized')) so the UI text is localized;
keep the same options and data attribute keys (f.collection_select,
:category_id, @categories.alphabetically_by_hierarchy, :id, :name_with_indent,
selected: @transfer.outflow_transaction.category&.id,
"data-auto-submit-form-target": "auto").
🧹 Nitpick comments (1)
test/models/category_test.rb (1)
34-54: Good test coverage for the new functionality.The tests appropriately verify both the
name_with_indentmethod and thealphabetically_by_hierarchyscope using fixtures for base cases, following project conventions.Optionally, consider adding an edge-case test to verify the scope correctly orders a parent before its child even when the child's name would alphabetically precede the parent's (e.g., parent "Zebra" with child "Apple"). Create this on-the-fly within the test rather than in fixtures to confirm the
COALESCElogic works as intended across different name ordering scenarios.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
app/models/category.rbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbtest/models/category_test.rb
🧰 Additional context used
📓 Path-based instructions (20)
**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rb: Application supports two modes: 'managed' and 'self_hosted' via Rails.application.config.app_mode
Use Current.user and Current.family instead of current_user / current_family for authentication context
Optimize database queries with proper indexes to prevent N+1 queries using includes/joins
**/*.rb: Use 2-space indentation for Ruby code
Usesnake_casefor method and variable names in Ruby
UseCamelCasefor class and module names in Ruby
Runbin/rubocopbefore pushing code; use-Aflag to auto-correct safe style violations
**/*.rb: UseCurrent.userfor the current user. Do NOT usecurrent_user.
UseCurrent.familyfor the current family. Do NOT usecurrent_family.
Files:
app/models/category.rbtest/models/category_test.rb
app/models/**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/models/**/*.rb: Keep business logic in models using skinny controllers and fat models pattern
Store all monetary values in base currency (user's primary currency) and use Money objects for conversion
Use ActiveRecord validations for form convenience and complex business logic validations
Use Rails concerns and POROs for organizing business logic instead of services folder
app/models/**/*.rb: Models should answer questions about themselves: useaccount.balance_seriesnotAccountSeries.new(account).call
Store all monetary values in base currency (user's primary currency). UseMoneyobjects for currency conversion and formatting.
Files:
app/models/category.rb
**/*.{rb,erb}
📄 CodeRabbit inference engine (.cursor/rules/general-rules.mdc)
**/*.{rb,erb}: UseCurrent.userfor accessing the current user. Do NOT usecurrent_user
UseCurrent.familyfor accessing the current family. Do NOT usecurrent_family
Files:
app/models/category.rbapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbtest/models/category_test.rbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{rb,js,erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Files:
app/models/category.rbapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbtest/models/category_test.rbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{rb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Use ActiveRecord validations for complex validations and business logic. Simple validations may be mirrored in ActiveRecord for form error handling convenience, but prioritize client-side form validation when possible
Files:
app/models/category.rbapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbtest/models/category_test.rbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
app/**/*.rb
📄 CodeRabbit inference engine (AGENTS.md)
Follow Rails conventions for folder and file names in the app directory
Files:
app/models/category.rb
**/*.{erb,rb}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,rb}: All user-facing strings must use localization (i18n). Always uset()helper. Update locale files for each new or changed element.
Use i18n interpolation for dynamic content:t("users.greeting", name: user.name)
Use Rails pluralization in i18n:t("transactions.count", count: @transactions.count)
Files:
app/models/category.rbapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbtest/models/category_test.rbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
{app/**/*.{erb,html},app/javascript/**/*.js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Prefer Hotwire-first approach: use Turbo + Stimulus for reactive UI without heavy JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
app/views/**/_*.html.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use partials only for simple, static HTML with minimal logic in specific contexts
app/views/**/_*.html.erb: Use underscore prefix for partial files (e.g., _trend_change.html.erb, _form_errors.html.erb, _sync_indicator.html.erb)
Place context-specific partials in relevant controller view directory (e.g., accounts/_account_sidebar_tabs.html.erb)
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
app/views/**/*.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/views/**/*.erb: Always use theiconhelper for icons in views, never uselucide_icondirectly
Use Tailwind design tokens (e.g., text-primary, bg-container, border-secondary) instead of raw color names
Pass data to Stimulus controllers via data-*-value attributes instead of inline JavaScript
Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Use Turbo Frames for page sections instead of client-side solutions
Use server-side formatting for currencies, numbers, and dates instead of client-side
app/views/**/*.erb: Avoid heavy logic in ERB views; prefer helpers and components instead
Ensure ERB views passerb-lintchecks as configured in.erb_lint.yml
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{css,erb}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Tailwind CSS v4.x with custom design system for styling
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.html.erb
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
**/*.html.erb: Prefer native HTML elements over JavaScript-based components. Use semantic HTML: for modals,for disclosures
Leverage Turbo frames to break up pages instead of JavaScript-driven client-side solutions
Use theiconhelper from application_helper.rb for icons. Never uselucide_iconhelper directly
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
{app/views/**,app/helpers/**,app/javascript/controllers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
{app/views/**,app/helpers/**,app/javascript/controllers/**}: Reference maybe-design-system.css for base primitives, functional tokens, and component tokens before writing styles
Prefer using functional design system tokens (e.g., text-primary, bg-container, border-primary) from maybe-design-system.css instead of raw Tailwind color values
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
{app/views/**,app/helpers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{erb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/view_conventions.mdc)
**/*.{erb,html.erb}: Use ViewComponents when: element has complex logic or styling patterns, will be reused across multiple views/contexts, needs structured styling with variants/sizes, requires interactive behavior or Stimulus controllers, has configurable slots or complex APIs, or needs accessibility features or ARIA support
Use Partials when: element is primarily static HTML with minimal logic, used in only one or few specific contexts, is simple template content, doesn't need variants/sizes/complex configuration, or is more about content organization than reusable functionality
Prefer components over partials: if a component is available in app/components, use it; if not, look for a partial; if neither exists, decide between component or partial based on complexity and reusability criteria
Keep domain logic out of views: compute values like button classes, conditional logic, and data transformations in the component file, not the template file
Always use the declarative approach when integrating Stimulus controllers in views: the ERB template should declare what happens using data-* attributes, and the Stimulus controller should respond
Component controllers in app/components/ should only be used within their component templates; global controllers in app/javascript/controllers/ can be used across any view
Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.erb
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.erb: In view templates, use native HTML elements preferred over JS components: use<dialog>for modals,<details><summary>for disclosures
Leverage Turbo frames for page sections over client-side solutions in views
Always use server-side formatting for currencies, numbers, and dates in views
Always useiconhelper inapplication_helper.rb. NEVER uselucide_icondirectly in templates.
Always generate semantic HTML in view templates
Keep domain logic OUT of view templates. Logic belongs in component files, not template files.
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{erb,js,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,js,ts,tsx}: Use query params for state management over localStorage/sessions in views
In TailwindCSS, always referenceapp/assets/tailwind/maybe-design-system.cssfor primitives and tokens
Use functional tokens defined in design system (e.g.,text-primaryinstead oftext-white,bg-containerinstead ofbg-white)
Pass data to Stimulus controllers viadata-*-valueattributes, not inline JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
**/*.{js,ts,tsx,erb}
📄 CodeRabbit inference engine (CLAUDE.md)
In Stimulus controllers, use Declarative Actions (HTML declares what happens). Example:
data-action="click->toggle#toggle"
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
test/**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
test/**/*.rb: Use Minitest with fixtures (never RSpec or FactoryBot) for testing
Use mocha gem for mocks and VCR for external API tests
Use fixtures for base cases in tests (2-3 per model) and create edge cases on-the-fly within test context
Test critical code paths only: test Commands for correct params, Queries for outputWrite tests using Minitest and fixtures as the testing framework
test/**/*.rb: Always use Minitest and fixtures for testing, NEVER rspec or factories
For tests that require a large number of fixture records, use Rails helpers to help create the records needed for the test, then inline the creation instead of defining them in fixtures
Distinguish between commands and query methods. Test output of query methods; test that commands were called with the correct params.
Never test the implementation details of one class in another class's test suite
Use themochagem for stubs and mocks
Always preferOpenStructwhen creating mock instances, or in complex cases, a mock class
Only mock what's necessary. If you're not testing return values, don't mock a return value.
test/**/*.rb: Use Minitest with fixtures for testing. NEVER use RSpec or factories.
Usemochagem for stubs and mocks. PreferOpenStructfor mock instances. Only mock what's necessary.
Files:
test/models/category_test.rb
test/**/*_test.rb
📄 CodeRabbit inference engine (AGENTS.md)
Name test files with
*_test.rbsuffix and mirror theapp/directory structure
Files:
test/models/category_test.rb
🧠 Learnings (12)
📓 Common learnings
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
📚 Learning: 2025-11-14T14:22:37.076Z
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
Applied to files:
app/models/category.rbapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbtest/models/category_test.rbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2026-01-09T12:25:59.839Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:25:59.839Z
Learning: Do not compare hard-coded strings to identify the 'Uncategorized Investments' category in Ruby/Rails code (e.g., ct.category.name != "Uncategorized Investments"). Localization/internationalization can change strings. Prefer: (1) a model-level predicate such as ct.category.uncategorized_investment? or (2) compare by identity with a canonical category, e.g., ct.category != Category.uncategorized_investments. This improves maintainability and correctness across translations. Apply this pattern to Ruby files that perform category checks (controllers, models, or elsewhere).
Applied to files:
app/models/category.rbtest/models/category_test.rb
📚 Learning: 2026-01-09T12:26:07.143Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:26:07.143Z
Learning: When checking if a category is "Uncategorized Investments" in app/controllers/pages_controller.rb (or elsewhere), avoid comparing against the hard-coded string ct.category.name != "Uncategorized Investments" because it will break when localization is implemented. Instead, use a model-level predicate like ct.category.uncategorized_investment? or compare object identity like ct.category != Category.uncategorized_investments.
Applied to files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbapp/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
Applied to files:
app/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.{rb,js,erb} : Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Applied to files:
app/views/transactions/_form.html.erb
📚 Learning: 2025-12-19T22:25:57.508Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-19T22:25:57.508Z
Learning: Applies to test/**/*_test.rb : Name test files with `*_test.rb` suffix and mirror the `app/` directory structure
Applied to files:
test/models/category_test.rb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to test/**/*.rb : Use fixtures for base cases in tests (2-3 per model) and create edge cases on-the-fly within test context
Applied to files:
test/models/category_test.rb
📚 Learning: 2025-11-24T16:57:02.574Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:57:02.574Z
Learning: Applies to test/**/*.rb : Never test the implementation details of one class in another class's test suite
Applied to files:
test/models/category_test.rb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{erb,rb} : Use Rails pluralization in i18n: `t("transactions.count", count: transactions.count)`
Applied to files:
app/views/transactions/show.html.erb
📚 Learning: 2025-11-24T16:55:59.156Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/general-rules.mdc:0-0
Timestamp: 2025-11-24T16:55:59.156Z
Learning: Applies to **/*.{rb,erb} : Use `Current.family` for accessing the current family. Do NOT use `current_family`
Applied to files:
app/views/transactions/show.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.rb : Use `Current.family` for the current family. Do NOT use `current_family`.
Applied to files:
app/views/transactions/show.html.erb
🧬 Code graph analysis (2)
app/models/category.rb (1)
app/models/budget_category.rb (2)
subcategory?(64-66)name(48-50)
test/models/category_test.rb (1)
app/models/category.rb (1)
name_with_indent(168-170)
🔇 Additional comments (4)
app/models/category.rb (1)
168-170: LGTM!Clean implementation that follows the existing
name_with_parentpattern. Using non-breaking spaces (\u00A0) is appropriate for HTML-safe indentation that won't collapse in the browser.app/views/transactions/_form.html.erb (1)
27-27: LGTM!The update correctly applies the hierarchical ordering and indented display to the category dropdown while maintaining proper i18n for the prompt and label.
app/views/category/dropdowns/_row.html.erb (1)
4-8: LGTM! Clean implementation of visual hierarchy.The conditional
ml-4class for subcategories works well alongside the existing "corner-down-right" icon indicator. Using CSS margin here (rather thanname_with_indent) is appropriate since this partial renders custom HTML rows with icons and menus, unlike the standard<select>elements in other views.app/views/transactions/show.html.erb (1)
81-88: LGTM! Hierarchical category display implemented correctly.The use of
alphabetically_by_hierarchyscope ensures parents appear before their children, andname_with_indentprovides the visual indentation in the select dropdown. The non-breaking spaces inname_with_indentwill render correctly in the HTML<option>elements. Correctly usesCurrent.familyper coding guidelines.
2f6b42a to
54537f8
Compare
Changes: - Add `name_with_indent` method to Category model using non-breaking spaces (U+00A0) for HTML-safe indentation of subcategories - Update category select dropdowns to use `alphabetically_by_hierarchy` scope and `name_with_indent` for consistent hierarchical display - Add `ml-4` margin to subcategory rows in the dropdown component - Add tests for `name_with_indent` and `alphabetically_by_hierarchy` - Localize hardcoded strings in bulk_updates and transfers views Affected views: - transactions/show, _form, bulk_updates/new - transfers/show - category/dropdowns/_row
54537f8 to
9e125c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
app/views/transactions/_form.html.erb (1)
26-27: LGTM! Verified thatincome_categoriesandexpense_categoriesare ActiveRecord relations with the correct classification filters. Thealphabetically_by_hierarchyscope properly orders categories with parent awareness, andname_with_indentcorrectly adds indentation for visual hierarchy. i18n keys are properly structured.Minor note: The controller applies
.alphabeticallyto these collections, but the view's.alphabetically_by_hierarchyscope will override that ordering. Consider removing.alphabeticallyfrom the controller since it becomes unused.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
app/models/category.rbapp/views/category/dropdowns/_row.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/transactions/show.html.erbapp/views/transfers/show.html.erbconfig/locales/views/transactions/en.ymlconfig/locales/views/transfers/en.ymltest/models/category_test.rb
🚧 Files skipped from review as they are similar to previous changes (5)
- app/views/transactions/bulk_updates/new.html.erb
- app/views/transactions/show.html.erb
- app/views/transfers/show.html.erb
- config/locales/views/transactions/en.yml
- test/models/category_test.rb
🧰 Additional context used
📓 Path-based instructions (20)
config/**
📄 CodeRabbit inference engine (AGENTS.md)
Place configuration files in
config/directory
Files:
config/locales/views/transfers/en.yml
config/locales/**/*.yml
📄 CodeRabbit inference engine (CLAUDE.md)
Organize i18n keys hierarchically by feature:
accounts.index.title,transactions.form.amount_label
Files:
config/locales/views/transfers/en.yml
{app/**/*.{erb,html},app/javascript/**/*.js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Prefer Hotwire-first approach: use Turbo + Stimulus for reactive UI without heavy JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
app/views/**/_*.html.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use partials only for simple, static HTML with minimal logic in specific contexts
app/views/**/_*.html.erb: Use underscore prefix for partial files (e.g., _trend_change.html.erb, _form_errors.html.erb, _sync_indicator.html.erb)
Place context-specific partials in relevant controller view directory (e.g., accounts/_account_sidebar_tabs.html.erb)
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
app/views/**/*.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/views/**/*.erb: Always use theiconhelper for icons in views, never uselucide_icondirectly
Use Tailwind design tokens (e.g., text-primary, bg-container, border-secondary) instead of raw color names
Pass data to Stimulus controllers via data-*-value attributes instead of inline JavaScript
Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Use Turbo Frames for page sections instead of client-side solutions
Use server-side formatting for currencies, numbers, and dates instead of client-side
app/views/**/*.erb: Avoid heavy logic in ERB views; prefer helpers and components instead
Ensure ERB views passerb-lintchecks as configured in.erb_lint.yml
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{css,erb}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Tailwind CSS v4.x with custom design system for styling
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{rb,erb}
📄 CodeRabbit inference engine (.cursor/rules/general-rules.mdc)
**/*.{rb,erb}: UseCurrent.userfor accessing the current user. Do NOT usecurrent_user
UseCurrent.familyfor accessing the current family. Do NOT usecurrent_family
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/models/category.rb
**/*.html.erb
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
**/*.html.erb: Prefer native HTML elements over JavaScript-based components. Use semantic HTML: for modals,for disclosures
Leverage Turbo frames to break up pages instead of JavaScript-driven client-side solutions
Use theiconhelper from application_helper.rb for icons. Never uselucide_iconhelper directly
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{rb,js,erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/models/category.rb
**/*.{rb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Use ActiveRecord validations for complex validations and business logic. Simple validations may be mirrored in ActiveRecord for form error handling convenience, but prioritize client-side form validation when possible
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/models/category.rb
{app/views/**,app/helpers/**,app/javascript/controllers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
{app/views/**,app/helpers/**,app/javascript/controllers/**}: Reference maybe-design-system.css for base primitives, functional tokens, and component tokens before writing styles
Prefer using functional design system tokens (e.g., text-primary, bg-container, border-primary) from maybe-design-system.css instead of raw Tailwind color values
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
{app/views/**,app/helpers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{erb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/view_conventions.mdc)
**/*.{erb,html.erb}: Use ViewComponents when: element has complex logic or styling patterns, will be reused across multiple views/contexts, needs structured styling with variants/sizes, requires interactive behavior or Stimulus controllers, has configurable slots or complex APIs, or needs accessibility features or ARIA support
Use Partials when: element is primarily static HTML with minimal logic, used in only one or few specific contexts, is simple template content, doesn't need variants/sizes/complex configuration, or is more about content organization than reusable functionality
Prefer components over partials: if a component is available in app/components, use it; if not, look for a partial; if neither exists, decide between component or partial based on complexity and reusability criteria
Keep domain logic out of views: compute values like button classes, conditional logic, and data transformations in the component file, not the template file
Always use the declarative approach when integrating Stimulus controllers in views: the ERB template should declare what happens using data-* attributes, and the Stimulus controller should respond
Component controllers in app/components/ should only be used within their component templates; global controllers in app/javascript/controllers/ can be used across any view
Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.erb
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.erb: In view templates, use native HTML elements preferred over JS components: use<dialog>for modals,<details><summary>for disclosures
Leverage Turbo frames for page sections over client-side solutions in views
Always use server-side formatting for currencies, numbers, and dates in views
Always useiconhelper inapplication_helper.rb. NEVER uselucide_icondirectly in templates.
Always generate semantic HTML in view templates
Keep domain logic OUT of view templates. Logic belongs in component files, not template files.
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{erb,js,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,js,ts,tsx}: Use query params for state management over localStorage/sessions in views
In TailwindCSS, always referenceapp/assets/tailwind/maybe-design-system.cssfor primitives and tokens
Use functional tokens defined in design system (e.g.,text-primaryinstead oftext-white,bg-containerinstead ofbg-white)
Pass data to Stimulus controllers viadata-*-valueattributes, not inline JavaScript
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.{erb,rb}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,rb}: All user-facing strings must use localization (i18n). Always uset()helper. Update locale files for each new or changed element.
Use i18n interpolation for dynamic content:t("users.greeting", name: user.name)
Use Rails pluralization in i18n:t("transactions.count", count: @transactions.count)
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erbapp/models/category.rb
**/*.{js,ts,tsx,erb}
📄 CodeRabbit inference engine (CLAUDE.md)
In Stimulus controllers, use Declarative Actions (HTML declares what happens). Example:
data-action="click->toggle#toggle"
Files:
app/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rb: Application supports two modes: 'managed' and 'self_hosted' via Rails.application.config.app_mode
Use Current.user and Current.family instead of current_user / current_family for authentication context
Optimize database queries with proper indexes to prevent N+1 queries using includes/joins
**/*.rb: Use 2-space indentation for Ruby code
Usesnake_casefor method and variable names in Ruby
UseCamelCasefor class and module names in Ruby
Runbin/rubocopbefore pushing code; use-Aflag to auto-correct safe style violations
**/*.rb: UseCurrent.userfor the current user. Do NOT usecurrent_user.
UseCurrent.familyfor the current family. Do NOT usecurrent_family.
Files:
app/models/category.rb
app/models/**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/models/**/*.rb: Keep business logic in models using skinny controllers and fat models pattern
Store all monetary values in base currency (user's primary currency) and use Money objects for conversion
Use ActiveRecord validations for form convenience and complex business logic validations
Use Rails concerns and POROs for organizing business logic instead of services folder
app/models/**/*.rb: Models should answer questions about themselves: useaccount.balance_seriesnotAccountSeries.new(account).call
Store all monetary values in base currency (user's primary currency). UseMoneyobjects for currency conversion and formatting.
Files:
app/models/category.rb
app/**/*.rb
📄 CodeRabbit inference engine (AGENTS.md)
Follow Rails conventions for folder and file names in the app directory
Files:
app/models/category.rb
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
Applied to files:
config/locales/views/transfers/en.yml
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{erb,rb} : All user-facing strings must use localization (i18n). Always use `t()` helper. Update locale files for each new or changed element.
Applied to files:
config/locales/views/transfers/en.yml
📚 Learning: 2026-01-09T12:26:07.143Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:26:07.143Z
Learning: When checking if a category is "Uncategorized Investments" in app/controllers/pages_controller.rb (or elsewhere), avoid comparing against the hard-coded string ct.category.name != "Uncategorized Investments" because it will break when localization is implemented. Instead, use a model-level predicate like ct.category.uncategorized_investment? or compare object identity like ct.category != Category.uncategorized_investments.
Applied to files:
config/locales/views/transfers/en.ymlapp/views/transactions/_form.html.erbapp/views/category/dropdowns/_row.html.erb
📚 Learning: 2025-12-18T07:48:15.175Z
Learnt from: jjmata
Repo: we-promise/sure PR: 464
File: config/locales/views/simplefin_items/zh-CN.yml:36-36
Timestamp: 2025-12-18T07:48:15.175Z
Learning: Enforce the exact branding: always use 'SimpleFIN' (FIN in all caps) and never 'SimpleFin' when referring to the Simple Financial Interchange protocol or SimpleFIN Bridge service across all locale files under config/locales/views. This applies to code, documentation, and translations. Update zh-CN.yml and other locale files as needed; perform a project-wide search/replace to fix inconsistent references and add a review check to catch any future deviations.
Applied to files:
config/locales/views/transfers/en.yml
📚 Learning: 2025-12-18T08:32:32.373Z
Learnt from: jjmata
Repo: we-promise/sure PR: 464
File: config/locales/views/simplefin_items/zh-CN.yml:36-36
Timestamp: 2025-12-18T08:32:32.373Z
Learning: In YAML locale files, ensure vendor branding (SimpleFIN) appears only in end-user visible strings (UI text, translations, user-facing messages). Internal keys such as logs, class names, and variable identifiers should not include the vendor branding and can use simpler naming like SimpleFin or simplefin. Apply this broadly to all locale files under config/locales.
Applied to files:
config/locales/views/transfers/en.yml
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{erb,rb} : Use Rails pluralization in i18n: `t("transactions.count", count: transactions.count)`
Applied to files:
app/views/transactions/_form.html.erb
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.{rb,js,erb} : Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Applied to files:
app/views/transactions/_form.html.erb
📚 Learning: 2025-11-14T14:22:37.076Z
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
Applied to files:
app/views/category/dropdowns/_row.html.erb
📚 Learning: 2025-08-22T18:30:26.758Z
Learnt from: jjmata
Repo: we-promise/sure PR: 116
File: app/views/family_exports/_list.html.erb:16-28
Timestamp: 2025-08-22T18:30:26.758Z
Learning: In the family exports UI (app/views/family_exports/_list.html.erb), raw color utilities like bg-green-500/5, text-green-500, bg-red-500/5, text-red-500 are preferred over design system tokens for status indicators to maintain UI legibility and consistency with the existing import UI patterns. The user has indicated that design token replacements would make the UI illegible in this context.
Applied to files:
app/views/category/dropdowns/_row.html.erb
📚 Learning: 2026-01-09T12:25:59.839Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:25:59.839Z
Learning: Do not compare hard-coded strings to identify the 'Uncategorized Investments' category in Ruby/Rails code (e.g., ct.category.name != "Uncategorized Investments"). Localization/internationalization can change strings. Prefer: (1) a model-level predicate such as ct.category.uncategorized_investment? or (2) compare by identity with a canonical category, e.g., ct.category != Category.uncategorized_investments. This improves maintainability and correctness across translations. Apply this pattern to Ruby files that perform category checks (controllers, models, or elsewhere).
Applied to files:
app/models/category.rb
🧬 Code graph analysis (1)
app/models/category.rb (1)
app/models/budget_category.rb (1)
subcategory?(64-66)
🔇 Additional comments (4)
config/locales/views/transfers/en.yml (1)
21-22: LGTM!The new i18n keys follow the hierarchical organization pattern (
transfers.show.category_label) and are consistent with the existing naming conventions in this file (e.g.,note_label,note_placeholder). Based on learnings and coding guidelines, this properly uses feature-based hierarchy.app/views/category/dropdowns/_row.html.erb (1)
4-8: LGTM!Clean implementation of visual hierarchy using Tailwind's
ml-4class for subcategory indentation. The conditional class pattern is idiomatic, and this complements the existingcorner-down-righticon indicator for subcategories.app/models/category.rb (2)
21-26: LGTM!The
alphabetically_by_hierarchyscope correctly implements hierarchical ordering:
- Groups categories by parent name (or own name for roots) via
COALESCE- Places roots before their subcategories via the
IS NOT NULLordering- Sorts alphabetically within each group
This ensures the expected display order: Parent A → Child A1 → Child A2 → Parent B → Child B1, etc.
168-172: LGTM!Good use of non-breaking spaces (
\u00A0) for HTML-safe indentation in select dropdowns. Unlike regular spaces, these won't collapse in HTML rendering. The comment clearly documents the purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| <%= f.fields_for :entryable do |ef| %> | ||
| <% categories = params[:nature] == "inflow" ? income_categories : expense_categories %> | ||
| <%= ef.collection_select :category_id, categories, :id, :name, { prompt: t(".category_prompt"), label: t(".category") } %> | ||
| <%= ef.collection_select :category_id, categories.alphabetically_by_hierarchy, :id, :name_with_indent, { prompt: t(".category_prompt"), label: t(".category") } %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chained ordering prevents hierarchical category display in form
Medium Severity
The TransactionsController#new sets @income_categories and @expense_categories with .alphabetically already applied. The view then calls .alphabetically_by_hierarchy on these relations. In Rails, chaining .order() calls appends rather than replaces the ordering, so the original ORDER BY name from .alphabetically takes precedence. This causes categories to be sorted purely alphabetically by their own name instead of being grouped with parents followed by their children. The hierarchical ordering intended by this PR won't work for the new transaction form, though other views like bulk_updates/new.html.erb and transactions/show.html.erb that call .alphabetically_by_hierarchy directly on Current.family.categories work correctly.
jjmata
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Subcategories already displayed like this:
And I don't see any changes here in the Rules UI (which is one of the ones I know needed treatment):
Can you include before/after screenshots to help the review, @dgilperez? 🙏
|
We can also go and unify the UI and use a autocomplete feature as your first screenshot. I didn't notice that existed already. |
But edit transactions was already working, right? I actually saw the layout added width that showed a scrollbar. |
Extends the visual hierarchy (indented subcategories) to rule condition filters and action executors, matching the transaction form behavior.
Aha, so again we are looking at different edit paths. I fixed (and found, I didn't noticed the category was clickable) this flow: When you list transactions, select one, use the edit button on the floating bottom bar, the right sidebar select is flat and not sorted properly (that's the first commit or second). |
Sooo many code-paths touch categories ... thanks for being thorough! 🙏 |
Thanks! and yes, it can be confusing, but in this case I think both paths are reasonable ... I was thinking about the autocomplete. My first thought was to use the one you showed me everywhere, but that will not fit well with the regular forms. We'd need to use a simpler one, ie a new component. I am looking at the codebase to see if I can reuse something, but otherwise I'd leave it indented for now ... what do you think? PS: The edit button in the floating bar is also broken in dark mode, its black over black ... shall I fix it in this PR or a new one? |
Replaces plain select dropdowns with searchable combobox for category selection in rule actions and conditions. Works for initial render (editing existing rules). Dynamic type changes still use plain select.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
app/views/rule/actions/_action.html.erb (1)
34-37: Template still uses plainform.selectwhile initial render usesform.combobox.The
selectTemplate(used by Stimulus when the action type changes dynamically) still renders a plainform.select, creating a UX inconsistency with the initial combobox render on line 20. Users will see a rich combobox initially but a plain select after changing action types.The commit message acknowledges this limitation ("dynamic type changes still fall back to plain select"). If this is intentional for now, consider adding a comment here noting the TODO, or update the template to use combobox for consistency.
Suggested comment to document the limitation
<%# Templates for different input types - these will be cloned and used by the Stimulus controller %> + <%# TODO: Update to use combobox for consistency with initial render (line 20) %> <template data-rule--actions-target="selectTemplate"> <span class="font-medium text-primary uppercase text-xs">to</span> <%= form.select :value, [], {} %> </template>app/views/rule/conditions/_condition.html.erb (2)
32-32: Hardcoded placeholder string should use i18n.Per coding guidelines, all user-facing strings must use localization. The placeholder
"Enter a value"should use thet()helper.Suggested fix
- <%= form.text_field :value, placeholder: "Enter a value" %> + <%= form.text_field :value, placeholder: t("rules.conditions.value_placeholder") %>Add the corresponding key to your locale file:
# config/locales/en.yml (or views/rules/en.yml) en: rules: conditions: value_placeholder: "Enter a value"Based on coding guidelines: "All user-facing strings must use localization (i18n). Always use
t()helper."
11-13: Consider i18n for the "and" prefix label.The hardcoded
"and"string should use thet()helper for localization consistency.Suggested fix
<div class="pl-2" data-condition-prefix> - <span class="font-medium uppercase text-xs">and</span> + <span class="font-medium uppercase text-xs"><%= t("rules.conditions.and_prefix") %></span> </div>
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/views/rule/actions/_action.html.erbapp/views/rule/conditions/_condition.html.erb
🧰 Additional context used
📓 Path-based instructions (15)
{app/**/*.{erb,html},app/javascript/**/*.js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Prefer Hotwire-first approach: use Turbo + Stimulus for reactive UI without heavy JavaScript
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
app/views/**/_*.html.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use partials only for simple, static HTML with minimal logic in specific contexts
app/views/**/_*.html.erb: Use underscore prefix for partial files (e.g., _trend_change.html.erb, _form_errors.html.erb, _sync_indicator.html.erb)
Place context-specific partials in relevant controller view directory (e.g., accounts/_account_sidebar_tabs.html.erb)
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
app/views/**/*.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/views/**/*.erb: Always use theiconhelper for icons in views, never uselucide_icondirectly
Use Tailwind design tokens (e.g., text-primary, bg-container, border-secondary) instead of raw color names
Pass data to Stimulus controllers via data-*-value attributes instead of inline JavaScript
Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Use Turbo Frames for page sections instead of client-side solutions
Use server-side formatting for currencies, numbers, and dates instead of client-side
app/views/**/*.erb: Avoid heavy logic in ERB views; prefer helpers and components instead
Ensure ERB views passerb-lintchecks as configured in.erb_lint.yml
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{css,erb}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Tailwind CSS v4.x with custom design system for styling
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{rb,erb}
📄 CodeRabbit inference engine (.cursor/rules/general-rules.mdc)
**/*.{rb,erb}: UseCurrent.userfor accessing the current user. Do NOT usecurrent_user
UseCurrent.familyfor accessing the current family. Do NOT usecurrent_family
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.html.erb
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
**/*.html.erb: Prefer native HTML elements over JavaScript-based components. Use semantic HTML: for modals,for disclosures
Leverage Turbo frames to break up pages instead of JavaScript-driven client-side solutions
Use theiconhelper from application_helper.rb for icons. Never uselucide_iconhelper directly
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{rb,js,erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{rb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Use ActiveRecord validations for complex validations and business logic. Simple validations may be mirrored in ActiveRecord for form error handling convenience, but prioritize client-side form validation when possible
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
{app/views/**,app/helpers/**,app/javascript/controllers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
{app/views/**,app/helpers/**,app/javascript/controllers/**}: Reference maybe-design-system.css for base primitives, functional tokens, and component tokens before writing styles
Prefer using functional design system tokens (e.g., text-primary, bg-container, border-primary) from maybe-design-system.css instead of raw Tailwind color values
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
{app/views/**,app/helpers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{erb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/view_conventions.mdc)
**/*.{erb,html.erb}: Use ViewComponents when: element has complex logic or styling patterns, will be reused across multiple views/contexts, needs structured styling with variants/sizes, requires interactive behavior or Stimulus controllers, has configurable slots or complex APIs, or needs accessibility features or ARIA support
Use Partials when: element is primarily static HTML with minimal logic, used in only one or few specific contexts, is simple template content, doesn't need variants/sizes/complex configuration, or is more about content organization than reusable functionality
Prefer components over partials: if a component is available in app/components, use it; if not, look for a partial; if neither exists, decide between component or partial based on complexity and reusability criteria
Keep domain logic out of views: compute values like button classes, conditional logic, and data transformations in the component file, not the template file
Always use the declarative approach when integrating Stimulus controllers in views: the ERB template should declare what happens using data-* attributes, and the Stimulus controller should respond
Component controllers in app/components/ should only be used within their component templates; global controllers in app/javascript/controllers/ can be used across any view
Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.erb
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.erb: In view templates, use native HTML elements preferred over JS components: use<dialog>for modals,<details><summary>for disclosures
Leverage Turbo frames for page sections over client-side solutions in views
Always use server-side formatting for currencies, numbers, and dates in views
Always useiconhelper inapplication_helper.rb. NEVER uselucide_icondirectly in templates.
Always generate semantic HTML in view templates
Keep domain logic OUT of view templates. Logic belongs in component files, not template files.
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{erb,js,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,js,ts,tsx}: Use query params for state management over localStorage/sessions in views
In TailwindCSS, always referenceapp/assets/tailwind/maybe-design-system.cssfor primitives and tokens
Use functional tokens defined in design system (e.g.,text-primaryinstead oftext-white,bg-containerinstead ofbg-white)
Pass data to Stimulus controllers viadata-*-valueattributes, not inline JavaScript
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{erb,rb}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,rb}: All user-facing strings must use localization (i18n). Always uset()helper. Update locale files for each new or changed element.
Use i18n interpolation for dynamic content:t("users.greeting", name: user.name)
Use Rails pluralization in i18n:t("transactions.count", count: @transactions.count)
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
**/*.{js,ts,tsx,erb}
📄 CodeRabbit inference engine (CLAUDE.md)
In Stimulus controllers, use Declarative Actions (HTML declares what happens). Example:
data-action="click->toggle#toggle"
Files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:26:07.143Z
Learning: When checking if a category is "Uncategorized Investments" in app/controllers/pages_controller.rb (or elsewhere), avoid comparing against the hard-coded string ct.category.name != "Uncategorized Investments" because it will break when localization is implemented. Instead, use a model-level predicate like ct.category.uncategorized_investment? or compare object identity like ct.category != Category.uncategorized_investments.
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.html.erb : Prefer native HTML elements over JavaScript-based components. Use semantic HTML: <dialog> for modals, <details><summary> for disclosures
Applied to files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.erb : In view templates, use native HTML elements preferred over JS components: use `<dialog>` for modals, `<details><summary>` for disclosures
Applied to files:
app/views/rule/conditions/_condition.html.erbapp/views/rule/actions/_action.html.erb
📚 Learning: 2025-09-23T22:22:00.149Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/stimulus_conventions.mdc:0-0
Timestamp: 2025-09-23T22:22:00.149Z
Learning: Applies to app/{views,components}/**/*.html.erb : In ERB views, wire Stimulus interactions declaratively using data-action to call controller methods
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-11-24T16:56:51.982Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/stimulus_conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:51.982Z
Learning: Applies to **/*_controller.{js,ts} : Use declarative actions in Stimulus controllers, not imperative event listeners - define actions in ERB templates using data-action attributes instead of binding events in the controller's connect() method
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{js,ts,tsx,erb} : In Stimulus controllers, use Declarative Actions (HTML declares what happens). Example: `data-action="click->toggle#toggle"`
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Pass data to Stimulus controllers via data-*-value attributes instead of inline JavaScript
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-09-23T22:23:22.963Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/view_conventions.mdc:0-0
Timestamp: 2025-09-23T22:23:22.963Z
Learning: Applies to app/{views,components}/**/*.html.erb : Integrate Stimulus declaratively in ERB: templates declare data-controller/actions/targets; controllers respond to those declarations
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-11-24T16:57:20.318Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/view_conventions.mdc:0-0
Timestamp: 2025-11-24T16:57:20.318Z
Learning: Applies to **/*.{erb,html.erb} : Always use the declarative approach when integrating Stimulus controllers in views: the ERB template should declare what happens using data-* attributes, and the Stimulus controller should respond
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-09-23T22:23:22.963Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/view_conventions.mdc:0-0
Timestamp: 2025-09-23T22:23:22.963Z
Learning: Applies to app/{views,components}/**/*.html.erb : Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-11-24T16:57:20.318Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/view_conventions.mdc:0-0
Timestamp: 2025-11-24T16:57:20.318Z
Learning: Applies to **/*.{erb,html.erb} : Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Applied to files:
app/views/rule/actions/_action.html.erb
📚 Learning: 2025-09-23T22:23:22.963Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/view_conventions.mdc:0-0
Timestamp: 2025-09-23T22:23:22.963Z
Learning: Applies to app/views/**/*.html.erb : Use ViewComponents when elements have complex logic/styling, are reused across contexts, need variants/slots/accessibility, or require Stimulus interactivity
Applied to files:
app/views/rule/actions/_action.html.erb
🔇 Additional comments (2)
app/views/rule/actions/_action.html.erb (1)
19-20: Good: Combobox integration for initial render looks correct.The
form.comboboxwith the|| []fallback is a solid defensive pattern for handling nil options.app/views/rule/conditions/_condition.html.erb (1)
26-27: LGTM! Combobox integration for condition values.The switch to
form.comboboxfor select-type filters is clean and consistent with the actions partial change. This will provide a better searchable experience for category selection.
Wrap combobox in 'form-field combobox' div to apply the dark mode styles defined in application.css.
- transactions/_form.html.erb: New transaction form - transactions/bulk_updates/new.html.erb: Bulk update drawer - transactions/show.html.erb: Edit transaction drawer (with auto-submit) All category dropdowns now use hotwire_combobox for searchable selection with hierarchical display and dark mode support.
Controller now uses alphabetically_by_hierarchy instead of alphabetically to avoid conflicting ORDER BY clauses when chained in the view.
|
New transaction (expense / income) ✅ New rule (if side) -> this is a different situation, it needs more refactoring work and I'd just move on as it is (indented). I'd say this is ready to UI-test |
Icons now use white color on the dark bg-gray-900 bar, with dark text on hover when background becomes light.
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In @app/views/transactions/bulk_updates/new.html.erb:
- Around line 15-23: The view is passing HTML attributes (class:, multiple:) in
the options hash for form.collection_select and form.select so they never reach
Rails as html_options; update the calls (and ensure
StyledFormBuilder#collection_select and #select forward attributes correctly) to
pass html attributes as the html_options argument (e.g., move class: into the
5th/6th param for collection_select and multiple: into the 4th param for select)
so Rails renders them as element attributes; adjust the StyledFormBuilder
implementations to accept an options and html_options signature and forward
html_options to super.
🧹 Nitpick comments (2)
app/views/transactions/_selection_bar.html.erb (1)
8-20: Prefer design tokens over rawtext-gray-900for icon hover, and avoid mixed color mechanismsLine 14 and Line 19 use
class: "group-hover:text-gray-900"(raw palette) while the rest of the styling leans on tokens likehover:bg-inverse. Consider switching the hover color to a token (e.g.,group-hover:text-primary) and driving icon color consistently via classes (or consistently viacolor:), to keep dark-mode/theming behavior predictable. As per coding guidelines, prefer design system tokens in views.Proposed diff (tokenize hover color; drive color via classes)
- <%= icon "pencil-line", color: "white", class: "group-hover:text-gray-900" %> + <%= icon "pencil-line", class: "text-inverse group-hover:text-primary" %> - <%= icon "trash-2", color: "white", class: "group-hover:text-gray-900" %> + <%= icon "trash-2", class: "text-inverse group-hover:text-primary" %>app/views/transactions/show.html.erb (1)
81-89: Move category options construction to controller or helper + ensure uncategorized can be selectedThe
Current.family.categories.alphabetically_by_hierarchy.map { |c| [c.name_with_indent, c.id] }pattern is duplicated across at least three views (show.html.erb, _form.html.erb, bulk_updates/new.html.erb). Prepare this in the controller or a helper method instead.Additionally, the
placeholder: t(".uncategorized")provides visual guidance but doesn't enable selecting uncategorized (nil value). You must explicitly include a nil option in the array (e.g.,[t(".uncategorized"), nil]prepended to the options) to allow users to clear the category, similar to howcollection_selectusesinclude_blank:in other parts of the codebase (e.g., transfers/show.html.erb).
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
app/controllers/transactions_controller.rbapp/views/rule/actions/_action.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/_selection_bar.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/transactions/show.html.erb
🚧 Files skipped from review as they are similar to previous changes (1)
- app/views/rule/actions/_action.html.erb
🧰 Additional context used
📓 Path-based instructions (18)
{app/**/*.{erb,html},app/javascript/**/*.js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Prefer Hotwire-first approach: use Turbo + Stimulus for reactive UI without heavy JavaScript
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
app/views/**/_*.html.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use partials only for simple, static HTML with minimal logic in specific contexts
app/views/**/_*.html.erb: Use underscore prefix for partial files (e.g., _trend_change.html.erb, _form_errors.html.erb, _sync_indicator.html.erb)
Place context-specific partials in relevant controller view directory (e.g., accounts/_account_sidebar_tabs.html.erb)
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/rule/conditions/_condition.html.erb
app/views/**/*.erb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/views/**/*.erb: Always use theiconhelper for icons in views, never uselucide_icondirectly
Use Tailwind design tokens (e.g., text-primary, bg-container, border-secondary) instead of raw color names
Pass data to Stimulus controllers via data-*-value attributes instead of inline JavaScript
Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Use Turbo Frames for page sections instead of client-side solutions
Use server-side formatting for currencies, numbers, and dates instead of client-side
app/views/**/*.erb: Avoid heavy logic in ERB views; prefer helpers and components instead
Ensure ERB views passerb-lintchecks as configured in.erb_lint.yml
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{css,erb}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Tailwind CSS v4.x with custom design system for styling
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{rb,erb}
📄 CodeRabbit inference engine (.cursor/rules/general-rules.mdc)
**/*.{rb,erb}: UseCurrent.userfor accessing the current user. Do NOT usecurrent_user
UseCurrent.familyfor accessing the current family. Do NOT usecurrent_family
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/controllers/transactions_controller.rbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.html.erb
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
**/*.html.erb: Prefer native HTML elements over JavaScript-based components. Use semantic HTML: for modals,for disclosures
Leverage Turbo frames to break up pages instead of JavaScript-driven client-side solutions
Use theiconhelper from application_helper.rb for icons. Never uselucide_iconhelper directly
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{rb,js,erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/controllers/transactions_controller.rbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{rb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/project-conventions.mdc)
Use ActiveRecord validations for complex validations and business logic. Simple validations may be mirrored in ActiveRecord for form error handling convenience, but prioritize client-side form validation when possible
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/controllers/transactions_controller.rbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
{app/views/**,app/helpers/**,app/javascript/controllers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
{app/views/**,app/helpers/**,app/javascript/controllers/**}: Reference maybe-design-system.css for base primitives, functional tokens, and component tokens before writing styles
Prefer using functional design system tokens (e.g., text-primary, bg-container, border-primary) from maybe-design-system.css instead of raw Tailwind color values
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
{app/views/**,app/helpers/**}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{erb,html.erb}
📄 CodeRabbit inference engine (.cursor/rules/view_conventions.mdc)
**/*.{erb,html.erb}: Use ViewComponents when: element has complex logic or styling patterns, will be reused across multiple views/contexts, needs structured styling with variants/sizes, requires interactive behavior or Stimulus controllers, has configurable slots or complex APIs, or needs accessibility features or ARIA support
Use Partials when: element is primarily static HTML with minimal logic, used in only one or few specific contexts, is simple template content, doesn't need variants/sizes/complex configuration, or is more about content organization than reusable functionality
Prefer components over partials: if a component is available in app/components, use it; if not, look for a partial; if neither exists, decide between component or partial based on complexity and reusability criteria
Keep domain logic out of views: compute values like button classes, conditional logic, and data transformations in the component file, not the template file
Always use the declarative approach when integrating Stimulus controllers in views: the ERB template should declare what happens using data-* attributes, and the Stimulus controller should respond
Component controllers in app/components/ should only be used within their component templates; global controllers in app/javascript/controllers/ can be used across any view
Pass data from Rails to Stimulus using data-*-value attributes, not inline JavaScript
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.erb
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.erb: In view templates, use native HTML elements preferred over JS components: use<dialog>for modals,<details><summary>for disclosures
Leverage Turbo frames for page sections over client-side solutions in views
Always use server-side formatting for currencies, numbers, and dates in views
Always useiconhelper inapplication_helper.rb. NEVER uselucide_icondirectly in templates.
Always generate semantic HTML in view templates
Keep domain logic OUT of view templates. Logic belongs in component files, not template files.
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{erb,js,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,js,ts,tsx}: Use query params for state management over localStorage/sessions in views
In TailwindCSS, always referenceapp/assets/tailwind/maybe-design-system.cssfor primitives and tokens
Use functional tokens defined in design system (e.g.,text-primaryinstead oftext-white,bg-containerinstead ofbg-white)
Pass data to Stimulus controllers viadata-*-valueattributes, not inline JavaScript
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{erb,rb}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{erb,rb}: All user-facing strings must use localization (i18n). Always uset()helper. Update locale files for each new or changed element.
Use i18n interpolation for dynamic content:t("users.greeting", name: user.name)
Use Rails pluralization in i18n:t("transactions.count", count: @transactions.count)
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/controllers/transactions_controller.rbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.{js,ts,tsx,erb}
📄 CodeRabbit inference engine (CLAUDE.md)
In Stimulus controllers, use Declarative Actions (HTML declares what happens). Example:
data-action="click->toggle#toggle"
Files:
app/views/transactions/_selection_bar.html.erbapp/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erbapp/views/transactions/show.html.erb
**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rb: Application supports two modes: 'managed' and 'self_hosted' via Rails.application.config.app_mode
Use Current.user and Current.family instead of current_user / current_family for authentication context
Optimize database queries with proper indexes to prevent N+1 queries using includes/joins
**/*.rb: Use 2-space indentation for Ruby code
Usesnake_casefor method and variable names in Ruby
UseCamelCasefor class and module names in Ruby
Runbin/rubocopbefore pushing code; use-Aflag to auto-correct safe style violations
**/*.rb: UseCurrent.userfor the current user. Do NOT usecurrent_user.
UseCurrent.familyfor the current family. Do NOT usecurrent_family.
Files:
app/controllers/transactions_controller.rb
app/controllers/**/*.rb
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use Rails strong parameters and CSRF protection throughout the application
Files:
app/controllers/transactions_controller.rb
app/**/*.rb
📄 CodeRabbit inference engine (AGENTS.md)
Follow Rails conventions for folder and file names in the app directory
Files:
app/controllers/transactions_controller.rb
🧠 Learnings (22)
📓 Common learnings
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
📚 Learning: 2025-08-22T18:30:26.758Z
Learnt from: jjmata
Repo: we-promise/sure PR: 116
File: app/views/family_exports/_list.html.erb:16-28
Timestamp: 2025-08-22T18:30:26.758Z
Learning: In the family exports UI (app/views/family_exports/_list.html.erb), raw color utilities like bg-green-500/5, text-green-500, bg-red-500/5, text-red-500 are preferred over design system tokens for status indicators to maintain UI legibility and consistency with the existing import UI patterns. The user has indicated that design token replacements would make the UI illegible in this context.
Applied to files:
app/views/transactions/_selection_bar.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Use Tailwind design tokens (e.g., text-primary, bg-container, border-secondary) instead of raw color names
Applied to files:
app/views/transactions/_selection_bar.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Use Turbo Frames for page sections instead of client-side solutions
Applied to files:
app/views/transactions/_selection_bar.html.erb
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.html.erb : Leverage Turbo frames to break up pages instead of JavaScript-driven client-side solutions
Applied to files:
app/views/transactions/_selection_bar.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.erb : Leverage Turbo frames for page sections over client-side solutions in views
Applied to files:
app/views/transactions/_selection_bar.html.erb
📚 Learning: 2026-01-09T12:26:07.143Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:26:07.143Z
Learning: When checking if a category is "Uncategorized Investments" in app/controllers/pages_controller.rb (or elsewhere), avoid comparing against the hard-coded string ct.category.name != "Uncategorized Investments" because it will break when localization is implemented. Instead, use a model-level predicate like ct.category.uncategorized_investment? or compare object identity like ct.category != Category.uncategorized_investments.
Applied to files:
app/views/transactions/_form.html.erbapp/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-11-14T14:22:37.076Z
Learnt from: jjmata
Repo: we-promise/sure PR: 326
File: app/models/category_import.rb:10-10
Timestamp: 2025-11-14T14:22:37.076Z
Learning: In the CategoryImport model (app/models/category_import.rb), the import process implements a "last write wins" strategy where importing a category.csv file completely overrides existing category structures, including parent relationships. Setting category.parent = nil in the first pass is intentional behavior to ensure the CSV becomes the source of truth.
Applied to files:
app/views/transactions/_form.html.erbapp/controllers/transactions_controller.rb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{erb,rb} : All user-facing strings must use localization (i18n). Always use `t()` helper. Update locale files for each new or changed element.
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.{erb,rb} : Use Rails pluralization in i18n: `t("transactions.count", count: transactions.count)`
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to config/locales/**/*.yml : Organize i18n keys hierarchically by feature: `accounts.index.title`, `transactions.form.amount_label`
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-10-07T09:51:02.265Z
Learnt from: jjmata
Repo: we-promise/sure PR: 189
File: app/views/password_resets/new.html.erb:14-14
Timestamp: 2025-10-07T09:51:02.265Z
Learning: In the we-promise/sure repository, use i18n methods (like `t()` or `I18n.t`) for all user-facing strings to maintain proper internationalization infrastructure. While translations should be provided, extensive localization work is not a priority at this stage of development.
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-10-01T11:40:36.711Z
Learnt from: jjmata
Repo: we-promise/sure PR: 173
File: app/mailers/email_confirmation_mailer.rb:9-9
Timestamp: 2025-10-01T11:40:36.711Z
Learning: In the we-promise/sure repository, i18n (internationalization) is used throughout the application for translations. When making branding configurable (e.g., product names), it's appropriate to add parameters like `product: product_name` to existing `t()` translation calls rather than replacing them with hardcoded strings.
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.{rb,js,erb} : Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Use server-side formatting for currencies, numbers, and dates instead of client-side
Applied to files:
app/views/transactions/bulk_updates/new.html.erb
📚 Learning: 2025-11-24T16:56:13.406Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/project-conventions.mdc:0-0
Timestamp: 2025-11-24T16:56:13.406Z
Learning: Applies to **/*.html.erb : Prefer native HTML elements over JavaScript-based components. Use semantic HTML: <dialog> for modals, <details><summary> for disclosures
Applied to files:
app/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.erb : In view templates, use native HTML elements preferred over JS components: use `<dialog>` for modals, `<details><summary>` for disclosures
Applied to files:
app/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erb
📚 Learning: 2025-11-24T16:54:59.198Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:54:59.198Z
Learning: Applies to app/views/**/*.erb : Prefer semantic HTML elements (dialog, details, summary) over JavaScript components
Applied to files:
app/views/transactions/bulk_updates/new.html.erbapp/views/rule/conditions/_condition.html.erb
📚 Learning: 2026-01-09T12:25:59.839Z
Learnt from: jjmata
Repo: we-promise/sure PR: 593
File: app/controllers/pages_controller.rb:200-203
Timestamp: 2026-01-09T12:25:59.839Z
Learning: Do not compare hard-coded strings to identify the 'Uncategorized Investments' category in Ruby/Rails code (e.g., ct.category.name != "Uncategorized Investments"). Localization/internationalization can change strings. Prefer: (1) a model-level predicate such as ct.category.uncategorized_investment? or (2) compare by identity with a canonical category, e.g., ct.category != Category.uncategorized_investments. This improves maintainability and correctness across translations. Apply this pattern to Ruby files that perform category checks (controllers, models, or elsewhere).
Applied to files:
app/controllers/transactions_controller.rb
📚 Learning: 2025-11-24T16:55:59.156Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/general-rules.mdc:0-0
Timestamp: 2025-11-24T16:55:59.156Z
Learning: Applies to **/*.{rb,erb} : Use `Current.family` for accessing the current family. Do NOT use `current_family`
Applied to files:
app/controllers/transactions_controller.rb
📚 Learning: 2026-01-10T19:11:44.566Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T19:11:44.566Z
Learning: Applies to **/*.rb : Use `Current.family` for the current family. Do NOT use `current_family`.
Applied to files:
app/controllers/transactions_controller.rb
📚 Learning: 2025-11-24T16:56:44.818Z
Learnt from: CR
Repo: we-promise/sure PR: 0
File: .cursor/rules/self_improve.mdc:0-0
Timestamp: 2025-11-24T16:56:44.818Z
Learning: Document breaking changes in rules
Applied to files:
app/views/rule/conditions/_condition.html.erb
🔇 Additional comments (6)
app/controllers/transactions_controller.rb (1)
6-10: Controller category lists now match hierarchy-aware UILine 8-9 switching to
alphabetically_by_hierarchyalignsnewwith the indented/hierarchical option rendering across the UI.app/views/rule/conditions/_condition.html.erb (1)
25-36: Combobox value input: format is compatible and properly implementedThe
condition.optionsimplementation is correct and compatible withform.combobox. Verification shows:
- Only 2 select filters exist (
TransactionCategory,TransactionMerchant), both properly overrideoptions- Format is consistent: Both return
[label, value]tuples matching the pattern used elsewhere (e.g.,app/views/transactions/bulk_updates/new.html.erbwith categories)- ID values (not strings): Both filters correctly use integer IDs as values:
[c.name_with_indent, c.id]and[name, id]via pluck- hotwire_combobox compatibility: The gem is established in the codebase and handles keyboard navigation and selection behavior natively
No action needed; the implementation is sound.
app/views/transactions/_form.html.erb (1)
26-33: Verify placeholder allows clearing category for optional fieldTransaction.category is optional (
optional: true) with no presence validation, socategory_idcan benil. However, the combobox is initialized with only mapped category options—no explicit blank choice. While a placeholder is provided, hotwire_combobox v0.4.0 may not create a selectable blank option from placeholder alone. Confirm the combobox allows users to clear/unset the category, or add an explicit blank option (e.g.,include_blank: trueor a leading blank entry in the categories array).Optionally, extract
categories.map { |c| [c.name_with_indent, c.id] }as a helper or pass it from the controller to avoid duplication across transaction forms.app/views/transactions/bulk_updates/new.html.erb (3)
2-2: Nice: relative i18n key for the drawer header title.
7-13: LGTM: disclosure titles + date label localized;Date.currentmax constraint is fine.
29-30: Good: footer button texts localized; actions unchanged.
| <div class="form-field combobox"> | ||
| <%= form.combobox :category_id, | ||
| Current.family.categories.alphabetically_by_hierarchy.map { |c| [c.name_with_indent, c.id] }, | ||
| label: t(".category"), | ||
| placeholder: t(".category_prompt") %> | ||
| </div> | ||
| <%= form.collection_select :merchant_id, Current.family.available_merchants.alphabetically, :id, :name, { prompt: t(".merchant_prompt"), label: t(".merchant"), class: "text-subdued" } %> | ||
| <%= form.select :tag_ids, Current.family.tags.alphabetically.pluck(:name, :id), { include_blank: t(".none"), multiple: true, label: t(".tags"), container_class: "h-40" } %> | ||
| <%= form.text_area :notes, label: t(".notes"), placeholder: t(".notes_placeholder"), rows: 5 %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find where styled_form_with is defined and which builder it uses
rg -n --hidden --glob='!.git/**' '\bstyled_form_with\b' -SRepository: we-promise/sure
Length of output: 9983
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate custom FormBuilder(s) and any overrides for select/collection_select
rg -n --hidden --glob='!.git/**' 'class .*FormBuilder\b|def (collection_select|select)\b' -SRepository: we-promise/sure
Length of output: 397
🏁 Script executed:
cat -n app/helpers/styled_form_builder.rbRepository: we-promise/sure
Length of output: 5654
Fix parameter positioning for collection_select and select helpers.
The StyledFormBuilder's select and collection_select methods pass the options hash unchanged to Rails' parent FormBuilder methods. HTML attributes like class: and multiple: must be in the html_options parameter (the 6th and 4th parameters respectively), not in options, or they won't be applied to the rendered HTML elements.
Proposed fix
- <%= form.collection_select :merchant_id, Current.family.available_merchants.alphabetically, :id, :name, { prompt: t(".merchant_prompt"), label: t(".merchant"), class: "text-subdued" } %>
- <%= form.select :tag_ids, Current.family.tags.alphabetically.pluck(:name, :id), { include_blank: t(".none"), multiple: true, label: t(".tags"), container_class: "h-40" } %>
+ <%= form.collection_select :merchant_id,
+ Current.family.available_merchants.alphabetically,
+ :id,
+ :name,
+ { prompt: t(".merchant_prompt"), label: t(".merchant") },
+ { class: "text-subdued" } %>
+
+ <%= form.select :tag_ids,
+ Current.family.tags.alphabetically.pluck(:name, :id),
+ { include_blank: t(".none"), label: t(".tags"), container_class: "h-40" },
+ { multiple: true } %>🤖 Prompt for AI Agents
In @app/views/transactions/bulk_updates/new.html.erb around lines 15 - 23, The
view is passing HTML attributes (class:, multiple:) in the options hash for
form.collection_select and form.select so they never reach Rails as
html_options; update the calls (and ensure StyledFormBuilder#collection_select
and #select forward attributes correctly) to pass html attributes as the
html_options argument (e.g., move class: into the 5th/6th param for
collection_select and multiple: into the 4th param for select) so Rails renders
them as element attributes; adjust the StyledFormBuilder implementations to
accept an options and html_options signature and forward html_options to super.
|
Would love to UI-test this like you said @dgilperez ... once the tests pass. ;-) |






As per #186 (reply in thread)
Changes:
name_with_indentmethod to Category model using non-breaking spaces (U+00A0) for HTML-safe indentation of subcategoriesalphabetically_by_hierarchyscope andname_with_indentfor consistent hierarchical displayml-4margin to subcategory rows in the dropdown componentname_with_indentandalphabetically_by_hierarchySummary by CodeRabbit
New Features
UI
Localization
Tests
✏️ Tip: You can customize this high-level summary in your review settings.