Priorytety
View on GitHubPriorytety
Priorytet issue'a to zasób per-projekt, oparty na prawdziwej tabeli
bazodanowej priorities (App\Models\Priority) — a nie na sztywnym
enumie low / medium / high, którym był wcześniej. Każdy projekt
dostaje startową skalę trzech priorytetów (High, Medium, Low),
zasiewaną leniwie przy pierwszej potrzebie, a każdy, kto ma odpowiednie
uprawnienie, może zmienić nazwę, kolor, ikonę, kolejność, dodać, usunąć
lub zmienić domyślność dowolnego z nich — również tych zasianych — z
poziomu Ustawienia → Priorities.
Przewodniki, w kolejności, w jakiej naprawdę byś ich potrzebował
- Zmień startowe priorytetyPriorytetyZmień startowe priorytetyPrzećwiczony przykład: dodanie czwartego startowego priorytetu, Urgent, ponad trzema, które dostaje każdy projekt (High, Medium, Low). Edycja SYSTEMPRIORIT… —
przećwiczony przykład dodania czwartego startowego priorytetu,
Urgent, do skali, jaką dostaje każdy nowy projekt, wraz z migracją danych, która dociąga projekty już zasiane, oraz testami do zaktualizowania. - Pokaż priorytety na nowej stroniePriorytetyPokaż priorytety na nowej stroniePrzećwiczony przykład: hipotetyczna jednoprojektowa strona Triage, która listuje issue'y projektu od najważniejszego, rysuje prawdziwą ikonę i kolor priory… —
przećwiczony przykład podpięcia prawdziwych priorytetów projektu
(kolory, ikony, kolejność, filtr, sortowanie) do zupełnie nowej
strony jednoprojektowej, na przykładzie hipotetycznej strony
Triage, zbudowanej w kształcie istniejącej stronyProjects/Show. Nigdy więcej nie hardcodujlow/medium/high.
Architektura w jednym akapicie
priorities (migracja 2026_10_18_100000_create_priorities_table.php)
ma kolumny project_id, name, color (6-cyfrowy hex), icon (nazwa
ikony z lucide-react), position, is_default, z unikalnością na
(project_id, name). App\Repositories\PriorityRepository i
App\Services\PriorityService idą za zwykłym podziałem Controller →
Service → Repository (zobacz
../architecture/02-backend-layered-architecture.mdArchitektura i technikalia projektuWarstwowa architektura backenduController → Service → Repository, bez wyjątków i bez skrótów — kontroler nigdy nie buduje zapytania Eloquent, a repozytorium nigdy nie zawiera logiki bizn…):
PriorityService::ensureSystemPriorities() zasiewa
PriorityService::SYSTEM_PRIORITIES — jedyne źródło startowej skali:
High (#f44336, SignalHigh), Medium (domyślny, #ff9800,
SignalMedium) i Low (#4caf50, SignalLow) — dokładnie raz dla
danego projektu, śledzone przez znacznik czasu
projects.priorities_seeded_at, a nie "wstaw wszystko, czego brakuje"
przy każdym odczycie, co wskrzeszałoby priorytet, który właściciel
świadomie usunął. Potem każdy priorytet jest edytowalny i usuwalny, a
lista nigdy nie jest już uzupełniana.
App\Http\Controllers\PriorityController udostępnia
projects.priorities.store, .update, .destroy i .reorder
(PATCH /projects/{project}/priorities/order, body order = wszystkie
id projektu, od najważniejszego), zabezpieczone czterema uprawnieniami
projects.priorities.view / .create / .update / .delete przez
ProjectPolicy::viewPriorities() / createPriorities() /
updatePriorities() / deletePriorities() (Owner i Admin dostają
wszystkie cztery, Member i Viewer dostają view, jak w pozostałych
katalogach). Priorytet issue'a to issues.priority_id, nullowalny klucz
obcy do priorities z nullOnDelete; null oznacza "brak
priorytetu". Zapisujące nadal operują na nazwach priorytetów:
przypisanie priority na Issue (create(), update(), fabryki,
importy, szablony, automatyzacje) przechodzi przez
Issue::setPriorityAttribute(), który rozwiązuje nazwę bez
rozróżniania wielkości liter względem projektu samego issue'a i
zapisuje id przy zapisie issue'a; nazwa, której projekt nie ma, zostawia
priorytet bez zmian, jawny null go czyści, a nowe issue, któremu
nigdy nie nadano priorytetu, dostaje domyślny priorytet projektu (hook
creating w Issue::booted()). IssueController@store/@update
walidują nazwę przez App\Rules\ProjectPriorityName, więc nazwa
priorytetu z innego projektu jest odrzucana. Odczyt zachowuje stary
kontrakt i go rozszerza: Issue::$with = ['priority'] eager-loaduje
relację, a Issue::relationsToArray() serializuje priority jako
nazwę (albo null) i dodaje priorityDetails —
{id, name, color, icon, position} z Priority::toDetails() — dzięki
czemu wiersz może narysować swoją ikonę i kolor bez zaglądania do listy
projektu (której strona wieloprojektowa, jak dashboard, nie ma).
Filtrowanie odbywa się po id priorytetu: ?priority=1,3 →
whereIn('issues.priority_id', ...), a zapisane filtry przechowują te
same id. Sortowanie idzie za position:
IssueRepository::orderByPriority() stawia najważniejsze pierwsze, a
issue'y bez priorytetu ostatnie (rosnąco; malejąco to dokładne
odwrócenie). statsForUser() na dashboardzie grupuje liczniki issue'ów
po nazwie priorytetu między projektami (reprezentuje ją najniższa
pozycja i jeden kolor/ikona tej nazwy), osobno liczy noPriority i
zwraca topPriority: issue'y na pozycji 0 skali własnego projektu,
jakkolwiek by się nazywała. Nieliczne miejsca, które nadal trzymają
priorytet jako zwykły tekst — default_priority szablonu, orbit_value
mapowania priorytetu z Jiry oraz params.priority akcji
automatyzacji change_priority — są przepisywane (zmiana nazwy) albo
usuwane/czyszczone (usunięcie) przez
PriorityRepository::replaceNameReferences(); zapisane filtry tracą
usunięte id przez removeFromSavedFilters(). Usunięcie priorytetu
przyjmuje opcjonalne replacement_id (issue'y przechodzą na niego, a
inaczej zostają bez priorytetu), projekt zawsze zachowuje co najmniej
jeden priorytet, a jeśli usunięty był domyślny, flaga przechodzi na
zastępnik (albo pierwszy pozostały priorytet). Priority używa concernu
BumpsIssueCache, więc cache list issue'ów się odświeża, a serwis sam
podbija CacheVersion::ISSUES po aktualizacji lub usunięciu (zbiorczy
UPDATE issue'ów przy usuwaniu nie wyzwala żadnego eventu modelu).
SettingsController::priorities() zasila zakładkę — priorities
(każdy z issueCount), hasPrioritiesAccess, canCreatePriorities /
canUpdatePriorities / canDeletePriorities — a pozostałe zakładki,
które wybierają priorytet (typy issue dla domyślnych wartości
szablonów, integracje dla mapowania priorytetów Jiry, automatyzacje dla
akcji zmiany priorytetu), oraz strony projektu i issue'a dostają prop
priorities z wierszami Priority::toOption() (id, name, color,
icon, position, isDefault; zakładki ustawień wysyłają pustą listę
bez priorities.view). Na froncie
ProjectPrioritiesProvider / useProjectPriorities() z
resources/js/context/ProjectPrioritiesContext.tsx (priorities,
defaultPriority, findByName()) to jedyne źródło prawdy o tym, jakie
priorytety ma projekt, montowane w Pages/Projects/Show.tsx i
Pages/Issues/Show.tsx; PriorityIcon przyjmuje {name, color, icon}
(albo null dla przerywanego kółka "brak priorytetu"), FilterDropdown
priority wylistowuje po jednej opcji na priorytet z id jako wartością,
StatusDot ma prop color na kolor własny priorytetu, a IssueBoard
buduje jedną kolumnę na priorytet (priority-<id>) plus
priority-none. Zakładka Ustawienia → Priorities
(WorkspaceSettingsPrioritiesTab.tsx) została odblokowana ze stanu
"coming soon" opisanego w
../settings-tabs/01-flip-a-placeholder-tab-live.mdZakładki ustawieńWłącz placeholder zakładkę na żywoPrzećwiczony przykład: zamiana Export (sekcja Account) z nieosiągalnego elementu nawigacji w prawdziwą zakładkę. Jej komponent, AccountSettingsExportTab.ts…;
jej UI tworzenia/edycji to ten sam panel rozwijany w miejscu, co w
zakładce labeli (WorkspaceSettingsPriorityInlineEditor.tsx), zmiana
kolejności to przyciski w górę/w dół, które wysyłają PATCH z nową
kolejnością, a usuwanie otwiera WorkspaceSettingsDeletePriorityModal.tsx
do wyboru zastępnika.
Aktualizacja: co cztery migracje zrobiły z istniejącymi danymi
Cztery migracje idą razem, w tej kolejności:
2026_10_18_100000_create_priorities_table.php— tworzyprioritiesi dodajeprojects.priorities_seeded_at.2026_10_18_110000_grant_priority_permissions_to_existing_roles.php— tworzy cztery uprawnieniaprojects.priorities.*i nadaje je istniejącym rolom systemowym (wszystkie cztery Ownerowi i Adminowi,viewMemberowi i Viewerowi), po czym podbijaCacheVersion::MEMBERSHIP. Nowe uprawnienia nie są nadawane już istniejącym rolom automatycznie — zobacz../permissions/01-add-a-new-permission.mdRole i uprawnienia (RBAC)Dodaj nowe uprawnienieOgólny, krok-po-kroku wzorzec dodawania dowolnego nowego uprawnienia projects./issues./comments. i sprawienia, żeby poprawnie pojawiło się w Settings → Rol… — więc każde przyszłe uprawnienie priorytetów potrzebuje takiej migracji. Role własne (custom) są nietknięte.2026_10_18_120000_move_issue_priority_to_priorities.php— dodajeissues.priority_id, zasiewa startową skalę w każdym projekcie, który ma issue'y, wskazuje każde issue na priorytet o jego dawnym słowie (high→High,medium→Medium,low→Low), usuwa starą kolumnę enumissues.priority, odtwarza triggery kolejności dat, które SQLite gubi przy przebudowie tabeli, i podbijaCacheVersion::ISSUES. Jejdown()zamienia skalę z powrotem na trzy słowa: pierwszy priorytet projektu tohigh, ostatnilow, resztamedium.2026_10_18_130000_migrate_priority_name_references.php— zasiewa każdy projekt, po czym przenosi tekstowe kopie na skalę:default_priorityszablonów,orbit_valuemapowań priorytetów Jiry i parametrychange_prioritydostają kanoniczną nazwę (high→High), a słowa priorytetu w zapisanym filtrze stają się id priorytetów. Słowo, na które projekt nie ma priorytetu, jest odrzucane (szablony, zapisane filtry) albo zostaje bez zmian (mapowania, akcje). Jejdown()nic nie robi: starych słów nie da się odróżnić od dzisiejszych nazw.
Efekt: każde istniejące issue zachowuje swój priorytet, każdy projekt ma
własną, edytowalną skalę High / Medium / Low, a nic już nie czyta
ani nie zapisuje issues.priority.
