Skip to content

Commit 44285ea

Browse files
authored
Merge branch 'main' into dependabot/bundler/noticed-2.8.1
2 parents 1ff1cfd + bfbb04c commit 44285ea

File tree

176 files changed

+4505
-606
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+4505
-606
lines changed

.github/copilot-instructions.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ This repository contains the **Better Together Community Engine** (an isolated R
9292
9393
## Coding Guidelines
9494
95+
### Debugging and Development Practices
96+
- **Never use Rails console or runner for debugging** - These commands don't support our test-driven development approach
97+
- **Debug through comprehensive tests**: Write detailed test scenarios to reproduce, understand, and verify fixes for issues
98+
- **Use test-driven debugging workflow**:
99+
- Create specific tests that reproduce the problematic behavior
100+
- Add debugging assertions in tests to verify intermediate state
101+
- Trace through code by reading files and using grep search
102+
- Validate fixes by ensuring tests pass
103+
- **Leverage RSpec debugging tools**: Use `--format documentation` for detailed output, `fit` for focused testing, `puts` for temporary debug output in tests
104+
- **Analyze logs and error messages**: Examine Rails logs, test output, and stack traces for debugging information
105+
- **Read code systematically**: Use file reading tools to understand code paths and data flow
106+
- **Temporary debug output**: Add debug statements in application code if needed, but remove before committing
107+
95108
### Docker Environment Usage
96109
- **All database-dependent commands must use `bin/dc-run`**: This includes tests, generators, and any command that connects to PostgreSQL, Redis, or Elasticsearch
97110
- **Dummy app commands use `bin/dc-run-dummy`**: For Rails commands that need the dummy app context (console, migrations specific to dummy app)
@@ -102,10 +115,11 @@ This repository contains the **Better Together Community Engine** (an isolated R
102115
- RuboCop: `bin/dc-run bundle exec rubocop`
103116
- **IMPORTANT**: Never use `rspec -v` - this displays version info, not verbose output. Use `--format documentation` for detailed output.
104117
- **Examples of commands requiring `bin/dc-run-dummy`**:
105-
- Rails console: `bin/dc-run-dummy rails console`
118+
- Rails console: `bin/dc-run-dummy rails console` (for administrative tasks only, NOT for debugging)
106119
- Dummy app migrations: `bin/dc-run-dummy rails db:migrate`
107120
- Dummy app database operations: `bin/dc-run-dummy rails db:seed`
108121
- **Commands that don't require bin/dc-run**: File operations, documentation generation (unless database access needed), static analysis tools that don't connect to services
122+
- **CRITICAL**: Rails console and runner are NOT debugging tools in this project - use comprehensive test suites instead
109123
110124
### Security Requirements
111125
- **Run Brakeman before generating code**: `bin/dc-run bundle exec brakeman --quiet --no-pager`

.rubocop.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,21 @@ plugins:
1313
- rubocop-rspec_rails
1414
- rubocop-capybara
1515
- rubocop-factory_bot
16+
17+
# Disable all RSpec cops that affect test quality but not production code
18+
RSpec/ExampleLength:
19+
Enabled: false
1620
RSpec/MultipleExpectations:
1721
Enabled: false
22+
RSpec/MultipleMemoizedHelpers:
23+
Enabled: false
24+
RSpec/ContextWording:
25+
Enabled: false
26+
RSpec/MessageSpies:
27+
Enabled: false
28+
RSpec/LetSetup:
29+
Enabled: false
30+
1831
Style/StringLiterals:
1932
Exclude:
2033
- 'db/migrate/*'

AGENTS.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ Instructions for GitHub Copilot and other automated contributors working in this
1919
- test: `community_engine_test`
2020
- Use `DATABASE_URL` to connect (overrides fallback host in `config/database.yml`).
2121

22+
## Debugging Guidelines
23+
- **Never use Rails console or runner for debugging** - These commands don't align with our test-driven development approach
24+
- **Use comprehensive test suites instead**: Write detailed tests to understand and verify system behavior
25+
- **Debug through tests**: Create specific test scenarios to reproduce and validate fixes for issues
26+
- **Use log analysis**: Examine Rails logs, test output, and error messages for debugging information
27+
- **Add temporary debugging assertions in tests**: Use `expect()` statements to verify intermediate state in tests
28+
- **Use RSpec debugging tools**: Use `--format documentation` for detailed test output, `fit` for focused testing
29+
- **Trace through code by reading files**: Use file reading and grep search to understand code paths
30+
- **Add debug output in application code temporarily** if needed, but remove before committing
31+
- **Validate fixes through test success**: Confirm that issues are resolved by having tests pass
32+
2233
## Commands
2334
- **Tests:** `bin/dc-run bin/ci`
2435
(Equivalent: `bin/dc-run bash -c "cd spec/dummy && bundle exec rspec"`)
@@ -29,7 +40,7 @@ Instructions for GitHub Copilot and other automated contributors working in this
2940
- Multiple specific lines: `bin/dc-run bundle exec rspec spec/file1_spec.rb:123 spec/file2_spec.rb:456`
3041
- **Important**: RSpec does NOT support hyphenated line numbers (e.g., `spec/file_spec.rb:123-456` is INVALID)
3142
- **Do NOT use `-v` flag**: The `-v` flag displays RSpec version information, NOT verbose output. Use `--format documentation` for detailed test descriptions.
32-
- **Rails Console:** `bin/dc-run-dummy rails console` (runs console in the dummy app context)
43+
- **Rails Console:** `bin/dc-run-dummy rails console` (for administrative tasks only - NOT for debugging. Use comprehensive tests for debugging instead)
3344
- **Rails Commands in Dummy App:** `bin/dc-run-dummy rails [command]` for any Rails commands that need the dummy app environment
3445
- **Lint:** `bin/dc-run bundle exec rubocop`
3546
- **Security:** `bin/dc-run bundle exec brakeman --quiet --no-pager` and `bin/dc-run bundle exec bundler-audit --update`
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { Controller } from "@hotwired/stimulus"
2+
3+
export default class extends Controller {
4+
static targets = ["select", "input"]
5+
static values = {
6+
searchUrl: String,
7+
searchDelay: { type: Number, default: 300 }
8+
}
9+
10+
connect() {
11+
this.setupPersonSearch()
12+
}
13+
14+
setupPersonSearch() {
15+
const select = this.selectTarget
16+
17+
// Convert select to a searchable input
18+
this.createSearchInput(select)
19+
20+
// Hide the original select
21+
select.style.display = 'none'
22+
}
23+
24+
createSearchInput(select) {
25+
const searchContainer = select.parentElement
26+
27+
// Create search input
28+
const searchInput = document.createElement('input')
29+
searchInput.type = 'text'
30+
searchInput.className = 'form-control person-search-input'
31+
searchInput.placeholder = select.options[0]?.text || 'Search for people...'
32+
searchInput.setAttribute('data-person-search-target', 'input')
33+
34+
// Create results dropdown
35+
const resultsDropdown = document.createElement('div')
36+
resultsDropdown.className = 'person-search-results'
37+
resultsDropdown.style.cssText = `
38+
position: absolute;
39+
top: 100%;
40+
left: 0;
41+
right: 0;
42+
background: white;
43+
border: 1px solid #ced4da;
44+
border-top: none;
45+
border-radius: 0 0 0.375rem 0.375rem;
46+
max-height: 200px;
47+
overflow-y: auto;
48+
z-index: 1000;
49+
display: none;
50+
`
51+
52+
// Insert elements
53+
searchContainer.style.position = 'relative'
54+
searchContainer.insertBefore(searchInput, select)
55+
searchContainer.appendChild(resultsDropdown)
56+
57+
// Setup event listeners
58+
let searchTimeout
59+
searchInput.addEventListener('input', (e) => {
60+
clearTimeout(searchTimeout)
61+
searchTimeout = setTimeout(() => {
62+
this.performSearch(e.target.value, resultsDropdown, select)
63+
}, this.searchDelayValue)
64+
})
65+
66+
searchInput.addEventListener('focus', () => {
67+
if (searchInput.value) {
68+
this.performSearch(searchInput.value, resultsDropdown, select)
69+
}
70+
})
71+
72+
// Hide dropdown when clicking outside
73+
document.addEventListener('click', (e) => {
74+
if (!searchContainer.contains(e.target)) {
75+
resultsDropdown.style.display = 'none'
76+
}
77+
})
78+
}
79+
80+
async performSearch(query, resultsDropdown, select) {
81+
if (query.length < 2) {
82+
resultsDropdown.style.display = 'none'
83+
return
84+
}
85+
86+
try {
87+
const response = await fetch(`${this.searchUrlValue}?search=${encodeURIComponent(query)}`, {
88+
headers: {
89+
'Accept': 'application/json',
90+
'X-Requested-With': 'XMLHttpRequest'
91+
}
92+
})
93+
94+
if (!response.ok) throw new Error('Search failed')
95+
96+
const people = await response.json()
97+
this.displayResults(people, resultsDropdown, select)
98+
} catch (error) {
99+
console.error('Person search error:', error)
100+
resultsDropdown.innerHTML = '<div class="p-2 text-danger">Search failed</div>'
101+
resultsDropdown.style.display = 'block'
102+
}
103+
}
104+
105+
displayResults(people, resultsDropdown, select) {
106+
if (people.length === 0) {
107+
resultsDropdown.innerHTML = '<div class="p-2 text-muted">No people found</div>'
108+
resultsDropdown.style.display = 'block'
109+
return
110+
}
111+
112+
const resultsHtml = people.map(person => `
113+
<div class="person-result p-2 border-bottom"
114+
style="cursor: pointer; display: flex; align-items: center;"
115+
data-person-id="${person.id}"
116+
data-person-name="${person.name}">
117+
<div class="me-2" style="width: 32px; height: 32px; background-color: #dee2e6; border-radius: 50%; display: flex; align-items: center; justify-content: center;">
118+
<i class="fas fa-user text-muted"></i>
119+
</div>
120+
<div>
121+
<div class="fw-medium">${person.name}</div>
122+
<small class="text-muted">@${person.slug}</small>
123+
</div>
124+
</div>
125+
`).join('')
126+
127+
resultsDropdown.innerHTML = resultsHtml
128+
resultsDropdown.style.display = 'block'
129+
130+
// Add click handlers to results
131+
resultsDropdown.querySelectorAll('.person-result').forEach(result => {
132+
result.addEventListener('click', () => {
133+
this.selectPerson(result, select)
134+
resultsDropdown.style.display = 'none'
135+
})
136+
})
137+
}
138+
139+
selectPerson(resultElement, select) {
140+
const personId = resultElement.dataset.personId
141+
const personName = resultElement.dataset.personName
142+
143+
// Update the hidden select
144+
select.innerHTML = `<option value="${personId}" selected>${personName}</option>`
145+
select.value = personId
146+
147+
// Update the search input
148+
const searchInput = this.inputTarget
149+
searchInput.value = personName
150+
151+
// Trigger change event for form handling
152+
select.dispatchEvent(new Event('change', { bubbles: true }))
153+
}
154+
}

app/assets/stylesheets/better_together/application.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
@use 'conversations';
3232
@use 'forms';
3333
@use 'image-galleries';
34+
@use 'invitations';
3435
@use 'maps';
3536
@use 'metrics';
3637
@use 'navigation';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
.profile-image.invitee {
3+
width: 32px;
4+
height: 32px;
5+
}

app/controllers/better_together/application_controller.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,13 @@ def user_not_authorized(exception) # rubocop:todo Metrics/AbcSize, Metrics/Metho
158158
]
159159
else
160160
flash[:error] = message # Use flash for regular redirects
161-
redirect_back(fallback_location: home_page_path)
161+
162+
# For unauthenticated users, redirect to login
163+
if current_user.nil?
164+
redirect_to new_user_session_path(locale: I18n.locale)
165+
else
166+
redirect_back(fallback_location: home_page_path)
167+
end
162168
end
163169
end
164170
# rubocop:enable Metrics/MethodLength

0 commit comments

Comments
 (0)