From 9577d4944a6f1d980fbe018ad3a1a29d6715888b Mon Sep 17 00:00:00 2001 From: Jacek Date: Sun, 19 Apr 2026 11:09:19 +0200 Subject: [PATCH] feat: custom labels toggle and inline editing in product list Adds session-based show/hide toggle for custom labels in admin product list, inline editable fields for custom_label_0..4, and label suggestions with custom entry support. Includes repository/controller updates, UI fixes, tests, and PAUL docs release updates. Co-Authored-By: Claude Opus 4.6 --- .paul/PROJECT.md | 6 +- .paul/ROADMAP.md | 13 +- .paul/STATE.md | 34 +-- .paul/changelog/2026-04-19.md | 22 ++ .paul/codebase/testing.md | 43 ++-- .paul/docs/TECH_CHANGELOG.md | 9 + .paul/docs/TODO.md | 78 +++++++ .../16-01-PLAN.md | 201 ++++++++++++++++++ .../16-01-SUMMARY.md | 149 +++++++++++++ .../products-list-custom-script.php | 159 ++++++++++++++ .../templates/shop-product/products-list.php | 1 + autoload/Domain/Product/ProductRepository.php | 38 ++++ .../Controllers/ShopProductController.php | 72 ++++++- .../Domain/Product/ProductRepositoryTest.php | 51 +++++ .../Controllers/ShopProductControllerTest.php | 22 ++ 15 files changed, 856 insertions(+), 42 deletions(-) create mode 100644 .paul/changelog/2026-04-19.md create mode 100644 .paul/phases/16-product-list-custom-labels/16-01-PLAN.md create mode 100644 .paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index ac8bf0a..e0eac56 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -14,7 +14,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online - |-----------|-------| | Version | 0.333 | | Status | Production | -| Last Updated | 2026-04-18 | +| Last Updated | 2026-04-19 | ## Requirements @@ -30,6 +30,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online - - [x] Redis caching - [x] Ochrona przed podwójnym składaniem zamówienia - [x] Domain-Driven Architecture (migracja z legacy zakończona) +- [x] Szybka edycja custom_label_0..4 na liscie produktow admina (toggle sesyjny + autocomplete) ### Active (In Progress) @@ -79,6 +80,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online - | PHP < 8.0 kompatybilność | Klienci na starszych serwerach | 2025 | Active | | Własny silnik zamiast frameworka | Pełna kontrola, brak narzutów | - | Active | | `id` w tabbed FormEdit przez `hiddenFields` | Zapobiega insert zamiast update przy edycji encji | 2026-04-18 | Active | +| Inline custom labels w product list przez sesyjny toggle | Szybszy workflow dla Google XML bez wejscia w edycje produktu | 2026-04-19 | Active | ## Success Metrics @@ -113,4 +115,4 @@ Quick Reference: --- *PROJECT.md - Updated when requirements or context change* -*Last updated: 2026-04-18 after Phase 15* +*Last updated: 2026-04-19 after Phase 16* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index ece845e..fc9cb7d 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -6,9 +6,9 @@ shopPRO to autorski silnik sklepu internetowego rozwijany iteracyjnie. Projekt j ## Current Milestone -**Hotfix backlog** +**Feature — Product list custom labels quick edit** Status: Complete -Phases: 4 of 4 complete +Phases: 1 of 1 complete ## Phases @@ -47,6 +47,7 @@ Status: Planning | 12 | summaryView redirect fix — double order block | 1 | Done | 2026-03-25 | | 13 | Basket logging + TTL token fix | 1 | Done | 2026-03-25 | | 14 | Custom fields delete bug — usunięcie wszystkich pól | 1 | Done | 2026-04-16 | +| 16 | Product list custom labels quick edit | 1 | Done | 2026-04-19 | ## Phase Details @@ -111,5 +112,11 @@ Status: Planning **Scope:** Poprawić przekazywanie `id` w nowym flow formularza ScontainersController + dodać test regresyjny dla edycji, bez zmian globalnych w innych kontrolerach. +### Phase 16 - Product list custom labels quick edit + +**Problem:** Na liscie produktow brakuje szybkiego trybu uzupelniania `custom_label_0..4`. Administrator musi wchodzic do edycji produktu, co spowalnia uzupelnianie danych Google XML. + +**Scope:** Dodac przycisk "Pokaz etykiety niestandardowe" obok "Dodaj produkt", zapisywac jego stan w sesji, pokazac 5 pol custom label pod nazwa produktu, zapisac wartosci do bazy i zapewnic podpowiedzi z juz istniejacych wartosci. + --- -*Last updated: 2026-04-18* +*Last updated: 2026-04-19 (Phase 16 complete)* diff --git a/.paul/STATE.md b/.paul/STATE.md index 9ab4c52..43a6997 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,19 +5,19 @@ See: .paul/PROJECT.md (updated 2026-04-18) **Core value:** Właściciel sklepu ma pełną kontrolę nad sprzedażą online w jednym systemie pisanym od podstaw, bez narzutów zewnętrznych platform. -**Current focus:** Phase 15 complete - loop closed (scontainers edit save fix) +**Current focus:** Phase 16 complete - loop closed ## Current Position -Milestone: Hotfix -Phase: 15 of 15 (Scontainers edit save fix) - Complete -Plan: 15-01 complete -Status: UNIFY complete, ready for next planning loop -Last activity: 2026-04-18 - Closed loop for .paul/phases/15-scontainers-edit-save-fix/15-01-PLAN.md +Milestone: Feature +Phase: 16 of 16 (Product list custom labels quick edit) - Complete +Plan: 16-01 complete +Status: UNIFY complete, ready for next PLAN loop +Last activity: 2026-04-19 - Closed loop for .paul/phases/16-product-list-custom-labels/16-01-PLAN.md Progress: - Milestone: [##########] 100% -- Phase 15: [##########] 100% +- Phase 16: [##########] 100% ## Loop Position @@ -41,10 +41,18 @@ Phase 12: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-03-25] Phase 13: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-03-25] Phase 14: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-16] Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18] +Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19] ``` ## Accumulated Context ### Decisions +- 2026-04-19: Created Phase 16 plan at .paul/phases/16-product-list-custom-labels/16-01-PLAN.md +- 2026-04-19: Phase 16 scope includes session toggle + inline custom_label_0..4 edit + suggestions on product list +- 2026-04-19: Override approved by user - proceeded without required /feature-dev skill in Phase 16 APPLY +- 2026-04-19: /koniec-pracy acknowledged by user as available for session close workflow +- 2026-04-19: Human verify checkpoint approved after UX fixes (button style + autocomplete in single input) +- 2026-04-19: Product list custom labels final UX: single input with autocomplete, no separate select under field +- 2026-04-19: Transition-phase git commit for Phase 16 not executed in this UNIFY run - 2026-04-18: Transition-phase git commit step pending (not executed during this UNIFY run) - 2026-04-18: Phase 15 loop closed with SUMMARY at .paul/phases/15-scontainers-edit-save-fix/15-01-SUMMARY.md - 2026-04-18: Override - proceeded without required /feature-dev skill for Phase 15 APPLY @@ -74,17 +82,17 @@ None. ### Blockers/Concerns None. -### Skill Audit (Phase 15) +### Skill Audit (Phase 16) | Expected | Invoked | Notes | |----------|---------|-------| | /feature-dev | ○ | User-approved override during APPLY | -| /koniec-pracy | ○ | Mapped to `.claude/commands/koniec-pracy.md`; release flow not executed in this loop | +| /koniec-pracy | ○ | Marked as available by user; execute on session close workflow | ## Session Continuity -Last session: 2026-04-18 -Stopped at: Phase 15 complete, loop closed -Next action: Start next work with $paul-plan (or run /koniec-pracy for release flow) -Resume file: .paul/phases/15-scontainers-edit-save-fix/15-01-SUMMARY.md +Last session: 2026-04-19 +Stopped at: Phase 16 complete, loop closed +Next action: Start next milestone or create next phase plan +Resume file: .paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md --- *STATE.md — Updated after every significant action* diff --git a/.paul/changelog/2026-04-19.md b/.paul/changelog/2026-04-19.md new file mode 100644 index 0000000..484dcdf --- /dev/null +++ b/.paul/changelog/2026-04-19.md @@ -0,0 +1,22 @@ +# 2026-04-19 + +## Co zrobiono + +- [Phase 16, Plan 01] Dodano szybka edycje custom_label_0..4 w `/admin/shop_product/view_list/` z przelacznikiem sesyjnym. +- Dodano zapis wartosci custom labels do bazy oraz walidacje dozwolonych `label_type` po stronie kontrolera. +- Dodano podpowiedzi istniejacych wartosci jako autocomplete w jednym input (z mozliwoscia wpisania wartosci wlasnej). +- Poprawiono UX przycisku toggla (kolorystyka, rozmiar, hover i czytelnosc). +- Rozszerzono testy jednostkowe kontrolera i repozytorium dla nowej funkcjonalnosci. + +## Zmienione pliki + +- `autoload/admin/Controllers/ShopProductController.php` +- `autoload/Domain/Product/ProductRepository.php` +- `admin/templates/shop-product/products-list.php` +- `admin/templates/shop-product/products-list-custom-script.php` +- `tests/Unit/admin/Controllers/ShopProductControllerTest.php` +- `tests/Unit/Domain/Product/ProductRepositoryTest.php` +- `.paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md` +- `.paul/PROJECT.md` +- `.paul/ROADMAP.md` +- `.paul/STATE.md` diff --git a/.paul/codebase/testing.md b/.paul/codebase/testing.md index 3783f32..7a67a5b 100644 --- a/.paul/codebase/testing.md +++ b/.paul/codebase/testing.md @@ -1,11 +1,11 @@ -# Testing Patterns +# Testing Patterns ## Overview | Metric | Value | |--------|-------| -| Total tests | **810** | -| Total assertions | **2264** | +| Total tests | **828** | +| Total assertions | **2306** | | Framework | PHPUnit 9.6 (`phpunit.phar`) | | Bootstrap | `tests/bootstrap.php` | | Config | `phpunit.xml` | @@ -13,7 +13,7 @@ ## Running Tests ```bash -# Full suite (PowerShell — recommended) +# Full suite (PowerShell — recommended) ./test.ps1 # Specific file @@ -36,16 +36,16 @@ Tests mirror source structure: ``` tests/Unit/ -├── Domain/ -│ ├── Product/ProductRepositoryTest.php -│ ├── Category/CategoryRepositoryTest.php -│ ├── Order/OrderRepositoryTest.php -│ └── ... (all 29 modules covered) -├── admin/Controllers/ -│ ├── ShopCategoryControllerTest.php -│ └── ... -└── api/ - └── ... +├── Domain/ +│ ├── Product/ProductRepositoryTest.php +│ ├── Category/CategoryRepositoryTest.php +│ ├── Order/OrderRepositoryTest.php +│ └── ... (all 29 modules covered) +├── admin/Controllers/ +│ ├── ShopCategoryControllerTest.php +│ └── ... +└── api/ + └── ... ``` ## Test Class Pattern @@ -229,13 +229,13 @@ $this->assertInstanceOf(ClassName::class, $obj); ## What's Covered -- All 29 Domain repositories ✓ -- Core business logic (quantity, pricing, category tree) ✓ -- Query behavior with mocked Medoo ✓ -- Cache patterns ✓ -- Controller constructor injection ✓ -- `FormValidator` behavior ✓ -- API controllers ✓ +- All 29 Domain repositories âś“ +- Core business logic (quantity, pricing, category tree) âś“ +- Query behavior with mocked Medoo âś“ +- Cache patterns âś“ +- Controller constructor injection âś“ +- `FormValidator` behavior âś“ +- API controllers âś“ ## What's Lightly Covered @@ -243,3 +243,4 @@ $this->assertInstanceOf(ClassName::class, $obj); - Session state in tests - AJAX response integration - Frontend Views (static classes) + diff --git a/.paul/docs/TECH_CHANGELOG.md b/.paul/docs/TECH_CHANGELOG.md index 861d346..e502711 100644 --- a/.paul/docs/TECH_CHANGELOG.md +++ b/.paul/docs/TECH_CHANGELOG.md @@ -1,3 +1,12 @@ # TECH_CHANGELOG > Chronologiczny log zmian technicznych — co i dlaczego. + +## v0.348 (2026-04-19) + +- Dodano przełącznik widoczności etykiet niestandardowych na liście produktów w panelu admina, z zapisem stanu w sesji. +- Po włączeniu opcji renderowane jest 5 pól custom_label_0..4 bezpośrednio pod sekcją zdjęcie/nazwa produktu. +- Dodano zapisywanie wartości etykiet niestandardowych do bazy oraz walidację dozwolonych typów etykiet po stronie kontrolera. +- Wprowadzono podpowiedzi istniejących wartości jako wybieralne sugestie z możliwością wpisania własnej wartości. +- Rozszerzono testy jednostkowe dla ShopProductController i ProductRepository pod nową funkcjonalność. + diff --git a/.paul/docs/TODO.md b/.paul/docs/TODO.md index c4a2aed..f9811d5 100644 --- a/.paul/docs/TODO.md +++ b/.paul/docs/TODO.md @@ -3608,3 +3608,81 @@ Dodać możliwość ustawienia limitu znaków w wiadomościach do produktu - [ ] [MINOR] templates/wiki/main-view.php:77 Replace "and" with "&&". (php:S2010) - [ ] [MINOR] templates/wiki/main-view.php:85 Anchors must have content and the content must be accessible by a screen reader. (Web:S6827) + +## SonarQube - 0.348 (2026-04-19) + +### Code Smells + +- [ ] [CRITICAL] autoload/admin/Controllers/ShopProductController.php:109 - Define a constant instead of duplicating this literal "" value="" 4 times. (php:S1192) +- [ ] [CRITICAL] autoload/admin/Controllers/ShopProductController.php:39 - Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/admin/Controllers/ShopProductController.php:713 - Define a constant instead of duplicating this literal " selected" 3 times. (php:S1192) +- [ ] [CRITICAL] autoload/admin/Controllers/ShopProductController.php:788 - Define a constant instead of duplicating this literal "Produkt został zapisany." 3 times. (php:S1192) +- [ ] [CRITICAL] autoload/admin/Controllers/ShopProductController.php:809 - Define a constant instead of duplicating this literal "Location: /admin/shop_product/view_list/" 3 times. (php:S1192) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2303 - Refactor this function to reduce its Cognitive Complexity from 21 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2329 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2384 - Define a constant instead of duplicating this literal "in stock" 6 times. (php:S1192) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2387 - Define a constant instead of duplicating this literal "out of stock" 3 times. (php:S1192) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2417 - Refactor this function to reduce its Cognitive Complexity from 17 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:2899 - Refactor this function to reduce its Cognitive Complexity from 38 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3061 - Refactor this function to reduce its Cognitive Complexity from 62 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3158 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3159 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3160 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3161 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3178 - Refactor this function to reduce its Cognitive Complexity from 24 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3246 - Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3369 - Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3425 - Refactor this function to reduce its Cognitive Complexity from 18 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3439 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3510 - Add curly braces around the nested statement(s). (php:S121) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3521 - Refactor this function to reduce its Cognitive Complexity from 37 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3556 - Refactor this function to reduce its Cognitive Complexity from 75 to the 15 allowed. (php:S3776) +- [ ] [CRITICAL] autoload/Domain/Product/ProductRepository.php:3604 - Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed. (php:S3776) +- [ ] [MAJOR] autoload/admin/Controllers/ShopProductController.php:272 - This function "buildProductFormViewModel" has 281 lines, which is greater than the 150 lines authorized. Split it into smaller functions. (php:S138) +- [ ] [MAJOR] autoload/admin/Controllers/ShopProductController.php:272 - This function has 9 parameters, which is greater than the 7 authorized. (php:S107) +- [ ] [MAJOR] autoload/admin/Controllers/ShopProductController.php:39 - This function "view_list" has 151 lines, which is greater than the 150 lines authorized. Split it into smaller functions. (php:S138) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:2641 - This method has 4 returns, which is more than the 3 allowed. (php:S1142) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:2663 - This method has 4 returns, which is more than the 3 allowed. (php:S1142) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:2858 - Remove the unused function parameter "$limit". (php:S1172) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:2899 - This method has 4 returns, which is more than the 3 allowed. (php:S1142) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3029 - This method has 4 returns, which is more than the 3 allowed. (php:S1142) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3061 - This method has 4 returns, which is more than the 3 allowed. (php:S1142) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3435 - Extract this nested ternary operation into an independent statement. (php:S3358) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3544 - Extract this nested ternary operation into an independent statement. (php:S3358) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3564 - Extract this nested ternary operation into an independent statement. (php:S3358) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3591 - Extract this nested ternary operation into an independent statement. (php:S3358) +- [ ] [MAJOR] autoload/Domain/Product/ProductRepository.php:3592 - Extract this nested ternary operation into an independent statement. (php:S3358) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1004 - Rename function "generate_combination" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1025 - Rename function "delete_combination" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1040 - Rename function "product_combination_stock_0_buy_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1050 - Rename function "product_combination_sku_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1060 - Rename function "product_combination_quantity_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1070 - Rename function "product_combination_price_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1080 - Rename function "delete_combination_ajax" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1097 - Rename function "image_delete" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1112 - Rename function "images_order_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1124 - Rename function "image_alt_change" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1139 - Rename function "product_file_delete" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1154 - Rename function "product_file_name_change" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1169 - Rename function "product_image_delete" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1186 - Rename function "mass_edit" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1200 - Rename function "mass_edit_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1205 - Use empty() to check whether the array is empty or not. (php:S1155) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:1226 - Rename function "get_products_by_category" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:215 - Rename function "product_custom_labels_toggle" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:228 - Rename function "product_edit" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:39 - Rename function "view_list" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:801 - Rename function "duplicate_product" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:816 - Rename function "product_archive" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:831 - Rename function "product_unarchive" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:846 - Rename function "product_delete" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:861 - Rename function "change_product_status" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:874 - Rename function "product_change_price_brutto" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:889 - Rename function "product_change_price_brutto_promo" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:904 - Rename function "product_change_custom_label" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:919 - Rename function "product_custom_label_suggestions" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:941 - Rename function "product_custom_label_save" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:962 - Rename function "ajax_product_url" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:971 - Rename function "generate_sku_code" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) +- [ ] [MINOR] autoload/admin/Controllers/ShopProductController.php:989 - Rename function "product_combination" to match the regular expression ^[a-z][a-zA-Z0-9]*$. (php:S100) + diff --git a/.paul/phases/16-product-list-custom-labels/16-01-PLAN.md b/.paul/phases/16-product-list-custom-labels/16-01-PLAN.md new file mode 100644 index 0000000..4900214 --- /dev/null +++ b/.paul/phases/16-product-list-custom-labels/16-01-PLAN.md @@ -0,0 +1,201 @@ +--- +phase: 16-product-list-custom-labels +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - autoload/admin/Controllers/ShopProductController.php + - autoload/Domain/Product/ProductRepository.php + - admin/templates/shop-product/products-list-custom-script.php + - tests/Unit/admin/Controllers/ShopProductControllerTest.php + - tests/Unit/Domain/Product/ProductRepositoryTest.php +autonomous: false +delegation: off +--- + + +## Goal +Dodac w liscie produktow (`/admin/shop_product/view_list/`) przelacznik "Pokaz etykiety niestandardowe", ktory zapisuje stan w sesji i po wlaczeniu pokazuje szybka edycje 5 pol `custom_label_0..4` z podpowiedziami. + +## Purpose +Administrator ma szybciej uzupelniac etykiety Google XML bez wchodzenia do edycji kazdego produktu, z zachowaniem spojnosc danych i wygodnych podpowiedzi istniejacych wartosci. + +## Output +- Nowy przycisk obok "Dodaj produkt", sterujacy widocznoscia custom labels i zapisujacy stan w sesji +- Render 5 pol `custom_label_0..4` pod nazwa/SKU produktu w tabeli, tylko przy wlaczonej opcji +- Zapis kazdego pola do `pp_shop_products` oraz system podpowiedzi z istniejacych wartosci w bazie +- Odczyt nazw etykiet z bazy (z fallbackiem) zamiast hardcodu w widoku listy + + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md + +## Source Files +@autoload/admin/Controllers/ShopProductController.php +@autoload/Domain/Product/ProductRepository.php +@admin/templates/components/table-list.php +@admin/templates/shop-product/products-list.php +@admin/templates/shop-product/products-list-custom-script.php +@tests/Unit/admin/Controllers/ShopProductControllerTest.php +@tests/Unit/Domain/Product/ProductRepositoryTest.php + + + +## Required Skills (from SPECIAL-FLOWS.md) + +| Skill | Priority | When to Invoke | Loaded? | +|-------|----------|----------------|---------| +| /feature-dev | required | Before implementation in APPLY | ○ | +| /koniec-pracy | required | After implementation/release wrap-up | ○ | + +**BLOCKING:** Required skills MUST be loaded before APPLY proceeds. +Run each skill command or confirm already loaded. + +## Skill Invocation Checklist +- [ ] /feature-dev loaded (run command or confirm) +- [ ] /koniec-pracy loaded (run command or confirm) + + + + + +## AC-1: Przelacznik widocznosci custom labels dziala i jest zapamietywany +```gherkin +Given administrator jest na /admin/shop_product/view_list/ +When kliknie przycisk "Pokaz etykiety niestandardowe" +Then stan opcji zostanie zapisany w sesji +And po odswiezeniu/listowaniu tabela zachowa ustawiony stan (wlaczony lub wylaczony) +``` + +## AC-2: Lista produktow pokazuje 5 pol custom_label po wlaczeniu opcji +```gherkin +Given opcja "Pokaz etykiety niestandardowe" jest wlaczona +When lista produktow sie renderuje +Then pod sekcja zdjecie/nazwa/SKU-EAN dla kazdego produktu widoczne sa pola custom_label_0..custom_label_4 +And etykiety tych pol sa pobrane dynamicznie z bazy danych (z fallbackiem tylko gdy brak konfiguracji) +``` + +## AC-3: Zapis i podpowiedzi wartosci dzialaja dla kazdego custom_label +```gherkin +Given administrator wpisuje wartosc w jednym z pol custom_label_0..custom_label_4 +When wybierze podpowiedz lub zatwierdzi wpis +Then wartosc zostanie zapisana w pp_shop_products dla danego produktu i pola +And podpowiedzi sa budowane z juz istniejacych wartosci tego samego custom_label w bazie +``` + +## AC-4: Walidacja i bezpieczenstwo endpointow sa zachowane +```gherkin +Given zapytanie AJAX podaje nieprawidlowy typ labela spoza custom_label_0..4 +When backend przetwarza request +Then operacja zostaje odrzucona bez zapisu +And odpowiedz zwraca status bledu bez ingerencji w dane produktu +``` + + + + + + + Task 1: Dodac backend przelacznika sesyjnego i danych dla widoku listy + autoload/admin/Controllers/ShopProductController.php, autoload/Domain/Product/ProductRepository.php + + Rozszerzyc `ShopProductController::view_list()` o flage sesyjna dla widocznosci custom labels + oraz przekazanie do widoku nazw etykiet pobieranych z bazy. + + Dodac akcje kontrolera do przelaczania flagi (toggle) i zwracania prostego JSON. + + W `ProductRepository` dodac metode pobierajaca nazwy etykiet custom_label_0..4 z bazy + (np. tabela ustawien), z bezpiecznym fallbackiem "Custom label N" gdy wartosc nie istnieje. + Nie stosowac konkatenacji SQL dla danych wejsciowych. + + Uruchomic testy kontrolera/repo oraz sprawdzic recznie, ze zmiana flagi utrzymuje sie po reloadzie listy + AC-1 i AC-2 satisfied + + + + Task 2: Dodac UI i logike AJAX dla custom labels na liscie produktow + autoload/admin/Controllers/ShopProductController.php, admin/templates/shop-product/products-list-custom-script.php + + Wygenerowac HTML 5 pol custom_label pod kolumna nazwy produktu tylko gdy flaga sesyjna jest wlaczona. + Uzyc klas zgodnych z istniejacym stylem (`custom-labels`, `custom_label_X_container`, listy sugestii). + + Dodac przycisk "Pokaz etykiety niestandardowe" obok "Dodaj produkt" (hook przez custom script listy) + oraz obsluge klikniecia przez AJAX do nowej akcji toggle + odswiezenie aktualnego URL. + + Podlaczyc dla kazdego inputa: + - pobieranie sugestii przez `/admin/shop_product/product_custom_label_suggestions/` + - zapis przez `/admin/shop_product/product_custom_label_save/` + z walidacja odpowiedzi i obsluga bledow UI. + + Manual: wlaczyc opcje, wpisac i zapisac wartosc custom_label, odswiezyc strone, potwierdzic widocznosc i dane + AC-2 i AC-3 satisfied + + + + Task 3: Dodac testy regresyjne dla nowego zachowania + tests/Unit/admin/Controllers/ShopProductControllerTest.php, tests/Unit/Domain/Product/ProductRepositoryTest.php + + Rozszerzyc testy kontrolera o przypadki: + - toggle flagi sesyjnej + - odrzucenie nieprawidlowych typow labeli + - poprawne przekazanie danych do widoku listy przy wlaczonej opcji. + + Rozszerzyc testy repozytorium o: + - pobieranie nazw custom labels z bazy z fallbackiem + - sugestie i zapis tylko dla dozwolonych label_type. + + ./test.ps1 tests/Unit/admin/Controllers/ShopProductControllerTest.php oraz ./test.ps1 tests/Unit/Domain/Product/ProductRepositoryTest.php + AC-4 covered and AC-1..AC-3 protected by tests + + + + Nowy przycisk sesyjny + szybka edycja custom labels 0..4 z podpowiedziami na liscie produktow + + 1. Otworz: /admin/shop_product/view_list/ + 2. Kliknij: "Pokaz etykiety niestandardowe" + 3. Potwierdz: pola custom_label_0..4 pojawiaja sie pod nazwa produktu + 4. Wpisz wartosc, wybierz podpowiedz i odswiez strone + 5. Potwierdz: wartosc zostala zapisana i toggle pozostaje aktywny + + Type "approved" to continue, or describe issues to fix + + + + + + +## DO NOT CHANGE +- Globalnych komponentow listy niezwiązanych z produktami (`admin/templates/components/table-list.php`) poza minimalnym, koniecznym hookiem +- Endpointow API (`autoload/api/*`) +- Logiki produktow frontendowych (`autoload/front/*`, `templates/shop-product/*`) + +## SCOPE LIMITS +- Zakres ograniczony do admin listy produktow i quick-edit custom labels +- Bez migracji DB w tym planie (odczyt nazw z istniejacych danych konfiguracyjnych) +- Bez refaktoru calego modułu integracji Google XML + + + + +Before declaring plan complete: +- [ ] ./test.ps1 tests/Unit/admin/Controllers/ShopProductControllerTest.php +- [ ] ./test.ps1 tests/Unit/Domain/Product/ProductRepositoryTest.php +- [ ] Manual check: toggle zapisuje sie w sesji i zachowuje po reloadzie +- [ ] Manual check: podpowiedzi i zapis custom labels dzialaja dla 0..4 +- [ ] All acceptance criteria met + + + +- Przycisk "Pokaz etykiety niestandardowe" dziala i przechowuje stan w sesji +- Lista produktow pokazuje i zapisuje custom_label_0..4 bez wejscia w edycje produktu +- Nazwy etykiet sa pobierane z bazy z fallbackiem +- Testy regresyjne dla backendu i repozytorium przechodza + + + +After completion, create `.paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md` + diff --git a/.paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md b/.paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md new file mode 100644 index 0000000..fd9055c --- /dev/null +++ b/.paul/phases/16-product-list-custom-labels/16-01-SUMMARY.md @@ -0,0 +1,149 @@ +--- +phase: 16-product-list-custom-labels +plan: 01 +subsystem: admin +tags: [shop-product, custom-label, session-toggle, autocomplete, quick-edit] + +requires: [] +provides: + - Szybka edycja custom_label_0..4 na liscie produktow + - Przelacznik widocznosci etykiet w sesji admina + - Podpowiedzi istniejacych wartosci + wpisywanie wartosci wlasnej w jednym polu +affects: [shop-product-list, google-xml-label-flow] + +tech-stack: + added: [] + patterns: [inline quick-edit in table list, datalist autocomplete in single input, settings fallback mapping] + +key-files: + created: [] + modified: + - autoload/admin/Controllers/ShopProductController.php + - autoload/Domain/Product/ProductRepository.php + - admin/templates/shop-product/products-list.php + - admin/templates/shop-product/products-list-custom-script.php + - tests/Unit/admin/Controllers/ShopProductControllerTest.php + - tests/Unit/Domain/Product/ProductRepositoryTest.php + +key-decisions: + - "Przelacznik widocznosci custom labels zapisany w sesji (per admin session)" + - "Nazwy custom labels pobierane z pp_settings z fallbackiem do domyslnych nazw" + - "UX: jedno pole input z autocomplete (datalist), bez osobnego select pod spodem" + +patterns-established: + - "Dla list admina: toggle funkcji przez dedykowany endpoint JSON + reload widoku" + - "Quick-edit text fields: walidacja typu po stronie kontrolera przed zapisem/sugestiami" + +duration: ~120min +completed: 2026-04-19 +--- + +# Phase 16 Plan 01: Product list custom labels quick edit - Summary + +**Wdrozono szybka edycje custom labels na liscie produktow z przelacznikiem sesyjnym i autocomplete w pojedynczym polu.** + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~120min | +| Completed | 2026-04-19 | +| Tasks | 3 completed + 1 checkpoint approved | +| Files modified | 6 | + +## Acceptance Criteria Results + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Przelacznik widocznosci custom labels dziala i jest zapamietywany | Pass | Dodano przycisk toggle + zapis stanu w sesji admina | +| AC-2: Lista pokazuje 5 pol custom_label po wlaczeniu opcji | Pass | Pola custom_label_0..4 renderowane pod nazwa/SKU/EAN tylko przy wlaczonej opcji | +| AC-3: Zapis i podpowiedzi wartosci dzialaja dla custom_label | Pass | Zapis AJAX do bazy + autocomplete istniejacych wartosci i mozliwosc wpisu wlasnego | +| AC-4: Walidacja i bezpieczenstwo endpointow zachowane | Pass | Kontroler odrzuca niedozwolone label_type przed zapisem i pobraniem sugestii | + +## Accomplishments + +- Dodano nowy toggle "Pokaz/Ukryj etykiety niestandardowe" przy liscie produktow, sterowany sesja. +- Dodano inline quick-edit custom_label_0..4 bez wchodzenia do edycji produktu. +- Podpowiedzi dzialaja jako autocomplete w tym samym input (nie osobny kontrolka pod polem). +- Ujednolicono UX przycisku toggle (kolorystyka, rozmiar, hover, czytelnosc). +- Rozszerzono testy kontrolera i repozytorium o nowe przypadki. + +## Files Created/Modified + +| File | Change | Purpose | +|------|--------|---------| +| `autoload/admin/Controllers/ShopProductController.php` | Modified | Toggle sesyjny, render custom labels w tabeli, walidacja label_type | +| `autoload/Domain/Product/ProductRepository.php` | Modified | Pobieranie nazw custom_label z ustawien (fallback) | +| `admin/templates/shop-product/products-list.php` | Modified | Przekazanie flagi custom_labels_enabled do skryptu | +| `admin/templates/shop-product/products-list-custom-script.php` | Modified | UI toggle, zapis/sugestie custom label, autocomplete, poprawki wygladu | +| `tests/Unit/admin/Controllers/ShopProductControllerTest.php` | Modified | Testy nowych metod i walidacji kontrolera | +| `tests/Unit/Domain/Product/ProductRepositoryTest.php` | Modified | Testy customLabelNames + walidacji sugestii/zapisu | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Session key dla toggla (`shop_product_show_custom_labels`) | Funkcja ma byc osobnym trybem widoku admina | Stabilny stan po odswiezeniu strony | +| Nazwy etykiet z `pp_settings` + fallback | Wymaganie "nazwy z bazy" i bezpieczne zachowanie gdy brak konfiguracji | Elastyczne nazewnictwo bez hardcodu | +| Autocomplete w jednym polu zamiast input + oddzielny select | UX feedback od usera podczas checkpointu | Czytelniejszy i szybszy flow edycji | + +## Deviations from Plan + +### Summary + +| Type | Count | Impact | +|------|-------|--------| +| Auto-fixed | 1 | Niski, techniczny (BOM w pliku kontrolera) | +| Scope additions | 2 | Niski, UX polish po feedbacku checkpoint | +| Deferred | 0 | Brak | + +**Total impact:** Niezbedne poprawki techniczne i UX bez scope creep funkcjonalnego. + +### Auto-fixed Issues + +**1. Encoding/BOM in controller file** +- **Found during:** Task 1 implementation verification +- **Issue:** Parser PHP zglaszal blad namespace przez BOM na poczatku pliku +- **Fix:** Zapisano plik `ShopProductController.php` jako UTF-8 bez BOM +- **Files:** `autoload/admin/Controllers/ShopProductController.php` +- **Verification:** `php -l autoload/admin/Controllers/ShopProductController.php` + +### Deferred Items + +None. + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Drobne regresje UX przycisku toggle | Iteracyjna poprawka stylu i hover po feedbacku usera | +| Forma podpowiedzi (select pod inputem) nieakceptowalna UX | Zmieniono na jedno pole z autocomplete (datalist) | + +## Verification Results + +- `php -l autoload/admin/Controllers/ShopProductController.php` -> OK +- `php -l autoload/Domain/Product/ProductRepository.php` -> OK +- `php -l admin/templates/shop-product/products-list-custom-script.php` -> OK +- `php phpunit.phar tests/Unit/admin/Controllers/ShopProductControllerTest.php` -> OK (15 tests, 71 assertions) +- `php phpunit.phar tests/Unit/Domain/Product/ProductRepositoryTest.php` -> OK (64 tests, 131 assertions) +- Checkpoint human-verify: approved by user after final UX adjustments + +Skill audit: +- `/feature-dev` - not invoked (user-approved override) +- `/koniec-pracy` - acknowledged by user as available for end-of-session flow + +## Next Phase Readiness + +**Ready:** +- Admin ma szybki i praktyczny workflow uzupelniania custom labels bez przechodzenia do edycji produktu. +- Kod posiada testy regresyjne dla nowej logiki backendowej. + +**Concerns:** +- Brak. + +**Blockers:** +- None. + +--- +*Phase: 16-product-list-custom-labels, Plan: 01* +*Completed: 2026-04-19* diff --git a/admin/templates/shop-product/products-list-custom-script.php b/admin/templates/shop-product/products-list-custom-script.php index 7830c84..b379ee9 100644 --- a/admin/templates/shop-product/products-list-custom-script.php +++ b/admin/templates/shop-product/products-list-custom-script.php @@ -1,3 +1,20 @@ +custom_labels_enabled ); ?> + + + shoppro_enabled ):?>