Skip to content

Conversation

@nishanroy561
Copy link

@nishanroy561 nishanroy561 commented Jan 10, 2026

Fixes #992

Implementation Approach

1. Backend (The Logic)

Database Count

  • I added a simple function db_get_total_image_count() that asks the database efficiently: "How many rows are in the images table?". This gives me the raw number of photos in your library.

Updating the API

  • I modified the existing GET /all-folders endpoint. Previously, it only returned a list of folders. Now, before sending the response, it calls my new database function to get the total count and packages it alongside the folder list.

Data Structure

  • I updated the "blueprint" (Schema) for the API response to officially include a new field: total_images.

2. Frontend (The Visuals)

Updating Definitions

  • I updated the TypeScript interfaces so the frontend knows to expect a total_images number from the server.

Storing the Data

  • I updated the Redux store (the app's global memory) to save this number when the folder list is loaded.

Displaying it

  • I found the "Folder Management" card in the Settings page and updated its description to dynamically show the number I stored (For Example, "1,250 images total").

In short: The backend counts the files, sends the number with the folder list, and the frontend grabs that number and simply displays it in the settings card.

Screenshot 2026-01-10 121140

Summary by CodeRabbit

  • New Features
    • Total image count now displayed in Folder Management settings.
    • Folder Management section is now expandable and collapsible.
    • Settings cards now support optional action elements in the header.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 10, 2026

📝 Walkthrough

Walkthrough

The PR implements a feature to display the total number of images across the entire gallery. It adds a database function to retrieve the total image count, enriches the /all-folders API endpoint to include this data, manages the count in Redux state, and enhances the UI with collapsible folder management and display of the total image count.

Changes

Cohort / File(s) Summary
Backend Database Layer
backend/app/database/images.py
Adds db_get_total_image_count() function that executes SELECT COUNT(*) on the images table, includes error handling with logging and connection cleanup.
Backend API & Schema
backend/app/routes/folders.py, backend/app/schemas/folders.py, docs/backend/backend_python/openapi.json
Updates get_all_folders() to call db_get_total_image_count() and include the result in the response. Adds total_images: int field to GetAllFoldersData schema and updates OpenAPI documentation.
Frontend Type Definitions
frontend/src/types/Folder.ts
Adds total_images: number field to GetAllFoldersData interface to align with backend schema.
Frontend Redux State
frontend/src/features/folderSlice.ts
Introduces totalImages: number state property, adds setTotalImages reducer to update it, and resets it in clearFolders().
Frontend Data Flow
frontend/src/hooks/useFolderOperations.tsx
Imports setTotalImages action and dispatches it with total_images from the API response when folders data loads.
Frontend UI Components
frontend/src/pages/SettingsPage/components/SettingsCard.tsx
Adds optional action prop to SettingsCardProps to support custom actions in the header, rendered right-aligned.
Frontend Folder Management UI
frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx
Adds collapsible section controlled by isExpanded state with chevron toggle button; integrates totalImages from Redux into the card description; wraps folder list and controls in conditional rendering.
Frontend Dependencies
frontend/package.json
Adds baseline-browser-mapping (^2.9.11) dependency.

Sequence Diagram(s)

sequenceDiagram
    participant DB as Database
    participant API as Backend API
    participant Hook as useFolderOperations
    participant Redux as Redux Store
    participant UI as FolderManagementCard

    API->>DB: SELECT COUNT(*) FROM images
    DB-->>API: total_count
    Hook->>API: GET /all-folders
    API-->>Hook: {folders, total_count, total_images}
    Hook->>Redux: dispatch setFolders(folders)
    Hook->>Redux: dispatch setTotalImages(total_images)
    Redux-->>UI: totalImages state update
    UI->>UI: render with total image count
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement, frontend, backend

Suggested reviewers

  • rahulharpal1603

Poem

🐰 Through databases deep, a count takes flight,
Redux state gleams with total insight,
Cards now collapsible, folders unfold,
The gallery's size, at last, is told! ✨📸

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive All changes are scoped to implementing total image count feature. The package.json dependency addition (baseline-browser-mapping) appears unrelated to the stated objectives and may warrant clarification. Clarify the purpose of the baseline-browser-mapping dependency addition in frontend/package.json to confirm it is not an accidental or unrelated change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Feat/total image count' directly and clearly describes the main change: adding total image count functionality across the application.
Linked Issues check ✅ Passed The pull request fully implements all coding requirements from issue #992: database function for total count [#992], GET /all-folders endpoint update [#992], GetAllFoldersData schema extension [#992], frontend type updates [#992], Redux state management [#992], and UI display [#992].

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @backend/app/routes/folders.py:
- Around line 14-15: The code calls db_get_total_image_count for the
/all-folders endpoint and returns 0 on DB error, which is both a potential perf
hotspot (COUNT(*) on every request) and hides errors; change the implementation
to avoid per-request full-table COUNT(*) by either: 1) returning the
total_images as a nullable field or propagating the DB error upward instead of
defaulting to 0 (so the UI can handle/error), or 2) compute the count alongside
your existing folder query or use a cached/materialized value updated
asynchronously; update the handler(s) that reference db_get_total_image_count
(including the other use at the block around lines 464-472) to adopt one of
these approaches and ensure error paths do not silently return 0.

