Files
adsPRO/.paul/phases/03-products-all-campaigns-view/03-01-PLAN.md
2026-04-24 23:37:47 +02:00

12 KiB
Raw Blame History

phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
phase plan type wave depends_on files_modified autonomous delegation
03-products-all-campaigns-view 01 execute 1
templates/products/main_view.php
false off
## Goal Przywrócić na stronie `/products` możliwość wyboru widoku "wszystkie kampanie" (agregacji) po wcześniejszym wybraniu konkretnej kampanii w filtrze `#products_campaign_id`. Analogicznie dla filtru grup reklam `#products_ad_group_id`.

Purpose

Obecnie po wybraniu dowolnej kampanii użytkownik nie widzi już opcji "- wszystkie kampanie -" w rozwijanej liście i nie może wrócić do widoku zbiorczego (ani zrestartować filtra grupy reklam). Jedynym sposobem jest zmiana klienta albo ręczne wyczyszczenie localStorage. To psuje podstawowy przepływ pracy na liście produktów.

Output

Zmodyfikowany plik templates/products/main_view.php — zmiana konfiguracji Select2 w init_products_scope_select_search() tak, aby opcja z pustą wartością ("- wszystkie kampanie -" / "- wszystkie grupy -") była stale widoczna w rozwijanej liście i dała się kliknąć w dowolnym momencie.

## Project Context @.paul/STATE.md @CLAUDE.md

Source Files

@templates/products/main_view.php @autoload/controls/class.Products.php @autoload/factory/class.Products.php

Prior Work

Nie wymaga wczytywania poprzednich SUMMARY — ten plan nie jest zależny od milestone'a CL1. Dotyczy innej warstwy (UI filtra) tej samej strony /products, co plany 01-01 i 02-01.

Kluczowe fakty z analizy

  • Szablon templates/products/main_view.php już zawiera <option value="">- wszystkie kampanie -</option> (linia ~19) oraz <option value="">- wszystkie grupy -</option> (linia ~27).
  • init_products_scope_select_search() (linia ~510) inicjuje Select2 z placeholder: '- wybierz -' i allowClear: true. Zgodnie z zachowaniem Select2, opcja z pustą wartością jest traktowana jako placeholder i ukrywana z dropdownu, co uniemożliwia jej ponowne wybranie po zmianie selekcji.
  • Backend (factory\Products::build_scope_filters, linia 470) filtruje po kampanii / grupie reklam TYLKO gdy campaign_id > 0 / ad_group_id > 0. Pusty campaign_id już teraz daje widok zbiorczy — zmiana wyłącznie po stronie JS.
  • AJAX DataTable (/products/get_products/, linia ~537) wysyła d.campaign_id = $('#products_campaign_id').val() || '' — pusty string trafia do kontrolera, (int)'' = 0, więc zagregowany widok działa bez zmian w kontrolerze.
  • Pozostałe funkcje (load_scope_alerts, load_zero_impressions_products, update_delete_ad_group_button_state) poprawnie krótko-spięte dla pustego campaign_id — wyłączają swoje panele, co jest pożądanym zachowaniem w widoku zbiorczym.

<acceptance_criteria>

AC-1: Powrót do widoku "wszystkie kampanie" po wyborze kampanii

Given użytkownik jest na /products i wybrał klienta z co najmniej jedną kampanią
  And wybrał konkretną kampanię w filtrze "Kampania"
  And tabela produktów pokazuje wyniki przefiltrowane do tej kampanii
When użytkownik rozwija dropdown "Kampania"
Then w liście wyboru widzi pozycję "- wszystkie kampanie -"
  And po jej kliknięciu wartość `#products_campaign_id` staje się pusta
  And tabela `#products` przeładowuje się i pokazuje produkty ze wszystkich kampanii klienta (zagregowane po `products_aggregate` dla całego `client_id`)
  And panele boczne "Produkty do sprawdzenia" oraz alerty zakresu (scope alerts) są ukryte (bo wymagają konkretnej kampanii)

AC-2: Powrót do widoku "wszystkie grupy" po wyborze grupy reklam

Given użytkownik ma wybraną kampanię oraz konkretną grupę reklam w filtrze "Grupa reklam"
When użytkownik rozwija dropdown "Grupa reklam"
Then w liście wyboru widzi pozycję "- wszystkie grupy -"
  And po jej kliknięciu wartość `#products_ad_group_id` staje się pusta
  And tabela `#products` przeładowuje się i pokazuje produkty ze wszystkich grup reklam wybranej kampanii
  And przycisk "Usuń grupę reklam" (`#delete-products-ad-group`) jest nieaktywny

