From 20b5a01a2d978eca0e3620441531377146635aca Mon Sep 17 00:00:00 2001 From: Maxim Grachev <161537477+pirajoke@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:07:49 +0900 Subject: [PATCH] Embed coordinator in campus room --- builder/dashboard-assets/script.js | 19 +++- builder/dashboard-assets/style.css | 95 ++++++++++++++++++- .../dashboard_builder/department_campus.py | 27 +++++- ...st_department_campus_visual_integration.py | 62 ++++++++---- 4 files changed, 178 insertions(+), 25 deletions(-) diff --git a/builder/dashboard-assets/script.js b/builder/dashboard-assets/script.js index b629dbe..511e0a8 100644 --- a/builder/dashboard-assets/script.js +++ b/builder/dashboard-assets/script.js @@ -60,6 +60,8 @@ const taskPanelEl = campus.querySelector('[data-campus-task-panel]'); const routeLayerEl = campus.querySelector('[data-campus-route-layer]'); const managerMarkerEl = campus.querySelector('[data-campus-static-manager]'); + const managerPresenceEl = campus.querySelector('[data-campus-manager-presence]'); + const managerStatusEl = campus.querySelector('[data-campus-manager-status]'); const boulevardEl = campus.querySelector('.campus-boulevard'); const rosterEls = Array.from(campus.querySelectorAll('[data-campus-roster-agent]')); const projectFolderEls = Array.from(campus.querySelectorAll('[data-campus-project-folder]')); @@ -179,9 +181,19 @@ closeCampusDetails(false); closeCampusProjectDetails(false); resetCampusProjectFolders(); + setManagerPresence(); lastTrigger = null; } + function setManagerPresence(event = null) { + if (!managerPresenceEl || !managerStatusEl) return; + const status = event && Object.prototype.hasOwnProperty.call(statusLabels, event.status) + ? statusLabels[event.status] + : 'ожидает задач'; + managerStatusEl.textContent = status; + managerPresenceEl.dataset.campusManagerState = event?.status || 'idle'; + } + function setCampusState(state, visibleTasks, agentCount, omittedTasks) { if (stateEl) stateEl.textContent = stateMessages[state] || stateMessages.unavailable; if (countEl) { @@ -229,7 +241,9 @@ ? event.next_step : null; const hasEvidence = Number.isInteger(event?.evidence_count) && event.evidence_count >= 0; - projectDetailFields.project.textContent = folder.dataset.campusProject || '—'; + projectDetailFields.project.textContent = ( + folder.dataset.campusProjectLabel || folder.dataset.campusProject || '—' + ); projectDetailFields.department_id.textContent = ( folder.dataset.campusProjectDepartmentLabel || '—' ); @@ -430,6 +444,9 @@ setCampusState('empty', 0, 0, Number(payload?.omitted_task_count) || 0); return; } + setManagerPresence( + matchedEvents.find((event) => event.agent_id === 'COORDINATOR') || null, + ); const newJourneySignatures = new Set(); const managerOriginRect = managerMarkerEl?.getBoundingClientRect() || null; matchedEvents.forEach((event) => { diff --git a/builder/dashboard-assets/style.css b/builder/dashboard-assets/style.css index 0e515cf..3048924 100644 --- a/builder/dashboard-assets/style.css +++ b/builder/dashboard-assets/style.css @@ -4591,6 +4591,15 @@ tr:last-child td { border-bottom: none; } gap: 0.4rem; } +.campus-zone-hq > header { + display: inline-grid; + grid-template-columns: max-content minmax(0, 1fr); + align-items: stretch; + justify-content: start; + gap: 0; + max-width: 100%; +} + .campus-zone h3 { margin: 0; padding: 0.3rem 0.5rem; @@ -4604,6 +4613,59 @@ tr:last-child td { border-bottom: none; } box-shadow: inset 0 1px 0 rgba(255, 225, 169, 0.16), 0 3px 0 rgba(30, 20, 14, 0.58); } +.campus-zone-presence { + min-width: 0; + padding: 0.24rem 0.42rem; + border: 1px solid rgba(209, 159, 91, 0.58); + border-left: 0; + background: linear-gradient(180deg, rgba(78, 54, 35, 0.94), rgba(45, 32, 24, 0.94)); + color: #f1d8a7; + display: grid; + align-content: center; + gap: 0.08rem; + font-family: 'JetBrains Mono', monospace; + text-shadow: 0 1px 0 #291b12; + box-shadow: inset 0 1px 0 rgba(255, 225, 169, 0.12), 0 3px 0 rgba(30, 20, 14, 0.58); +} + +.campus-zone-presence strong { + min-width: 0; + font-size: 0.48rem; + line-height: 1.05; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.campus-zone-presence-status { + min-width: 0; + color: #d8c49f; + display: flex; + align-items: center; + gap: 0.2rem; + font-size: 0.4rem; + line-height: 1.05; + white-space: nowrap; +} + +.campus-zone-presence-status i { + width: 0.3rem; + height: 0.3rem; + flex: 0 0 auto; + border-radius: 50%; + background: #b98b43; + box-shadow: 0 0 0 1px rgba(43, 31, 21, 0.72); +} + +.campus-zone-presence[data-campus-manager-state="active"] .campus-zone-presence-status i, +.campus-zone-presence[data-campus-manager-state="testing"] .campus-zone-presence-status i { + background: #65a873; +} + +.campus-zone-presence[data-campus-manager-state="failed"] .campus-zone-presence-status i { + background: #c7554c; +} + .campus-owner-boundary { max-width: 104px; padding: 0.25rem 0.35rem; @@ -4944,9 +5006,22 @@ tr:last-child td { border-bottom: none; } height: 32px; } +.campus-static-manager::after { + content: ""; + position: absolute; + left: 6px; + bottom: -1px; + width: 20px; + height: 3px; + background: rgba(35, 24, 17, 0.58); + box-shadow: 0 1px 0 rgba(12, 9, 7, 0.38); +} + .campus-manager-sprite { + position: relative; + z-index: 1; display: block; - filter: sepia(0.16) saturate(0.86) hue-rotate(-8deg) + filter: brightness(0.76) contrast(0.94) sepia(0.2) saturate(0.72) hue-rotate(-8deg) drop-shadow(0 3px 1px rgba(43, 31, 21, 0.78)); } @@ -5131,6 +5206,15 @@ tr:last-child td { border-bottom: none; } font-size: clamp(0.44rem, 1.35vw, 0.58rem); white-space: nowrap; } + .campus-zone-presence { + padding: 0.2rem 0.28rem; + } + .campus-zone-presence strong { + font-size: clamp(0.34rem, 1.2vw, 0.44rem); + } + .campus-zone-presence-status { + font-size: clamp(0.3rem, 1vw, 0.38rem); + } .campus-owner-boundary { display: none; } .campus-project-shelf { right: 0.35rem; @@ -5213,6 +5297,15 @@ tr:last-child td { border-bottom: none; } gap: 0.55rem; padding: 0.5rem; } + .campus-zone-hq { + background-color: #1b1513; + background-image: + linear-gradient(180deg, rgba(52, 36, 27, 0.48), rgba(27, 21, 19, 0.38)), + url("/dashboard-assets/pixel-verse-campus-bg.webp"); + background-position: center, left 83%; + background-repeat: no-repeat; + background-size: auto, 410% auto; + } .campus-task-lanes { grid-template-columns: minmax(0, 1fr); } .campus-details dl > div { grid-template-columns: minmax(0, 1fr); gap: 0.2rem; } .campus-project-detail { max-width: 100%; } diff --git a/builder/dashboard_builder/department_campus.py b/builder/dashboard_builder/department_campus.py index bfc12a6..7a0d89c 100644 --- a/builder/dashboard_builder/department_campus.py +++ b/builder/dashboard_builder/department_campus.py @@ -545,6 +545,18 @@ def _zone_html(department_id: str, zone: dict[str, Any]) -> str: if zone["owner_permission_boundary"] else "" ) + manager_presence = "" + if department_id == "hq": + manager = _CAMPUS_RESIDENT_PROFILES["COORDINATOR"] + manager_dom_id = "campus-resident-coordinator" + manager_presence = f""" +