In @frontend/package.json:
- Line 91: The devDependency "baseline-browser-mapping" is unused and should be
removed from frontend/package.json; delete the "baseline-browser-mapping":
"^2.9.11" entry from the devDependencies block, run your package manager (npm
install or yarn install) to update the lockfile, and verify there are no
references by searching the repo for "baseline-browser-mapping" and confirming
it no longer appears in package-lock.json or yarn.lock.

In @frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx:
- Around line 29-55: Format the totalImages displayed in the SettingsCard
description by calling totalImages.toLocaleString() so it renders like "1,250
images total"; switch the Button's onClick to the functional updater form
setIsExpanded(prev => !prev) and add an aria-label (e.g., aria-label="Toggle
folder management") to the icon-only expand/collapse Button for accessibility;
in the folder list rendering replace unstable index keys with the stable
folder.folder_id property (use folder.folder_id as the key wherever you
currently use index).
🧹 Nitpick comments (1)
frontend/src/hooks/useFolderOperations.tsx (1)

11-12: Remove the unknown cast; read total_images via the typed response (?? 0)
The current cast can hide contract mismatches and makes refactors risky. Prefer accessing the field directly and using nullish coalescing.

Proposed diff
   useEffect(() => {
     if (foldersQuery.data?.data?.folders) {
       const folders = foldersQuery.data.data.folders as FolderDetails[];
       dispatch(setFolders(folders));
-      dispatch(
-        setTotalImages(
-          (foldersQuery.data.data as unknown as { total_images: number })
-            .total_images || 0,
-        ),
-      );
+      dispatch(setTotalImages(foldersQuery.data.data.total_images ?? 0));
     }
   }, [foldersQuery.data, dispatch]);

Also applies to: 60-71

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3af96c and 33ad75d.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • backend/app/database/images.py
  • backend/app/routes/folders.py
  • backend/app/schemas/folders.py
  • docs/backend/backend_python/openapi.json
  • frontend/package.json
  • frontend/src/features/folderSlice.ts
  • frontend/src/hooks/useFolderOperations.tsx
  • frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx
  • frontend/src/pages/SettingsPage/components/SettingsCard.tsx
  • frontend/src/types/Folder.ts
🧰 Additional context used
🧬 Code graph analysis (3)
frontend/src/hooks/useFolderOperations.tsx (1)
frontend/src/features/folderSlice.ts (1)
  • setTotalImages (28-30)
backend/app/routes/folders.py (3)
backend/app/database/images.py (1)
  • db_get_total_image_count (424-440)
backend/app/schemas/folders.py (2)
  • GetAllFoldersResponse (66-70)
  • GetAllFoldersData (35-38)
frontend/src/types/Folder.ts (1)
  • GetAllFoldersData (10-14)
frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx (3)
frontend/src/app/store.ts (1)
  • RootState (22-22)
frontend/src/types/Folder.ts (1)
  • FolderDetails (1-8)
frontend/src/components/FolderPicker/FolderPicker.tsx (1)
  • FolderPicker (5-29)
🔇 Additional comments (6)
docs/backend/backend_python/openapi.json (1)

1789-1798: LGTM!

The OpenAPI schema correctly reflects the addition of the total_images field to GetAllFoldersData, with appropriate type (integer) and required status.

backend/app/schemas/folders.py (1)

38-38: LGTM!

The addition of total_images: int to the GetAllFoldersData model is straightforward and consistent with the existing schema structure.

frontend/src/types/Folder.ts (1)

13-13: LGTM!

The TypeScript interface correctly mirrors the backend schema change, with appropriate type mapping (Python int → TypeScript number).

backend/app/database/images.py (1)

424-440: Consider the error handling approach, though consistent with existing patterns.

The function returns 0 on both database errors and when no results exist, which masks failures. However, this approach is consistent with other database functions in this file (e.g., db_get_all_images returns [] on error). Since errors are logged and this is for display purposes, the current implementation is acceptable.

For enhanced robustness, consider whether the calling code in backend/app/routes/folders.py should handle potential database unavailability differently (e.g., returning an error response vs. showing 0 images).

frontend/src/pages/SettingsPage/components/SettingsCard.tsx (1)

17-21: Action slot addition looks good; ensure icon-only actions are accessible
action?: React.ReactNode and the ml-auto placement are clean and flexible. Just make sure consumers (e.g., icon-only <Button>) provide an aria-label/tooltip since the card can’t enforce that.

Also applies to: 34-35, 47-47

frontend/src/features/folderSlice.ts (1)

5-16: Redux addition is clean and consistent with the API contract
totalImages + setTotalImages, and resetting it in clearFolders(), all look good. (Optional: if clearFolders is meant to fully reset state, also consider clearing lastUpdatedAt.)

Also applies to: 27-31, 77-80, 100-109

Comment on lines +14 to 15
from app.database.images import db_get_total_image_count
from app.logging.setup_logging import get_logger
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Consider perf + error semantics of COUNT(*) on every /all-folders call
This correctly wires total_images into the response, but a full-table COUNT(*) can become expensive at scale, and returning 0 on error (per db_get_total_image_count) can silently mislead the UI. Consider either caching/materializing the count (or computing it alongside existing queries), and/or propagating an error (or a nullable field) instead of defaulting to 0 on DB failure.

Also applies to: 464-472

🤖 Prompt for AI Agents
In @backend/app/routes/folders.py around lines 14 - 15, The code calls
db_get_total_image_count for the /all-folders endpoint and returns 0 on DB
error, which is both a potential perf hotspot (COUNT(*) on every request) and
hides errors; change the implementation to avoid per-request full-table COUNT(*)
by either: 1) returning the total_images as a nullable field or propagating the
DB error upward instead of defaulting to 0 (so the UI can handle/error), or 2)
compute the count alongside your existing folder query or use a
cached/materialized value updated asynchronously; update the handler(s) that
reference db_get_total_image_count (including the other use at the block around
lines 464-472) to adopt one of these approaches and ensure error paths do not
silently return 0.

