Skip to content

Fix image storage performance for large local histories#30

Open
NormanMises wants to merge 5 commits intoCookSleep:mainfrom
NormanMises:codex/fix-issue-29-image-storage-performance
Open

Fix image storage performance for large local histories#30
NormanMises wants to merge 5 commits intoCookSleep:mainfrom
NormanMises:codex/fix-issue-29-image-storage-performance

Conversation

@NormanMises
Copy link
Copy Markdown

Fixes #29.

Summary

  • Avoid loading every stored image into memory during app initialization; initialization now enumerates image IDs for cleanup and loads full data URLs only when needed.
  • Add bounded LRU caches for full-size images and thumbnails to prevent many 4K data URLs from staying resident in JS memory.
  • Persist small generated thumbnails alongside the original dataUrl, and use thumbnails for task cards and detail previews so list/detail interactions do not decode full 4K originals.
  • Keep original images for full-resolution workflows: lightbox, download/copy from the image context menu, editing outputs, and export still resolve the original image by ID.
  • Reduce interaction delay by removing expensive full-screen backdrop-blur overlays from modals/lightbox.

Verification

  • npm test passes: 8 test files, 43 tests.
  • npm run build passes.

Copilot AI review requested due to automatic review settings May 3, 2026 06:04
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses performance and memory issues when many large (e.g., 4K) images are stored locally by introducing thumbnail persistence, bounded in-memory caching, and by avoiding eager image loading during initialization.

Changes:

  • Add persisted thumbnail/metadata fields to stored image records and introduce thumbnail retrieval APIs.
  • Replace unbounded image caching with bounded LRU-style caches for originals and thumbnails.
  • Update UI components to prefer thumbnails for list/detail previews and reduce expensive blur effects in overlays/modals.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/types.ts Extends StoredImage with persisted thumbnail + dimension metadata fields.
src/store.ts Adds bounded LRU caches, thumbnail cache helpers, and changes init to enumerate IDs for orphan cleanup without loading all images.
src/lib/db.ts Generates/stores thumbnails on write and provides thumbnail/ID enumeration helpers.
src/components/TaskCard.tsx Switches task card cover rendering to use cached thumbnails (and tags images with data-image-id).
src/components/DetailModal.tsx Uses thumbnails for output preview rendering and tags images with data-image-id.
src/components/Lightbox.tsx Passes imageId through and tags the displayed image for context menu original-resolution actions.
src/components/ImageContextMenu.tsx Uses data-image-id to resolve/copy/download the original image when the displayed src is a thumbnail.
src/components/SizePickerModal.tsx Removes backdrop blur from overlay for performance.
src/components/SettingsModal.tsx Removes backdrop blur from overlay/dropdown for performance.
src/components/HelpModal.tsx Removes backdrop blur from overlay for performance.
src/components/ConfirmDialog.tsx Removes backdrop blur from overlay and adjusts modal background opacity.
src/components/InputBar.tsx Removes backdrop blur from drag overlay and adjusts opacity for performance.
Comments suppressed due to low confidence (1)