AC-3: Stan zachowany w localStorage po odświeżeniu strony

Given użytkownik wrócił do "wszystkich kampanii" (pusty `#products_campaign_id`)
When odświeży stronę (`F5`)
Then filtr "Kampania" pokazuje "- wszystkie kampanie -" jako aktualną wartość
  And filtr "Grupa reklam" pokazuje "- wszystkie grupy -"
  And tabela `#products` od razu ładuje zagregowany widok bez błędów konsoli

AC-4: Brak regresji dla istniejących ścieżek

Given strona /products po zmianie
When użytkownik wybierze klienta → kampanię → grupę reklam → produkt
Then wszystkie istniejące przepływy działają jak dotychczas:
  - filtry tekstowe (search, CL1, CL4) aktualizują tabelę
  - sortowanie kolumn, paginacja DataTables działają
  - edycja `custom_label_1` / `custom_label_4`, `min_roas` zapisuje się
  - "Usuń grupę reklam" działa wyłącznie dla kampanii SHOPPING z wybraną grupą
  - brak regresji w alertach zakresu i panelu "Produkty do sprawdzenia"

</acceptance_criteria>

Task 1: Naprawa konfiguracji Select2 w init_products_scope_select_search() templates/products/main_view.php W funkcji `init_products_scope_select_search()` (około linii 510527) zmień konfigurację Select2 dla selektorów `#products_campaign_id` i `#products_ad_group_id`, aby opcja z pustą wartością była dostępna do wyboru w dropdownie.
Zmiana:
- Usuń parametry `placeholder: '- wybierz -'` oraz `allowClear: true`. Select2 bez `placeholder` nie promuje pierwszej pustej opcji do roli placeholdera — dzięki czemu `<option value="">- wszystkie kampanie -</option>` (i odpowiednio "- wszystkie grupy -") pozostaje normalną pozycją listy, klikalną po selekcji innej opcji.
- Pozostaw `width: '100%'` oraz `data( 'products-select2-ready', true )` bez zmian.
- Nie dodawaj `minimumResultsForSearch` — domyślna wyszukiwarka wewnątrz dropdownu dalej jest pożądana przy większej liczbie kampanii.

Dlaczego dokładnie tak:
- Dokumentacja Select2: "If you do not specify a placeholder, a clear option will not be shown" — usunięcie placeholdera jest jednym krokiem, który przywraca widoczność pustej opcji i zarazem neutralizuje wymóg `allowClear`.
- Nie trzeba zmieniać wartości `<option value="">` w HTML-u, ponieważ reszta JS-a (`$('#products_campaign_id').val() || ''`, `load_products_ad_groups`, `load_scope_alerts`, `localStorage.setItem`) traktuje pusty string jako "wszystkie" i działa poprawnie.