"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.20",
"babel-jest": "^29.7.0",
"baseline-browser-mapping": "^2.9.11",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the package.json file to confirm the dependency
cat -n frontend/package.json | head -100

Repository: AOSSIE-Org/PictoPy

Length of output: 4146


🏁 Script executed:

# Search for any usage of baseline-browser-mapping in the codebase
rg "baseline-browser-mapping" --type js --type json -A 2 -B 2

Repository: AOSSIE-Org/PictoPy

Length of output: 1775


🏁 Script executed:

# Also search for any imports or references to this package
rg "baseline.*browser.*mapping" --type js --type ts --type json

Repository: AOSSIE-Org/PictoPy

Length of output: 563


🏁 Script executed:

# Check what packages depend on baseline-browser-mapping
rg "baseline-browser-mapping" frontend/package-lock.json -B 20 | grep -E '"(name|requires|dependencies)"' | head -30

Repository: AOSSIE-Org/PictoPy

Length of output: 85


🏁 Script executed:

# Search for any configuration files that might use it
find frontend -type f \( -name "jest.config.*" -o -name "postcss.config.*" -o -name "babel.config.*" -o -name ".babelrc*" \) -exec cat {} \;

Repository: AOSSIE-Org/PictoPy

Length of output: 753


🏁 Script executed:

# Check if it's referenced in any scripts or configuration
rg "baseline" frontend --type json --type js --type ts -i

Repository: AOSSIE-Org/PictoPy

Length of output: 563


🏁 Script executed:

# Check which package in package-lock.json has baseline-browser-mapping as a dependency
python3 <<'EOF'
import json
import sys

with open('frontend/package-lock.json', 'r') as f:
    lock_data = json.load(f)

packages = lock_data.get('packages', {})
for pkg_name, pkg_info in packages.items():
    if 'dependencies' in pkg_info:
        if 'baseline-browser-mapping' in pkg_info['dependencies']:
            print(f"Package '{pkg_name}' depends on baseline-browser-mapping: {pkg_info['dependencies']['baseline-browser-mapping']}")
