Co nowego:
- Kolumny kolejki operatora: dwie nowe (ID, e-mail) obok istniejących, oraz
  możliwość zmiany kolejności widocznych kolumn strzałkami ↑/↓ w picker
  „Kolumny” — nie tylko włączanie/wyłączanie. Kolejność zapamiętywana jest
  per operator tak samo jak dotąd widoczność.
- Wybór sprzętu klienta (Snipe-IT): druga lista dozwolonych kategorii obok
  istniejącej listy podkategorii — pozwala objąć od razu wszystkie
  podkategorie danej kategorii jednym zaznaczeniem.
- Pulpit klienta i widok zgłoszenia operatora pamiętają teraz aktywną
  zakładkę, więc „Wróć do listy” wraca do tej samej, a nie zawsze do
  domyślnej.

Poprawki:
- Paginacja (kolejka operatora, pulpit klienta) używała domyślnego,
  szarego stylu Laravela reagującego na motyw systemu/przeglądarki, a nie
  przełącznik jasny/ciemny w aplikacji — stąd ciemne przyciski nawet w
  trybie jasnym. Podmieniony na własny widok zgodny z kolorami aplikacji
  (w tym własne tło/border każdego przycisku i wyśrodkowanie na telefonie).
- Kolorystyka boksu z informacją o logowaniu nie zmienia już odcienia
  między trybem jasnym i ciemnym (wcześniej pochodziła z --color-accent) —
  teraz stałe, ciemne tło w obu trybach, więc kolory tekstu ustawione przez
  admina (np. biały) zostają czytelne niezależnie od motywu. Poszerzona
  karta logowania (380px → 480px).
- Lista zgłoszeń klienta: etykiety priorytetu/statusu nie zawijają się już
  do osobnej linii przy długim temacie na wąskich ekranach — zostają
  przypięte do prawej, a temat zawija się we własnej kolumnie.
- Liczniki czasu pracy (resumeTimer/stopTimer/...) nie dotykają już
  updated_at — samo otwarcie zgłoszenia nie liczy się jako aktualizacja.
  Kolejka operatora i pulpit klienta domyślnie sortują po dacie utworzenia
  z tego samego powodu.

Zaktualizowana dokumentacja: README, CLAUDE.md, ARCHITECTURE.md,
CHANGELOG.md, wiki/admin, wiki/client, wiki/operator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 09:01:34 +02:00
parent 4b70b910a9
commit 0943829331
28 changed files with 684 additions and 104 deletions

View File

@@ -45,7 +45,8 @@ Category ─< Subcategory ─< CustomField (per-subcategory custom fields
└── csat_rating/csat_comment/csat_rated_at (nullable — set once, on close)
User ─< UserFieldValue >─ UserField
User ─< SavedQueueView (operator's own saved queue filter/sort/column presets)
User ─< SavedQueueView (operator's own named/default saved queue filter/sort/column presets)
User.operator_queue_columns (JSON, auto-remembers shown/hidden queue columns + their order, independent of SavedQueueView)
User ─< notifications (Laravel's database channel — polymorphic, morph-mapped as 'user')
ApiClient (Sanctum token owner, ability-scoped)
Setting (single-row-per-key config store, see below)
@@ -98,6 +99,19 @@ enforced by a `saving` listener that throws `InvalidArgumentException` on
anything else, so a typo'd literal fails loudly instead of sticking silently.
Add new values to the constant before writing them anywhere.
**Timer bookkeeping never touches `updated_at`.** `flushTimer()`/`stopTimer()`/
`resumeTimer()`/`resetTimer()`/`setTimeSpent()` all route their writes through
the private `updateTimerFields()`, which toggles `$this->timestamps = false`
around the `update()` call. `resumeTimer()` runs on every single ticket open
(`TicketShow::mount()`) and `stopTimer()` on every navigate-away/tab-close —
without this, merely viewing a ticket (no reply, no status change) would bump
`updated_at`, which used to drown out genuinely stale tickets in any list
sorted by that column (operator queue, client dashboard — both now default to
sorting by `created_at` instead, for the same reason). Real content changes
still touch `updated_at` normally, via their own separate `update()`/`save()`
calls elsewhere. If you add another timer-only field, write it through
`updateTimerFields()` too rather than a plain `update()`.
## Ticket numbering & URLs
A ticket carries three distinct identifiers, each with a different job:
@@ -605,15 +619,19 @@ toggleable settings gate what a client/operator can actually do with it —
none of them affect `SnipeItClient` itself, only which Livewire methods are
willing to call it:
- `snipeit_client_can_select_asset` (+ `snipeit_client_asset_subcategory_ids`,
a comma-separated allow-list) — gates `Client\NewTicket`'s asset picker.
Mirrors BookStack's shelf allow-lists: an **empty** subcategory list means
the picker never shows for any subcategory, not "every subcategory" —
`NewTicket::snipeitAssets()` checks both the toggle and that the currently
selected `subcategoryId` is in the list before calling
`assetsForEmail()`. `selectCategory()`/`selectSubcategory()` reset any
already-picked asset, so switching to an out-of-scope subcategory can't
silently carry a stale selection through to `submit()`.
- `snipeit_client_can_select_asset` (+ `snipeit_client_asset_subcategory_ids`
and `snipeit_client_asset_category_ids`, two independent comma-separated
allow-lists) — gates `Client\NewTicket`'s asset picker. Mirrors BookStack's
shelf allow-lists: **empty** lists mean the picker never shows for any
subcategory, not "every subcategory" — `NewTicket::snipeitAssets()` checks
the toggle and that *either* the currently selected `subcategoryId` is in
the subcategory list *or* `categoryId` is in the (coarser) category list
before calling `assetsForEmail()`. The category list exists so an admin can
cover every subcategory of a category in one click instead of ticking each
one individually; the two lists are additive, not exclusive.
`selectCategory()`/`selectSubcategory()` reset any already-picked asset, so
switching to an out-of-scope subcategory can't silently carry a stale
selection through to `submit()`.
- `snipeit_operator_view_requester_assets` — gates the same
`assetsForEmail()` lookup (by the ticket's own `email`, not the viewing
operator's) in `Operator\TicketShow`'s sidebar.