Skip to content

feat: dashboard navigation, photo processing refactor, and UI fixes#182

Merged
copyandpastecoder merged 18 commits intoMasterfrom
develop
Dec 31, 2025
Merged

feat: dashboard navigation, photo processing refactor, and UI fixes#182
copyandpastecoder merged 18 commits intoMasterfrom
develop

Conversation

@copyandpastecoder
Copy link
Copy Markdown
Owner

No description provided.

copyandpastecoder and others added 18 commits December 22, 2025 00:36
…eb images; restart pods; ensure migrations applied; deploy to https://dev.myuglyrocks.com
Apply the same fix to cycle-stats-chart.tsx that was applied to
dashboard statistics charts. All CSS variables in this project use
oklch() format, so hsl(var(--...)) creates invalid CSS.
Bumps the npm-minor group with 8 updates in the /src/web directory:

| Package | From | To |
| --- | --- | --- |
| [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) | `5.90.12` | `5.90.14` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `0.561.0` | `0.562.0` |
| [next](https://github.com/vercel/next.js) | `16.0.10` | `16.1.1` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.68.0` | `7.69.0` |
| [zod](https://github.com/colinhacks/zod) | `4.2.0` | `4.2.1` |
| [@next/bundle-analyzer](https://github.com/vercel/next.js/tree/HEAD/packages/next-bundle-analyzer) | `16.0.10` | `16.1.1` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.0.2` | `25.0.3` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `16.0.10` | `16.1.1` |



Updates `@tanstack/react-query` from 5.90.12 to 5.90.14
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.90.14/packages/react-query)

Updates `lucide-react` from 0.561.0 to 0.562.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/0.562.0/packages/lucide-react)

Updates `next` from 16.0.10 to 16.1.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](vercel/next.js@v16.0.10...v16.1.1)

Updates `react-hook-form` from 7.68.0 to 7.69.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](react-hook-form/react-hook-form@v7.68.0...v7.69.0)

Updates `zod` from 4.2.0 to 4.2.1
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](colinhacks/zod@v4.2.0...v4.2.1)

Updates `@next/bundle-analyzer` from 16.0.10 to 16.1.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.1.1/packages/next-bundle-analyzer)