EOF

Repository: AOSSIE-Org/PictoPy

Length of output: 148


🏁 Script executed:

# Also check the dependencies of autoprefixer and caniuse which often pull in browser mappings
rg "\"autoprefixer\"" frontend/package-lock.json -A 15 | head -40

Repository: AOSSIE-Org/PictoPy

Length of output: 1193


Remove baseline-browser-mapping from devDependencies

This package is explicitly listed but has no usage anywhere in the codebase—not in any code files, configuration files, or npm scripts. It's a CLI tool for browser mapping that's unrelated to the PR objective of displaying total image count and appears to be an accidental inclusion.

🤖 Prompt for AI Agents
In @frontend/package.json at line 91, The devDependency
"baseline-browser-mapping" is unused and should be removed from
frontend/package.json; delete the "baseline-browser-mapping": "^2.9.11" entry
from the devDependencies block, run your package manager (npm install or yarn
install) to update the lockfile, and verify there are no references by searching
the repo for "baseline-browser-mapping" and confirming it no longer appears in
package-lock.json or yarn.lock.

Comment on lines +29 to +55
const [isExpanded, setIsExpanded] = useState(true);

const taggingStatus = useSelector(
(state: RootState) => state.folders.taggingStatus,
);

const totalImages = useSelector((state: RootState) => state.folders.totalImages);

return (
<SettingsCard
icon={Folder}
title="Folder Management"
description="Configure your photo library folders and AI settings"
description={`Configure your photo library folders and AI settings (${totalImages} images total)`}
action={
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
onClick={() => setIsExpanded(!isExpanded)}
>
{isExpanded ? (
<ChevronUp className="h-4 w-4" />
) : (
<ChevronDown className="h-4 w-4" />
)}
</Button>
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix formatting + list keys + a11y for the new header action

  • Format totalImages (toLocaleString) to match the “1,250 images total” requirement.
  • Use a stable key (folder.folder_id) instead of index.
  • Add aria-label for the icon-only expand/collapse button; use functional state update.
Proposed diff
-  const [isExpanded, setIsExpanded] = useState(true);
+  const [isExpanded, setIsExpanded] = useState(true);

   const taggingStatus = useSelector(
     (state: RootState) => state.folders.taggingStatus,
   );

-  const totalImages = useSelector((state: RootState) => state.folders.totalImages);
+  const totalImages = useSelector((state: RootState) => state.folders.totalImages);
+  const totalImagesLabel = totalImages.toLocaleString();

   return (
     <SettingsCard
       icon={Folder}
       title="Folder Management"
-      description={`Configure your photo library folders and AI settings (${totalImages} images total)`}
+      description={`Configure your photo library folders and AI settings (${totalImagesLabel} images total)`}
       action={
         <Button
           variant="ghost"
           size="sm"
           className="h-8 w-8 p-0"
-          onClick={() => setIsExpanded(!isExpanded)}
+          aria-label={isExpanded ? 'Collapse folder management' : 'Expand folder management'}
+          onClick={() => setIsExpanded((v) => !v)}
         >
           {isExpanded ? (
             <ChevronUp className="h-4 w-4" />
           ) : (
             <ChevronDown className="h-4 w-4" />
           )}
         </Button>
       }
     >
       {isExpanded && (
         <div className="animate-in fade-in slide-in-from-top-2 duration-200">
           {folders.length > 0 ? (
             <div className="space-y-3">
               {folders.map((folder: FolderDetails, index: number) => (
                 <div
-                  key={index}
+                  key={folder.folder_id}
                   className="group border-border bg-background/50 relative rounded-lg border p-4 transition-all hover:border-gray-300 hover:shadow-sm dark:hover:border-gray-600"
                 >

Also applies to: 35-35, 41-41, 57-66, 61-65

🤖 Prompt for AI Agents
In @frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx around
lines 29 - 55, Format the totalImages displayed in the SettingsCard description
by calling totalImages.toLocaleString() so it renders like "1,250 images total";
switch the Button's onClick to the functional updater form setIsExpanded(prev =>
!prev) and add an aria-label (e.g., aria-label="Toggle folder management") to
the icon-only expand/collapse Button for accessibility; in the folder list
rendering replace unstable index keys with the stable folder.folder_id property
(use folder.folder_id as the key wherever you currently use index).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEAT/ENHAN. : Display the total number of Photos in the Gallery

1 participant