--- phase: 03-products-all-campaigns-view plan: 01 type: execute wave: 1 depends_on: [] files_modified: - templates/products/main_view.php autonomous: false delegation: 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 `` (linia ~19) oraz `` (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. ## AC-1: Powrót do widoku "wszystkie kampanie" po wyborze kampanii ```gherkin 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 ```gherkin 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 ```gherkin 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 ```gherkin 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" ``` 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 510–527) 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 `` (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 `')` 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 ``) — istniejące opcje `` 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) - 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. 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`.