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>
73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
// Domain types — mirror the JSON returned by the FastAPI backend (main.py).
|
||
// Keeping these in one place lets TypeScript catch drift between the frontend
|
||
// and the ClickHouse-backed API (e.g. a renamed or missing field) at build time.
|
||
|
||
/** GET /api/meta */
|
||
export interface Meta {
|
||
cities: string[];
|
||
dimensions: string[];
|
||
brands: string[];
|
||
managers: string[];
|
||
statuses: string[];
|
||
}
|
||
|
||
/** One row of GET /api/boards (grouped per board_id). */
|
||
export interface Board {
|
||
board_id: string;
|
||
board_address: string;
|
||
board_city: string;
|
||
board_dimension: string;
|
||
}
|
||
|
||
/** One row of GET /api/bookings. task_id/task_status added in the July 2026 change. */
|
||
export interface Booking {
|
||
board_id: string;
|
||
task_id: string;
|
||
task_status: string;
|
||
start_date: string; // ISO date YYYY-MM-DD
|
||
end_date: string; // ISO date YYYY-MM-DD
|
||
brand: string;
|
||
company_name: string;
|
||
manager: string[]; // canonical "Фамилия Имя" names (a task may have several)
|
||
}
|
||
|
||
/** Current filter selection shared by boards/bookings queries. */
|
||
export interface Filters {
|
||
cities: string[];
|
||
dimensions: string[];
|
||
brands: string[];
|
||
managers: string[];
|
||
statuses: string[];
|
||
search: string;
|
||
dateStart: string; // YYYY-MM-DD or '' — start_date >= dateStart
|
||
dateEnd: string; // YYYY-MM-DD or '' — end_date <= dateEnd
|
||
}
|
||
|
||
/** A booking active "today" attached to a map surface (for the balloon). */
|
||
export interface MapBooking {
|
||
task_id: string;
|
||
task_status: string;
|
||
start_date: string;
|
||
end_date: string;
|
||
brand: string;
|
||
company_name: string;
|
||
}
|
||
|
||
/** One surface returned by GET /api/map (from board_info, joined to bookings). */
|
||
export interface MapSurface {
|
||
board_key: number;
|
||
board_id: string;
|
||
city: string;
|
||
address: string;
|
||
dimension: string;
|
||
board_type: string;
|
||
side: string;
|
||
lat: number | null;
|
||
lon: number | null;
|
||
occupied_now: boolean;
|
||
bookings: MapBooking[];
|
||
}
|
||
|
||
/** task_status value that marks an archived booking (painted slate #708090). */
|
||
export const ARCHIVED_STATUS = 'РК. Архив';
|