src/components/DetailModal.tsx:316

  • The output preview now only renders when currentOutputPreviewSrc exists (thumbnail). If thumbnail retrieval/generation fails, the modal shows no output image at all. Add a fallback to load/show the original output image (via ensureImageCached) when the thumbnail is unavailable, so users can still view/click the result.
          {task.status === 'done' && outputLen > 0 && currentOutputPreviewSrc && (
            <>
              <img
                ref={mainImageRef}
                src={currentOutputPreviewSrc}
                data-image-id={currentOutputImageId}
                className="saveable-image max-w-[calc(100%-2rem)] max-h-[calc(100%-2rem)] object-contain cursor-pointer"
                onLoad={() => {
                  const panel = imagePanelRef.current
                  const image = mainImageRef.current
                  if (!panel || !image) return

                  const panelRect = panel.getBoundingClientRect()
                  const imageRect = image.getBoundingClientRect()
                  setImageLabelLeft(Math.max(8, imageRect.left - panelRect.left))
                }}
                onClick={() =>
                  setLightboxImageId(task.outputImages[imageIndex], task.outputImages)
                }
                alt=""
              />
              <div data-selectable-text className="absolute top-[15px] flex items-center gap-1.5" style={{ left: imageLabelLeft }}>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/db.ts Outdated
Comment thread src/store.ts Outdated
Comment thread src/store.ts Outdated
Comment thread src/components/TaskCard.tsx
Comment thread src/store.ts
@NormanMises
Copy link
Copy Markdown
Author

Pull request overview

This PR addresses performance and memory issues when many large (e.g., 4K) images are stored locally by introducing thumbnail persistence, bounded in-memory caching, and by avoiding eager image loading during initialization.

Changes:

  • Add persisted thumbnail/metadata fields to stored image records and introduce thumbnail retrieval APIs.
  • Replace unbounded image caching with bounded LRU-style caches for originals and thumbnails.
  • Update UI components to prefer thumbnails for list/detail previews and reduce expensive blur effects in overlays/modals.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/types.ts Extends StoredImage with persisted thumbnail + dimension metadata fields.
src/store.ts Adds bounded LRU caches, thumbnail cache helpers, and changes init to enumerate IDs for orphan cleanup without loading all images.
src/lib/db.ts Generates/stores thumbnails on write and provides thumbnail/ID enumeration helpers.
src/components/TaskCard.tsx Switches task card cover rendering to use cached thumbnails (and tags images with data-image-id).
src/components/DetailModal.tsx Uses thumbnails for output preview rendering and tags images with data-image-id.
src/components/Lightbox.tsx Passes imageId through and tags the displayed image for context menu original-resolution actions.
src/components/ImageContextMenu.tsx Uses data-image-id to resolve/copy/download the original image when the displayed src is a thumbnail.
src/components/SizePickerModal.tsx Removes backdrop blur from overlay for performance.
src/components/SettingsModal.tsx Removes backdrop blur from overlay/dropdown for performance.
src/components/HelpModal.tsx Removes backdrop blur from overlay for performance.
src/components/ConfirmDialog.tsx Removes backdrop blur from overlay and adjusts modal background opacity.
src/components/InputBar.tsx Removes backdrop blur from drag overlay and adjusts opacity for performance.
Comments suppressed due to low confidence (1)
src/components/DetailModal.tsx:316

  • The output preview now only renders when currentOutputPreviewSrc exists (thumbnail). If thumbnail retrieval/generation fails, the modal shows no output image at all. Add a fallback to load/show the original output image (via ensureImageCached) when the thumbnail is unavailable, so users can still view/click the result.
          {task.status === 'done' && outputLen > 0 && currentOutputPreviewSrc && (
            <>
              <img
                ref={mainImageRef}
                src={currentOutputPreviewSrc}
                data-image-id={currentOutputImageId}
                className="saveable-image max-w-[calc(100%-2rem)] max-h-[calc(100%-2rem)] object-contain cursor-pointer"
                onLoad={() => {
                  const panel = imagePanelRef.current
                  const image = mainImageRef.current
                  if (!panel || !image) return

                  const panelRect = panel.getBoundingClientRect()
                  const imageRect = image.getBoundingClientRect()
                  setImageLabelLeft(Math.max(8, imageRect.left - panelRect.left))
                }}
                onClick={() =>
                  setLightboxImageId(task.outputImages[imageIndex], task.outputImages)
                }
                alt=""
              />
              <div data-selectable-text className="absolute top-[15px] flex items-center gap-1.5" style={{ left: imageLabelLeft }}>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Addressed in 3699eb8:

  • Added a separate IndexedDB thumbnails object store so thumbnail reads no longer deserialize full-size dataUrl records after thumbnails exist.
  • Added lazy migration for legacy thumbnail fields.
  • Added fallback to the original image when thumbnail retrieval/generation fails.
  • Added explicit InputImage[] typing for restored input images.
  • Updated delete/clear paths to remove thumbnail records too.

Verification:

  • npm test passes: 8 files, 43 tests.
  • npm run build passes.

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.

本地存图片的方式还是有点问题

2 participants