From 04ecda99eed0d573ded7850e718ba5babd8a170c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Tue, 3 Mar 2026 11:16:40 +0100 Subject: [PATCH 1/4] fix(chore): --- .../com/printcalculator/controller/OptionsController.java | 5 +++-- .../repository/FilamentVariantRepository.java | 5 +++++ .../repository/MaterialOrcaProfileMapRepository.java | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/printcalculator/controller/OptionsController.java b/backend/src/main/java/com/printcalculator/controller/OptionsController.java index 3b2295b..e187422 100644 --- a/backend/src/main/java/com/printcalculator/controller/OptionsController.java +++ b/backend/src/main/java/com/printcalculator/controller/OptionsController.java @@ -16,6 +16,7 @@ import com.printcalculator.repository.NozzleOptionRepository; import com.printcalculator.repository.PrinterMachineRepository; import com.printcalculator.service.OrcaProfileResolver; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -54,13 +55,13 @@ public class OptionsController { } @GetMapping("/api/calculator/options") + @Transactional(readOnly = true) public ResponseEntity getOptions( @RequestParam(value = "printerMachineId", required = false) Long printerMachineId, @RequestParam(value = "nozzleDiameter", required = false) Double nozzleDiameter ) { List types = materialRepo.findAll(); - List allVariants = variantRepo.findAll().stream() - .filter(v -> Boolean.TRUE.equals(v.getIsActive())) + List allVariants = variantRepo.findByIsActiveTrue().stream() .sorted(Comparator .comparing((FilamentVariant v) -> safeMaterialCode(v.getFilamentMaterialType()), String.CASE_INSENSITIVE_ORDER) .thenComparing(v -> safeString(v.getVariantDisplayName()), String.CASE_INSENSITIVE_ORDER)) diff --git a/backend/src/main/java/com/printcalculator/repository/FilamentVariantRepository.java b/backend/src/main/java/com/printcalculator/repository/FilamentVariantRepository.java index 43b9e73..bd70537 100644 --- a/backend/src/main/java/com/printcalculator/repository/FilamentVariantRepository.java +++ b/backend/src/main/java/com/printcalculator/repository/FilamentVariantRepository.java @@ -2,11 +2,16 @@ package com.printcalculator.repository; import com.printcalculator.entity.FilamentVariant; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.EntityGraph; import com.printcalculator.entity.FilamentMaterialType; +import java.util.List; import java.util.Optional; public interface FilamentVariantRepository extends JpaRepository { + @EntityGraph(attributePaths = {"filamentMaterialType"}) + List findByIsActiveTrue(); + // We try to match by color name if possible, or get first active Optional findByFilamentMaterialTypeAndColorName(FilamentMaterialType type, String colorName); Optional findByFilamentMaterialTypeAndVariantDisplayName(FilamentMaterialType type, String variantDisplayName); diff --git a/backend/src/main/java/com/printcalculator/repository/MaterialOrcaProfileMapRepository.java b/backend/src/main/java/com/printcalculator/repository/MaterialOrcaProfileMapRepository.java index 0c2e61c..30c7d35 100644 --- a/backend/src/main/java/com/printcalculator/repository/MaterialOrcaProfileMapRepository.java +++ b/backend/src/main/java/com/printcalculator/repository/MaterialOrcaProfileMapRepository.java @@ -3,6 +3,7 @@ package com.printcalculator.repository; import com.printcalculator.entity.FilamentMaterialType; import com.printcalculator.entity.MaterialOrcaProfileMap; import com.printcalculator.entity.PrinterMachineProfile; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; @@ -14,5 +15,6 @@ public interface MaterialOrcaProfileMapRepository extends JpaRepository findByPrinterMachineProfileAndIsActiveTrue(PrinterMachineProfile printerMachineProfile); } From 90bdb5384d9e76fa50458f4f7277e9d218c81b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Tue, 3 Mar 2026 11:49:40 +0100 Subject: [PATCH 2/4] fix(front-end): color selector --- .../color-selector/color-selector.component.scss | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/app/shared/components/color-selector/color-selector.component.scss b/frontend/src/app/shared/components/color-selector/color-selector.component.scss index 3c487dc..9d0843a 100644 --- a/frontend/src/app/shared/components/color-selector/color-selector.component.scss +++ b/frontend/src/app/shared/components/color-selector/color-selector.component.scss @@ -47,6 +47,10 @@ box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; width: 230px; /* Increased size */ + max-height: min(62vh, 360px); + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; // Little triangle arrow &::before { @@ -67,6 +71,7 @@ transform: translate(-50%, -50%); width: 280px; /* Provide enough width for touch targets */ max-width: 90vw; /* Safety constraint */ + max-height: min(72vh, 420px); box-shadow: 0 10px 25px rgba(0,0,0,0.2); /* Stronger shadow for modal feel */ /* Hide arrow on mobile since it's detached from trigger */ @@ -76,6 +81,12 @@ } } +@media (max-height: 720px) { + .color-popup { + max-height: min(56vh, 300px); + } +} + .category { margin-bottom: 12px; From c6804861574450b4183e897f70f409107f567767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Tue, 3 Mar 2026 12:05:00 +0100 Subject: [PATCH 3/4] fix(front-end): quantity changes and normalization --- backend/entrypoint.sh | 2 - .../calculator/calculator-page.component.ts | 3 +- .../quote-result/quote-result.component.ts | 3 +- .../upload-form/upload-form.component.ts | 49 ++++++++++++++----- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh index 8013e19..cd79e27 100644 --- a/backend/entrypoint.sh +++ b/backend/entrypoint.sh @@ -5,8 +5,6 @@ echo "DB_URL: $DB_URL" echo "DB_USERNAME: $DB_USERNAME" echo "SPRING_DATASOURCE_URL: $SPRING_DATASOURCE_URL" echo "SLICER_PATH: $SLICER_PATH" -echo "--- ALL ENV VARS ---" -env echo "----------------------------------------------------------------" # Determine which environment variables to use for database connection diff --git a/frontend/src/app/features/calculator/calculator-page.component.ts b/frontend/src/app/features/calculator/calculator-page.component.ts index d8b1dbb..2f67113 100644 --- a/frontend/src/app/features/calculator/calculator-page.component.ts +++ b/frontend/src/app/features/calculator/calculator-page.component.ts @@ -226,9 +226,10 @@ export class CalculatorPageComponent implements OnInit { this.step.set('quote'); } - onItemChange(event: {id?: string, fileName: string, quantity: number}) { + onItemChange(event: {id?: string, index: number, fileName: string, quantity: number}) { // 1. Update local form for consistency (UI feedback) if (this.uploadForm) { + this.uploadForm.updateItemQuantityByIndex(event.index, event.quantity); this.uploadForm.updateItemQuantityByName(event.fileName, event.quantity); } diff --git a/frontend/src/app/features/calculator/components/quote-result/quote-result.component.ts b/frontend/src/app/features/calculator/components/quote-result/quote-result.component.ts index 3320816..a97b1b8 100644 --- a/frontend/src/app/features/calculator/components/quote-result/quote-result.component.ts +++ b/frontend/src/app/features/calculator/components/quote-result/quote-result.component.ts @@ -22,7 +22,7 @@ export class QuoteResultComponent implements OnDestroy { result = input.required(); consult = output(); proceed = output(); - itemChange = output<{id?: string, fileName: string, quantity: number}>(); + itemChange = output<{id?: string, index: number, fileName: string, quantity: number}>(); // Local mutable state for items to handle quantity changes items = signal([]); @@ -83,6 +83,7 @@ export class QuoteResultComponent implements OnDestroy { this.itemChange.emit({ id: item.id, + index, fileName: item.fileName, quantity: normalizedQty }); diff --git a/frontend/src/app/features/calculator/components/upload-form/upload-form.component.ts b/frontend/src/app/features/calculator/components/upload-form/upload-form.component.ts index 9bacf3f..eb9d39d 100644 --- a/frontend/src/app/features/calculator/components/upload-form/upload-form.component.ts +++ b/frontend/src/app/features/calculator/components/upload-form/upload-form.component.ts @@ -199,11 +199,28 @@ export class UploadFormComponent implements OnInit { } } - updateItemQuantityByName(fileName: string, quantity: number) { + updateItemQuantityByIndex(index: number, quantity: number) { + if (!Number.isInteger(index) || index < 0) return; + const normalizedQty = this.normalizeQuantity(quantity); + this.items.update(current => { + if (index >= current.length) return current; + const updated = [...current]; + updated[index] = { ...updated[index], quantity: normalizedQty }; + return updated; + }); + } + + updateItemQuantityByName(fileName: string, quantity: number) { + const targetName = this.normalizeFileName(fileName); + const normalizedQty = this.normalizeQuantity(quantity); + + this.items.update(current => { + let matched = false; return current.map(item => { - if (item.file.name === fileName) { - return { ...item, quantity }; + if (!matched && this.normalizeFileName(item.file.name) === targetName) { + matched = true; + return { ...item, quantity: normalizedQty }; } return item; }); @@ -239,14 +256,9 @@ export class UploadFormComponent implements OnInit { updateItemQuantity(index: number, event: Event) { const input = event.target as HTMLInputElement; - let val = parseInt(input.value, 10); - if (isNaN(val) || val < 1) val = 1; - - this.items.update(current => { - const updated = [...current]; - updated[index] = { ...updated[index], quantity: val }; - return updated; - }); + const parsed = parseInt(input.value, 10); + const quantity = Number.isFinite(parsed) ? parsed : 1; + this.updateItemQuantityByIndex(index, quantity); } updateItemColor(index: number, newSelection: string | { colorName: string; filamentVariantId?: number }) { @@ -387,4 +399,19 @@ export class UploadFormComponent implements OnInit { this.form.get('itemsTouched')?.setValue(true); } } + + private normalizeQuantity(quantity: number): number { + if (!Number.isFinite(quantity) || quantity < 1) { + return 1; + } + return Math.floor(quantity); + } + + private normalizeFileName(fileName: string): string { + return (fileName || '') + .split(/[\\/]/) + .pop() + ?.trim() + .toLowerCase() ?? ''; + } } From be8e52357490538342126a5efe2ec57154c709b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Tue, 3 Mar 2026 12:33:18 +0100 Subject: [PATCH 4/4] fix(deploy): cicd.yaml --- .gitea/workflows/cicd.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/cicd.yaml b/.gitea/workflows/cicd.yaml index c2b1f54..8975867 100644 --- a/.gitea/workflows/cicd.yaml +++ b/.gitea/workflows/cicd.yaml @@ -3,6 +3,8 @@ name: Build, Test, Deploy and Analysis on: push: branches: [main, int, dev] + pull_request: + branches: [main, int, dev] workflow_dispatch: concurrency: @@ -12,6 +14,7 @@ concurrency: jobs: # --- JOB DI ANALISI (In parallelo) --- qodana: + if: ${{ gitea.event_name == 'pull_request' }} runs-on: ubuntu-latest steps: - name: Checkout @@ -19,11 +22,19 @@ jobs: with: fetch-depth: 0 # Fondamentale per Qodana per analizzare la storia + - name: Prepare Qodana directories + shell: bash + run: | + mkdir -p .qodana/caches .qodana/results + - name: 'Qodana Scan' uses: JetBrains/qodana-action@v2025.3 env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} with: + cache-dir: .qodana/caches + results-dir: .qodana/results + args: -i,backend # In Gitea, pr-mode funziona se il runner ha accesso ai dati del clone pr-mode: ${{ gitea.event_name == 'pull_request' }} use-caches: false @@ -32,6 +43,7 @@ jobs: post-pr-comment: false use-annotations: true test-backend: + if: ${{ gitea.event_name == 'pull_request' }} runs-on: ubuntu-latest steps: - name: Checkout @@ -50,7 +62,7 @@ jobs: ./gradlew test build-and-push: - needs: test-backend + if: ${{ gitea.event_name == 'push' || gitea.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest steps: - name: Checkout @@ -101,6 +113,7 @@ jobs: deploy: needs: build-and-push + if: ${{ gitea.event_name == 'push' || gitea.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest steps: - name: Checkout