Updates `@types/node` from 25.0.2 to 25.0.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint-config-next` from 16.0.10 to 16.1.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.1.1/packages/eslint-config-next)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.90.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: lucide-react
  dependency-version: 0.562.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: next
  dependency-version: 16.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: react-hook-form
  dependency-version: 7.69.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: zod
  dependency-version: 4.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: "@next/bundle-analyzer"
  dependency-version: 16.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: "@types/node"
  dependency-version: 25.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: eslint-config-next
  dependency-version: 16.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps AWSSDK.S3 from 4.0.14.3 to 4.0.16
Bumps Scalar.AspNetCore from 2.11.6 to 2.11.10

---
updated-dependencies:
- dependency-name: AWSSDK.S3
  dependency-version: 4.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet-minor
- dependency-name: Scalar.AspNetCore
  dependency-version: 2.11.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
- Add max-h-[60vh] and overflow-y-auto to CommandList
- Ensures materials dropdown is scrollable on mobile devices
- Fixes issue where users couldn't scroll through materials list when adding materials to stage runs
- Add OriginalStorageKey, OriginalUrl, OriginalMimeType, OriginalFileSizeBytes fields to Photo and InventoryPhoto entities
- Implement 3-phase photo processing:
  * Phase 1: Thumbnail (fast, user sees immediately)
  * Phase 2: Large WebP variant (user can view 1600x1600 while original processes)
  * Phase 3: Preserve original in native format (JPG/PNG/HEIC/etc, no conversion)
- Update ImageProcessingService with PreserveOriginalAsync method
- Update PhotoProcessingJob and InventoryPhotoProcessingJob with PreserveOriginalAsync
- Update PhotosController to chain 3 background jobs for complete processing
- Update delete methods to remove original files along with WebP variants
- Add database migration for new original photo fields

This allows users to:
- View the large variant (1600x1600 WebP) immediately when clicking photos
- Keep the true original upload for later use or deletion
- Have full quality originals preserved without lossy WebP conversion
- Add nextStageWeightBefore and nextStageWaterAmount fields to Complete Stage modal
- Fields only show when 'Repeat' or 'Advance' is selected
- Values are transferred to the auto-created next stage
- Reset fields when modal closes
- Improves workflow by allowing users to set starting values for the next stage run
- Add onClick prop to StatCard component with cursor-pointer styling
- Active Cycles card navigates to /cycles
- Completed Cycles card navigates to /cycles?tab=completed
- My Tumblers card navigates to /tumblers
- Add URL parameter support to cycles page for initial tab state
…pi/MyUglyRocks.Api/dotnet-minor-a4739b4ff2

deps(dotnet): Bump the dotnet-minor group with 2 updates
…n/src/web/npm-minor-c39b9e994d

deps(npm): bump the npm-minor group across 1 directory with 8 updates
- Update TargetFramework from net10.0 to net9.0 in all projects
- Downgrade NuGet packages to .NET 9 compatible versions:
  - Microsoft.EntityFrameworkCore: 10.0.1 -> 9.0.0
  - Npgsql.EntityFrameworkCore.PostgreSQL: 10.0.0 -> 9.0.2
  - Microsoft.AspNetCore packages: 10.0.1 -> 9.0.0
  - Serilog.AspNetCore: 10.0.0 -> 9.0.0
- Update Dockerfile to use .NET 9 SDK and runtime images

Fixes NETSDK1045 error with SDK 9.0.201
Downgrade to .NET 9.0 for SDK compatibility
## Features
- Add clickable navigation to dashboard stat cards
  - Active Cycles  /cycles
  - Completed Cycles  /cycles?tab=completed
  - My Tumblers  /tumblers
- Enhance water amount input with unit conversion (ml/fl oz)
- Add image error handling with placeholder fallback for inventory cards

## Refactoring
- Eliminate code duplication in photo processing jobs
  - Create generic BasePhotoProcessingJob<TPhoto> base class
  - Reduce PhotoProcessingJob and InventoryPhotoProcessingJob from 310 to 76 lines (-75%)
  - Total reduction: ~460 lines of duplicate code

## Bug Fixes
- Fix cycles expand/collapse individual control after using Expand All
  - Add onExpandedChange callback to reset global state
- Fix inventory card text overflow on desktop
  - Add overflow-hidden to text container
  - Add flex-shrink-0 to right side elements
  - Increase padding from p-3 to p-4
- Fix React hook error (#310) by moving useState to component level
- Fix water amount type mismatch with proper numeric input

## Database
- Add migration for photo original file fields
  - OriginalFileSizeBytes, OriginalMimeType, OriginalStorageKey, OriginalUrl
  - Apply to both photos and inventory_photos tables

## Documentation
- Add XML documentation for photo file naming conventions
- Export WATER_UNITS constant from stage-form

See CHANGELOG-2025-12-31.md for detailed changes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…to-refactor-ui-fixes

feat: dashboard navigation, photo processing refactor, and UI fixes
Copilot AI review requested due to automatic review settings December 31, 2025 21:23
@copyandpastecoder copyandpastecoder merged commit 453aa59 into Master Dec 31, 2025
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 implements dashboard navigation enhancements, refactors photo processing jobs to eliminate code duplication, and fixes several UI issues related to inventory cards and cycle expansion controls. It also adds support for preserving original uploaded photos alongside WebP variants.

  • Dashboard stat cards are now clickable and navigate to relevant pages
  • Photo processing jobs refactored using a generic base class, reducing ~460 lines of duplicate code
  • UI fixes for inventory card text overflow and image error handling
  • Cycles expand/collapse control restored after using "Expand All"

Reviewed changes

Copilot reviewed 30 out of 32 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/web/src/components/ui/stat-card.tsx Added onClick prop and cursor pointer styling for clickable stat cards
src/web/src/components/ui/cycle-stats-chart.tsx Removed unnecessary hsl() wrappers from CSS variable references
src/web/src/components/stage/stage-materials-section.tsx Added max-height and scrolling to material selection dropdown
src/web/src/components/stage-form/index.tsx Exported WATER_UNITS constant for reuse
src/web/src/components/cycle-card/types.ts Added onExpandedChange callback prop
src/web/src/components/cycle-card/cycle-card.tsx Implemented callback to reset expand state on manual toggle
src/web/src/app/(protected)/inventory/page.tsx Fixed text overflow, added image error handling, increased padding
src/web/src/app/(protected)/dashboard/page.tsx Added navigation onClick handlers to stat cards
src/web/src/app/(protected)/cycles/page.tsx Added URL parameter handling for tab selection and expand state reset
src/web/src/app/(protected)/cycles/[id]/page.tsx Added water amount input with unit conversion for next stage
src/web/package.json Updated frontend dependencies to latest versions
src/api/MyUglyRocks.Infrastructure/Services/ImageProcessingService.cs Added PreserveOriginalAsync method for phase 3 processing
src/api/MyUglyRocks.Infrastructure/MyUglyRocks.Infrastructure.csproj Downgraded from non-existent .NET 10.0 to .NET 9.0
src/api/MyUglyRocks.Infrastructure/Migrations/*.cs Added database migrations for original photo fields
src/api/MyUglyRocks.Infrastructure/Jobs/*.cs Refactored photo processing jobs with generic base class
src/api/MyUglyRocks.Core/*.csproj Corrected .NET version and dependencies
src/api/MyUglyRocks.Core/Entities/*.cs Added original photo fields to Photo and InventoryPhoto entities
src/api/MyUglyRocks.Api/*.cs Updated to three-phase photo processing and .NET 9.0
src/api/MyUglyRocks.Abstractions/Interfaces/IImageProcessingService.cs Added OriginalPreservationResult record and PreserveOriginalAsync method
Files not reviewed (1)
  • src/web/package-lock.json: Language not supported

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

Comment on lines +13 to +101
// Add original photo fields to photos table
migrationBuilder.AddColumn<string>(
name: "OriginalStorageKey",
table: "photos",
type: "text",
nullable: true);

migrationBuilder.AddColumn<string>(
name: "OriginalUrl",
table: "photos",
type: "text",
nullable: true);

migrationBuilder.AddColumn<string>(
name: "OriginalMimeType",
table: "photos",
type: "character varying(50)",
maxLength: 50,
nullable: true);

migrationBuilder.AddColumn<long>(
name: "OriginalFileSizeBytes",
table: "photos",
type: "bigint",
nullable: true);

// Add original photo fields to inventory_photos table
migrationBuilder.AddColumn<string>(
name: "OriginalStorageKey",
table: "inventory_photos",
type: "text",
nullable: true);

migrationBuilder.AddColumn<string>(
name: "OriginalUrl",
table: "inventory_photos",
type: "text",
nullable: true);

migrationBuilder.AddColumn<string>(
name: "OriginalMimeType",
table: "inventory_photos",
type: "character varying(50)",
maxLength: 50,
nullable: true);

migrationBuilder.AddColumn<long>(
name: "OriginalFileSizeBytes",
table: "inventory_photos",
type: "bigint",
nullable: true);
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
// Drop original photo fields from photos table
migrationBuilder.DropColumn(
name: "OriginalStorageKey",
table: "photos");

migrationBuilder.DropColumn(
name: "OriginalUrl",
table: "photos");

migrationBuilder.DropColumn(
name: "OriginalMimeType",
table: "photos");

migrationBuilder.DropColumn(
name: "OriginalFileSizeBytes",
table: "photos");

// Drop original photo fields from inventory_photos table
migrationBuilder.DropColumn(
name: "OriginalStorageKey",
table: "inventory_photos");

migrationBuilder.DropColumn(
name: "OriginalUrl",
table: "inventory_photos");

migrationBuilder.DropColumn(
name: "OriginalMimeType",
table: "inventory_photos");

migrationBuilder.DropColumn(
name: "OriginalFileSizeBytes",
table: "inventory_photos");
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

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

The duplicate migration files (20251231000000_AddOriginalPhotoFields.cs and 20251231203756_AddPhotoOriginalFields.cs) appear to have the same purpose but different timestamps. The earlier migration (20251231000000) adds slightly different column types for OriginalMimeType (character varying(50) vs text). This could cause migration conflicts if both are applied. Consider removing the duplicate migration or consolidating them into a single migration.

Suggested change
// Add original photo fields to photos table
migrationBuilder.AddColumn<string>(
name: "OriginalStorageKey",
table: "photos",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "OriginalUrl",
table: "photos",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "OriginalMimeType",
table: "photos",
type: "character varying(50)",
maxLength: 50,
nullable: true);
migrationBuilder.AddColumn<long>(
name: "OriginalFileSizeBytes",
table: "photos",
type: "bigint",
nullable: true);
// Add original photo fields to inventory_photos table
migrationBuilder.AddColumn<string>(
name: "OriginalStorageKey",
table: "inventory_photos",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "OriginalUrl",
table: "inventory_photos",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "OriginalMimeType",
table: "inventory_photos",
type: "character varying(50)",
maxLength: 50,
nullable: true);
migrationBuilder.AddColumn<long>(
name: "OriginalFileSizeBytes",
table: "inventory_photos",
type: "bigint",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
// Drop original photo fields from photos table
migrationBuilder.DropColumn(
name: "OriginalStorageKey",
table: "photos");
migrationBuilder.DropColumn(
name: "OriginalUrl",
table: "photos");
migrationBuilder.DropColumn(
name: "OriginalMimeType",
table: "photos");
migrationBuilder.DropColumn(
name: "OriginalFileSizeBytes",
table: "photos");
// Drop original photo fields from inventory_photos table
migrationBuilder.DropColumn(
name: "OriginalStorageKey",
table: "inventory_photos");
migrationBuilder.DropColumn(
name: "OriginalUrl",
table: "inventory_photos");
migrationBuilder.DropColumn(
name: "OriginalMimeType",
table: "inventory_photos");
migrationBuilder.DropColumn(
name: "OriginalFileSizeBytes",
table: "inventory_photos");
// Intentionally left empty.
// A later migration (20251231203756_AddPhotoOriginalFields) is the
// authoritative source for adding the original photo fields.
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
// Intentionally left empty.
// The corresponding columns are managed by the later migration.

Copilot uses AI. Check for mistakes.
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.

3 participants