Commit Graph

25 Commits

Author SHA1 Message Date
aaverbitskiy
e9eee60dab ui: toasts, icon segmented mode switch, steppers, date-range picker (v0.2.13)
Second modernization batch (reference: easystudy ui_elements):
- Toast/snackbar notifications (dark, green check) for actions — copy link.
- Mode switch: icons (horizontal bars / pin / columns) + a sliding active
  indicator; fixed width so the bold active label never resizes the block.
- Appearance number fields became steppers: an editable field with centred −/+
  buttons, ~20% narrower.
- Date filter: the two native date inputs are replaced by a custom range picker
  — one field "Период (даты)" + a calendar popup with month nav and range
  selection (circle endpoints, light band between). The native inputs stay hidden
  as the source of truth so all filter/URL/chip wiring is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 19:02:45 +00:00
aaverbitskiy
f5166b888a ui: toggles, stat tiles, dropdown search, bubble scale slider (v0.2.12)
Modernised several controls (reference: easystudy ui_elements catalogue):
- Display checkboxes (Бренд/Компания/Коллизии/Все поверхности) are now toggle
  switches; the option checkboxes inside filter dropdowns stay normal.
- Counters became stat tiles: header "Поверхности N" (accent) and the map
  legend (свободно/занято/всего + dashed "без координат").
- Filter dropdowns gained an in-panel search that filters the option list
  (shown for lists >7, auto-focused on open).
- Timeline scale control restyled as a filled slider with a value bubble, moved
  out of the header to float over the top-right of the chart just below the time
  axis (5px gap), bubble pointing up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 14:46:04 +00:00
aaverbitskiy
d7c1ce7b77 ui: fresh panel per cluster click, 5-step scale, unified column resizer (v0.2.11)
- Map panel: every marker/cluster click reopens a fresh panel repositioned next
  to the just-clicked cluster (with a pop-in), instead of leaving it in place and
  only swapping the content.
- Timeline scale slider: 5 fixed stops — 6/12/18/24/30 months; label is now
  "Масштаб графика: <6М|12М|18М|24М|30М>" (default 12М).
- Address-column resizer now matches the timeline/map splitter: a 6px solid bar
  that turns accent on hover/drag, so both dividers look identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 13:40:10 +00:00
aaverbitskiy
f4c1de70b4 feat: timeline label -> fly map to surface; keep panel inside the window (v0.2.10)
Timeline: clicking a surface in the left column now flies the map to it — it
switches to the combined "Карта и график" view when only the timeline is open,
then centres+zooms on the surface's cluster (deferred focus waits for the map to
render; works for anonymous and manager users). Replaces the old manager-only
board detail panel on that click (the map card already shows photos + bookings).

Map panel: for clusters with many surfaces it now widens (tabs flow into 3-4
columns) and its height is capped to the space available in the window, so it
never overflows the browser window and scrolls inside instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 09:59:52 +00:00
aaverbitskiy
e83bb5ad49 feat: custom map surface panel (fits content, resizable, smart-positioned) (v0.2.8)
Replace the Yandex balloon with our own floating card, opened on marker/cluster
click. It fits its content (no forced scroll), is draggable by the header and
resizable from the bottom-right corner, and — for clusters — carries tabs to
switch between the co-located surfaces. Photo gallery + lightbox are preserved.

On open it positions itself next to the clicked cluster and offsets toward the
free side of the map (the map half the cluster sits in picks the direction, e.g.
bottom-left cluster -> panel opens up and to the right), clamped inside the map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 08:40:48 +00:00
aaverbitskiy
9b6ca6f848 polish: appearance menu offsets, anon map badge, bar label overflow (v0.2.4)
- appearance menu opens 20px below the header/chips and 58px from the right edge
- map "no coordinates" badge is manager-only (hidden for anonymous visitors)
- timeline bar label that is wider than its bar now renders just past the bar's
  right edge as dark text on the track, instead of being clipped; labels that
  fit still sit inside the bar in white. Applied post-render (measure overflow),
  re-run on changed/rangechanged with a double rAF so bar widths are settled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 19:09:47 +00:00