Czego unikać:
- Nie wprowadzaj `value="0"` dla opcji "wszystkie" — dodałoby to niepotrzebną gałąź w logice porównań w `load_products_campaigns` (`if (selected_campaign_id && ...)`) i mogłoby namieszać w `get_selected_products_campaign_channel_type`.
- Nie zmieniaj handlerów `change` (`#client_id`, `#products_campaign_id`, `#products_ad_group_id`) — ich aktualne zachowanie przy pustej wartości jest już poprawne (czyszczą localStorage grupy, przeładowują tabelę, chowają panele boczne).
- Nie ruszaj `load_products_campaigns()` / `load_products_ad_groups()` — już dzisiaj same dodają `.append('<option value="">…</option>')` przy każdym przeładowaniu.
1. Otwórz plik `templates/products/main_view.php`, znajdź funkcję `init_products_scope_select_search` — potwierdź, że blok `$select.select2({...})` zawiera tylko `width: '100%'`. 2. `php -l "templates/products/main_view.php"` → "No syntax errors detected". 3. Szybki `grep -n "placeholder: '- wybierz -'" templates/products/main_view.php` → brak wyników. 4. Szybki `grep -n "allowClear" templates/products/main_view.php` → brak wyników. AC-1, AC-2 i AC-4 satysfakcjonowalne: opcja "wszystkie kampanie/grupy" widoczna w dropdownie po każdej selekcji; reszta przepływu bez regresji. Naprawa filtra kampanii i grup reklam na stronie /products: przywrócenie widoczności opcji "- wszystkie kampanie -" oraz "- wszystkie grupy -" w rozwijanej liście Select2 po wcześniejszej selekcji konkretnej wartości. 1. Wdróż zmianę na `https://adspro.projectpro.pl` (lub lokalne środowisko z tą bazą). 2. Otwórz `https://adspro.projectpro.pl/products` (Hard Reload: Ctrl+Shift+R, aby odświeżyć cache JS). 3. Wybierz klienta, który ma co najmniej 2 kampanie Shopping/PMax z produktami. 4. AC-1: Rozwiń filtr "Kampania", wybierz konkretną kampanię → tabela pokazuje produkty tej kampanii. Rozwiń filtr ponownie → pierwsza pozycja listy to "- wszystkie kampanie -". Kliknij ją → tabela przeładowuje się i pokazuje zagregowane produkty wszystkich kampanii klienta; panele "Produkty do sprawdzenia" i alerty są ukryte. 5. AC-2: Wybierz kampanię → wybierz konkretną grupę reklam → tabela ją filtruje. Rozwiń filtr "Grupa reklam" → pozycja "- wszystkie grupy -" jest widoczna i klikalna; po wybraniu tabela wraca do widoku wszystkich grup kampanii, a przycisk "Usuń grupę reklam" jest wyszarzony. 6. AC-3: Ustaw filtr w trybie "wszystkie kampanie" → wykonaj F5. Po reloadzie dropdowny pokazują "- wszystkie kampanie -" / "- wszystkie grupy -" i tabela ładuje zagregowany widok bez błędów w konsoli (F12 → Console). 7. AC-4 (regresje): - Wyszukiwarka (`#products_search`) + filtry CL1/CL4 działają w widoku "wszystkich kampanii" oraz w widoku konkretnej kampanii. - Sortowanie kolumn (np. ROAS, clicks_30) + paginacja DataTables nie wyrzucają błędów. - Edycja inline `custom_label_1`, `custom_label_4` i `min_roas` poprawnie zapisuje wartości. - "Usuń grupę reklam" działa dla kampanii SHOPPING z wybraną grupą. 8. Sprawdź konsolę przeglądarki — nie powinno być błędów `Select2: The placeholder must be specified...` ani innych ostrzeżeń Select2. Wpisz "approved" aby zamknąć plan, albo opisz problem do naprawienia (nowe odchylenie).

DO NOT CHANGE

  • autoload/controls/class.Products.php — kontroler już poprawnie obsługuje pusty campaign_id / ad_group_id.
  • autoload/factory/class.Products.php (w tym build_scope_filters, get_products, get_records_total_products, get_roas_bounds) — logika agregacji dla client_id bez filtrów kampanii jest sprawdzona i nie wymaga zmian.
  • HTML strony (sekcje <select id="products_campaign_id"> i <select id="products_ad_group_id">) — istniejące opcje <option value="">…</option> pozostają.
  • Handlery change dla #client_id, #products_campaign_id, #products_ad_group_id — ich logika z pustą wartością jest już poprawna.
  • load_products_campaigns(), load_products_ad_groups(), load_scope_alerts(), load_zero_impressions_products() — bez zmian.
  • localStorage keys (products_campaign_id, products_ad_group_id) — zachowujemy istniejący format (pusty string = "wszystkie").
  • Migracje SQL — brak zmian w schemacie.

SCOPE LIMITS

  • Nie dodajemy nowych filtrów na stronie /products.
  • Nie zmieniamy stylistyki Select2 (CSS .products-page .select2-*).
  • Nie wprowadzamy sentineli 0/all dla wartości "wszystkie" — świadomy wybór, żeby minimalizować blast radius.
  • Nie dotykamy widoku products/product_history.php ani analogicznych filtrów na innych stronach (np. /campaigns).
Przed uznaniem planu za zamknięty: - [ ] `php -l templates/products/main_view.php` → no syntax errors - [ ] `grep -n "placeholder: '- wybierz -'" templates/products/main_view.php` → brak trafień - [ ] `grep -n "allowClear" templates/products/main_view.php` → brak trafień - [ ] Brak błędów w konsoli przeglądarki na /products po zmianie - [ ] Checkpoint human-verify odhaczony (AC-1…AC-4 zweryfikowane ręcznie)

<success_criteria>

  • Użytkownik może z dowolnej selekcji w filtrze "Kampania" wrócić do widoku zbiorczego "- wszystkie kampanie -" jednym kliknięciem w dropdown.
  • To samo dla filtra "Grupa reklam".
  • Brak regresji w istniejących przepływach edycji, sortowania, usuwania grup reklam, AI suggestions, merchant sync i filtrów tekstowych.
  • Zmiana ograniczona do jednego pliku (templates/products/main_view.php), bez nowych zależności, bez migracji DB. </success_criteria>
Po zakończeniu utwórz `.paul/phases/03-products-all-campaigns-view/03-01-SUMMARY.md` opisujący faktyczne zmiany (diff + ew. odchylenia od planu) i wynik testów manualnych z `checkpoint:human-verify`.