feat(collections): implement rule testing/preview functionality (Limitation #1)
Add ability to test collection rules before saving:
- New API endpoint: POST /api/collections/test-rules
- Evaluates rules against all media items
- Returns matching books with reasons
- Supports all operators: equals, contains, greater_than, etc.
- Works with all fields: genre, author, series, etc.
Backend Implementation:
- TestRules() handler in collections.go
- evaluateRule() matches book properties against rule criteria
- compareValues() handles string/numeric comparisons
- Case-insensitive matching for contains operator
Frontend Integration:
- Updated testRule() function in collection_rules.templ
- Displays matching books with covers and authors
- Shows match reason (which rule criteria matched)
- Limits preview to 20 results with count indicator
Tests Added:
- TestCompareValues_Equals: Exact match validation
- TestCompareValues_Contains: Substring matching
- TestCompareValues_GreaterThan: Numeric comparison
- TestCompareValues_NotEquals: Negation
- TestEvaluateRule_Genre: Genre field matching
- TestEvaluateRule_Author: Author field matching
- TestEvaluateRule_CopyrightYear: Year field matching
API Request Format:
{
"rules": [{
"field": "genre",
"operator": "equals",
"value": "Science Fiction"
}]
}
API Response Format:
{
"matches": [{
"media_item_id": "uuid",
"title": "Book Title",
"author": "Author Name",
"cover_image_path": "/path/to/cover.jpg",
"match_reason": "Matched rule: genre equals Science Fiction"
}],
"total": 42
}
Resolves Limitation #1: Rule Testing Preview
This commit is contained in:
@@ -301,13 +301,19 @@ templ CollectionRules(user User, collection CollectionDetailData) {
|
||||
testResultsDiv.classList.remove('hidden');
|
||||
resultsList.innerHTML = '<p class="text-sm" style="color: var(--text-secondary)">Testing rule...</p>';
|
||||
|
||||
fetch(`/api/collections/${collectionId}/test-rule`, {
|
||||
const rules = [{
|
||||
field: field,
|
||||
operator: operator,
|
||||
value: value
|
||||
}];
|
||||
|
||||
fetch('/api/collections/test-rules', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||||
},
|
||||
body: JSON.stringify({ field, operator, value })
|
||||
body: JSON.stringify({ rules: rules })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
@@ -316,9 +322,15 @@ templ CollectionRules(user User, collection CollectionDetailData) {
|
||||
html += '<div style="display: flex; flex-direction: column; gap: 0.5rem;">';
|
||||
|
||||
result.matches.slice(0, 20).forEach(book => {
|
||||
html += '<div style="display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: 0.25rem; background-color: var(--bg-primary);">';
|
||||
html += '<div style="display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: 0.25rem; background-color: var(--bg-secondary);">';
|
||||
html += '<img src="' + (book.cover_image_path || '/static/placeholder-book.svg') + '" alt="Cover" style="width: 2rem; height: 3rem; object-fit: cover; border-radius: 0.25rem;">';
|
||||
html += '<span style="font-size: 0.875rem; font-weight: 500; color: var(--text-primary);">' + book.title + '</span>';
|
||||
html += '<div style="flex: 1;">';
|
||||
html += '<div style="font-size: 0.875rem; font-weight: 500; color: var(--text-primary);">' + book.title + '</div>';
|
||||
if (book.author) {
|
||||
html += '<div style="font-size: 0.75rem; color: var(--text-secondary);">' + book.author + '</div>';
|
||||
}
|
||||
html += '<div style="font-size: 0.75rem; color: var(--accent);">' + book.match_reason + '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user