aaverbitskiy
b4d56d0540 polish: chips bar + appearance menu placement + brand title (v0.2.2)
- appearance menu drops below the active-filter chips row when it is shown,
  and sits 10px further from the right edge
- "Скопировать ссылку" moved to the left of the chips, separated by a divider
- enlarge "Green Media" title so it is flush with the "Адресная программа"
  line below it

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 16:00:47 +00:00
aaverbitskiy
aeb4651f6f polish: appearance menu + clean status names everywhere (v0.2.1)
Appearance ("Оформление") menu:
- add missing status "РК. Предварительное бронирование" (8 statuses total)
- strip the systemic "РК. " prefix from status names in the UI (menu,
  tooltip, status filter dropdown, active-filter chips); raw values stay
  intact for filtering/URLs
- fixed-position menu: opens 25px below the header, ends >=30px above the
  window bottom, scrolls inside — never overflows the viewport
- drop the "Прочие статусы" row
- per-status grey reset glyph (circular arrows) restoring its default colour

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 15:37:03 +00:00
aaverbitskiy
5cabad9c33 feat: all-surfaces timeline + UI polish (v0.2.0)
Timeline can now list the entire inventory (occupied + free + never
booked), not just booked surfaces. New manager-only "Все поверхности"
checkbox (on by default; forced on and hidden for anonymous visitors so
they can spot what is currently free with no future bookings).

/api/boards gains all_surfaces: sources rows from board_info and unions
pf_board so a just-booked surface not yet in the inventory snapshot still
gets a row. Surface facets (city/dimension/search) narrow rows; booking
facets (brand/manager/status) narrow to booked surfaces; dates are a
window that narrows bars, not the surface set.

UI polish:
- timeline tooltip flips up/left near viewport edges
- anonymous "Войти" button filled accent, inverts to white-on-accent hover
- appearance button uses a gear icon instead of "+"
- header counter shows only "Поверхности: N"
- map "всего" counter includes surfaces without coordinates

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 14:48:25 +00:00
aaverbitskiy
341bc42778 auth ui: prevent flash of manager-only controls on load
Anonymous visitors briefly saw the manager-only filters (Brand/Manager/Status),
checkboxes and appearance menu on refresh, because applyRoleUi() hides them only
after the async Keycloak check-sso resolves.

Fix: mark those elements .manager-only and hide them pre-paint via a .role-pending
class set on <html> by the inline head script, gated by a render-blocking CSS rule
(html.role-pending .manager-only { display:none }). applyRoleUi() drops
.role-pending once the role is known and then applies the final per-element state.
Default is now fail-closed (hidden until confirmed manager), so anonymous never
flashes them; managers see the controls appear a moment after load.
2026-08-14 11:29:51 +00:00
aaverbitskiy
1eda6c1e9d auth ui: anon tooltip = dates only; move login button to header top-right
- timeline: RenderFlags.managerView drives the tooltip. Anonymous tier shows
  a minimal tooltip (date range + duration only) — no title, task №, status,
  manager or Planfix hint. Manager tier keeps the rich tooltip.
- header: login/logout button pinned to the top-right corner (.auth-wrap,
  absolute) instead of sitting next to the view-mode switch.

Keycloak: register bare origin in post.logout.redirect.uris so keycloak-js
logout (redirectUri without trailing path) is accepted.
2026-08-14 11:22:16 +00:00
aaverbitskiy
b6b9c27cb0 auth: Keycloak OIDC — anonymous (truncated) vs manager (full) tiers
Backend (main.py + auth.py):
- Validate Bearer JWT against the intense-sale realm JWKS (RS256, issuer
  checked, aud skipped). Missing/invalid token = anonymous, never an error,
  so the public map keeps working when Keycloak is down.
- Anonymous truncation: /api/meta hides brand/manager/status facets;
  /api/bookings blanks brand/company_name/manager/task_id/task_status
  (bars stay, one neutral colour); /api/map keeps occupied_now but empties
  booking details. Hidden facet filters are ignored for anonymous callers.
- boards stay visible to all (physical inventory: address/city/dimension).

Frontend (keycloak-js):
- Silent SSO (check-sso) — anonymous by default, Войти/Выйти button.
- Bearer token attached + refreshed on every API call.
- Anonymous UI hides Brand/Manager/Status filters, Brand/Company toggles,
  appearance menu, collisions and labels; board detail panel (Planfix
  deep-links) gated to managers.

Test manager: user / 1234567890 (realm role `manager`).
2026-08-14 11:05:47 +00:00
aaverbitskiy
4425bd394c features: shareable filter links, board detail panel, spacing rhythm on tokens
- Shareable filter links: current filters sync to the URL query
  (?city=&brand=&dimension=&manager=&status=&q=&from=&to=, repeated params for
  multi-selects) and are restored on load; a "Скопировать ссылку" action in the
  chips row copies the current URL.
- Board detail panel: clicking a timeline row label opens a right-side panel with
  the surface's code, city · size, address and the full list of its bookings
  (brand/company, dates, status dot, manager, Planfix link). Close via ✕ /
  backdrop / Esc. Bars still open the Planfix task. Dropdown gains a public
  setOnBoardClick on the timeline view.
- Fix: the panel showed empty on load because .board-panel{display:flex}
  overrode the UA [hidden] rule — added an explicit [hidden]{display:none}.
- Spacing: tokenised the secondary chrome (header groups, fields, dropdown panel,
  appearance menu, legend, map tooltip) onto the Open Props --size-* scale;
  structural density of the header/fields/inputs deliberately kept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 18:08:45 +00:00
aaverbitskiy
52a1a7cb2d ui: active-filter chips, empty/loading states, focus/animation polish
- Active-filter chips row under the header: one chip per selected city / brand /
  dimension / manager / status plus search and date bounds, each removable; a
  "Сбросить всё" clears everything. Dropdown gains setSelected()/clear().
- Empty states for the timeline and map: icon + title + subtitle + "Сбросить
  фильтры" button (wired to the same reset). (empty toggled to display:flex.)
- Delayed indeterminate loading bar (250ms threshold so fast loads don't flash),
  covering both the data and the map fetches via an in-flight counter.
- Polish: pop-in animation for dropdown/appearance menus, :focus-visible accent
  rings, :active press on buttons, thin themed scrollbars in panels, tabular
  figures on the timeline date axis and tooltips. New components use the Open
  Props --size-* spacing scale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 16:28:51 +00:00
aaverbitskiy
17c54db501 design: adopt Open Props tokens, indigo accent + IBM Plex Sans, collision colour
- Add Open Props as the token foundation (@import "open-props/style"). Our
  semantic tokens (--bg/--surface/--border/--text/--shadow-*/--transition) are
  now backed by its gray ramp, shadows and easing; the rest of the CSS is
  untouched since it already references var(--…).
- Accent → indigo #4f46e5 (--accent + derived rings / month-hover), and the
  timeline bar default colours (appearance.ts) move to the same indigo so the
  content and UI share one palette.
- Font → IBM Plex Sans, self-hosted via @fontsource (latin + cyrillic, weights
  400/500/600/700) so there is no runtime Google Fonts dependency. Backed into
  --font-sans (overrides Open Props' :where() default). Tabular figures on the
  counters and map legend.
- Collision default colour → warm amber-orange #e8590c: distinct from the indigo
  bars and from the green/red map status, reads as a conflict warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 21:15:50 +00:00
aaverbitskiy
a68cac80d1 map: donut clusters, occupancy legend/search/no-coords, styled balloon; header polish
Map (map.ts, styles.css, index.html):
- Cluster icons are now donut charts split green (free) / red (busy) by the
  occupancy of the surfaces they contain, count in the centre. Custom
  clusterIconLayout with a hit-area shape; hover/click preserved.
- gridSize 64 -> 112 so nearby clusters stop overlapping at the overview zoom.
- Live legend: "свободна: X · занята: Y · поверхностей: N", reacts to filters.
- "Без координат" is now a clickable badge opening a compact codes-only panel
  (header "Без координат") so the missing-coordinate surfaces can be fixed.
- Search-to-locate: when a filter narrows to one surface the map flies in and
  opens its balloon.
- Balloon restyled to match the timeline tooltip; muted map tiles (ground-pane
  filter) so the markers stand out.
- Cluster hover tooltip shows the brand for occupied surfaces; legend plate
  raised above the Yandex controls.

Header (index.html, styles.css, main.ts):
- Scale + appearance + checkboxes recomposed into one compact block; shorter
  slider; the "Масштаб" label uses the shared field-label style again.
- "Оформление" is now a round "+" button pinned to the header's bottom-right
  corner with a hover tooltip; opens the same appearance menu.
- Counters relabelled "Поверхности" / "Брони"; the counters plate and the
  view-mode switch now share one borderless grey fill; mode buttons sit on a
  more visible grey frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 09:39:11 +00:00
aaverbitskiy
557522afcf ui: visual refresh, richer bar tooltip (+manager), header alignment fixes
Frontend (styles.css, index.html, main.ts):
- Design tokens: single accent/border/radius/shadow/spacing system; flat header
  (dropped the boxed groups) with a subtle bottom divider.
- Unified controls: 36px height, consistent focus ring; search field gets a
  magnifier icon; view-mode switch is now a compact vertical segmented control.
- Fixed the dropdown option font: `.field label` styles were leaking into the
  option <label>s (they're inside .field), forcing uppercase + bold; options are
  now normal weight / normal case.
- Header alignment: mode switch fills the row so its bottom lines up with the
  date fields; the counters block is pinned to the same bottom line.
- Dropdown lists no longer show the column-resizer line bleeding through: the
  header now establishes a stacking context (position:relative + z-index) so its
  panels sit above the timeline.
- Dark theme is implemented (tokens + no-flash) but hidden for now (toggle
  display:none, forced light) until it's polished — easy to re-enable.

Timeline tooltip (timeline.ts, types.ts):
- Replaced the plain multi-line text tooltip with a structured card: bold brand
  title + task №, company subtitle, localized dates + duration, status as a
  coloured dot, manager, a distinct collision section, and a "click to open in
  Planfix" hint. Left accent stripe in the bar colour; matches the map tooltip.
- Values are escaped (escapeHtml) before going into innerHTML.

Backend (main.py):
- /api/bookings now returns `manager` (Array(String)), canonicalized to the
  "Фамилия Имя" form (see canon_manager) so the tooltip can show it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 04:39:55 +00:00
aaverbitskiy
c7eae87660 filters: add faceted Status (task_status) filter — meta.statuses, boards/bookings/map filtering (map marker visibility), UI dropdown under Size in filter grid 2026-07-27 19:40:26 +00:00
aaverbitskiy
68417bf45e map: Yandex map section (3 modes + resizable split), green/red markers, hover tooltips for markers+clusters; fix map init race; header keeps counters inline (fields shrink first); add Manager (Менеджер) faceted filter 2026-07-26 05:05:04 +00:00
aaverbitskiy
66e501ef59 date filters: independent Дата начала (start_date>=) / Дата окончания (end_date<=), header fields under Город/Бренд; qualify pf_board.start_date/end_date to avoid alias shadowing 2026-07-21 10:07:39 +00:00
aaverbitskiy
fe06cdab72 dependent (faceted) filters: city/brand/dimension/search narrow each other 2026-07-21 08:38:53 +00:00
aaverbitskiy
5db77b7a06 brand filter (backend+frontend), compact checkbox grid, two-line counter 2026-07-18 11:15:43 +00:00
aaverbitskiy
b393562c3a frontend UI: header 4 groups, Оформление menu (colors/sizes/fonts), centered bars via inner div, clickable Planfix links 2026-07-17 19:27:22 +00:00
aaverbitskiy
6704a50b33 frontend: full modular migration (collisions/dropdown/timeline/styles), staged at /next/, prod unchanged 2026-07-17 16:17:00 +00:00
aaverbitskiy
c6363cd8cf frontend: Vite+TypeScript scaffold (types, api) — not wired to static yet 2026-07-17 15:41:13 +00:00