diff --git a/README.md b/README.md index 63b7287..2f10753 100644 --- a/README.md +++ b/README.md @@ -119,9 +119,11 @@ The full security model, its limits and the open items are in [docs/SECURITY.md] ## The dashboard +From the top: a weather strip across the full width, then the stat tiles over the technician table, with the recently closed feed down the right side. The feed scrolls inside its own panel and runs the height of the tiles and table. On narrow screens everything stacks. The footer lists what the dashboard is watching (sites, groups, technicians, check intervals and the last check). + - **Stat tiles**: unassigned requests, total open requests, closed today, closed in the last hour, and the technician with the most open tickets. - **Tickets by technician**: each technician's open tickets by status. **Total open** and **Closed today** come first, so they stay visible on narrow screens while the status columns scroll sideways. Darker cells mean more tickets. Click a column header to sort by it, and click it again to reverse. Rows start A to Z by name; the arrow points toward the larger end (↓ is A to Z or lowest first, ↑ is highest first). Each browser remembers its own sort. A row flashes when that technician closes a ticket. -- **Weather**: current conditions and a 5-day forecast for `OWM_ZIP_CODE`, refreshed every 10 minutes. +- **Weather**: current conditions and a 5-day forecast for the chosen location (`OWM_ZIP_CODE` by default), refreshed every 10 minutes. - **Recently closed**: the live closed-ticket feed, checked every minute. A ding plays for each new close. The sound is on by default, and the **Sound on close** toggle mutes it in that browser. - **Refresh now** reruns every check immediately. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 37585d3..03c2f67 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -38,5 +38,6 @@ A hosted dashboard for MCCS help desk staff. Everyone signs in with their own Zo - Live test on 2026-10-15: per-user sign-in, data, Sign out and the IP access list all work behind NPM. - Per-user settings (2026-10-15, `v2.1.0`): ⚙ Settings and a first-visit setup prompt; sites, groups, technicians with suggestions from recent SDP tickets; table refresh and feed length; weather location from a campus list; hidden panels and status columns. Saved server side by Zoho email, so they follow the user between browsers. - Per-user closed statuses for the feed and ding (2026-10-19, `v2.1.1`), so Resolved can ding without waiting days for SDP's automatic close. Tested with stubs only; check against real SDP that resolved tickets carry `resolved_time` and that the later automatic close doesn't ding again. +- New layout (2026-10-19, `v2.3.0`): weather strip across the top, stat tiles over the table, the closed feed full height beside them, and the "watching" text in the footer. - Contrast pass and MCCS colors (2026-10-19, `v2.2.0`): WCAG AA text, stronger heat scale, 12px minimum text, MCCS green accent and navy heat, all colors as tokens. - Sortable technician table (2026-10-19, `v2.1.1`): click any header to sort, again to reverse. Defaults to name A to Z; remembered per browser. diff --git a/src/public/index.html b/src/public/index.html index 508937a..fbcbb22 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -234,8 +234,16 @@ button.quiet:disabled { opacity: 0.5; cursor: default; } display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; - margin-top: 24px; } +/* tiles share rows, so a label that wraps beside the table keeps every number on one line */ +.stats .stat { + display: grid; + grid-row: span 3; + grid-template-rows: subgrid; + row-gap: 0; + align-content: start; +} +.stats .stat .label { align-self: end; } .stat { padding: 16px 18px; @@ -274,8 +282,9 @@ button.quiet:disabled { opacity: 0.5; cursor: default; } grid-template-columns: minmax(0, 1fr) 380px; gap: 20px; margin-top: 20px; - align-items: start; } +/* stat tiles over the technician table, as wide as the table */ +.main-col { display: grid; gap: 20px; align-content: start; min-width: 0; } .section { background: var(--card); @@ -403,15 +412,24 @@ tr.flash td { animation: flash 2.4s ease-out; } /* ---- feed ---- */ +/* the feed runs the full height of the tiles and table beside it and scrolls inside. + contain: size keeps its own length from stretching the row; the left column sets the height */ +.feed-panel { + display: flex; + flex-direction: column; + contain: size; + min-height: 420px; +} .feed { - max-height: 640px; + flex: 1; + min-height: 0; overflow-y: auto; } .ticket { --age: 0; display: grid; - grid-template-columns: 66px 1fr; + grid-template-columns: 80px 1fr; border-bottom: 1px solid var(--rule); } .feed .ticket:last-child { border-bottom: none; } @@ -475,19 +493,39 @@ body > footer { body > footer p { margin: 0; } body > footer p + p { margin-top: 4px; } body > footer .credit { color: var(--signal); } +body > footer .meta { margin: 0 0 12px; } +body > footer .meta:empty { display: none; } /* ---- weather ---- */ -.side { display: grid; gap: 20px; min-width: 0; } +/* one strip across the top: now, details, then the forecast days filling the rest */ +.weather-strip { + display: grid; + grid-template-columns: auto auto minmax(0, 1fr); + align-items: stretch; + margin-top: 20px; +} +.weather-empty { grid-column: 1 / -1; padding: 18px; color: var(--muted); } .weather-now { - display: grid; - grid-template-columns: auto 1fr; + display: flex; align-items: center; - gap: 4px 12px; - padding: 12px 18px 14px 8px; + gap: 8px; + padding: 10px 22px 10px 8px; } .weather-now img { width: 84px; height: 84px; margin: -6px 0; } +.weather-place { + margin: 0 0 4px; + font-size: 15px; + font-weight: 600; +} +.weather-place .note { + margin-left: 8px; + font-family: var(--mono); + font-size: 12px; + font-weight: 400; + color: var(--muted); +} .weather-temp { font-family: var(--mono); font-size: 38px; @@ -496,21 +534,23 @@ body > footer .credit { color: var(--signal); } } .weather-desc { margin-top: 4px; font-size: 14px; text-transform: capitalize; } .weather-details { - grid-column: 1 / -1; display: flex; - flex-wrap: wrap; - gap: 2px 14px; - padding-left: 10px; + flex-direction: column; + justify-content: center; + gap: 2px; + padding: 10px 22px; + border-left: 1px solid var(--rule); font-family: var(--mono); - font-size: 12px; + font-size: 13px; color: var(--muted); + white-space: nowrap; } .weather-details b { color: var(--ink); font-weight: 500; } .forecast { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); - border-top: 1px solid var(--rule); + border-left: 1px solid var(--rule); } .forecast-day { padding: 10px 4px 12px; @@ -662,7 +702,11 @@ button:disabled { opacity: 0.5; cursor: default; } @media (max-width: 1040px) { .board { grid-template-columns: minmax(0, 1fr); } .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .feed { max-height: none; } + /* stacked under the table, the feed sizes to its tickets again */ + .feed-panel { contain: none; min-height: 0; } + /* the forecast drops under the current conditions */ + .weather-strip { grid-template-columns: auto minmax(0, 1fr); } + .forecast { grid-column: 1 / -1; border-left: none; border-top: 1px solid var(--rule); } } @media (max-width: 720px) { @@ -698,13 +742,18 @@ button:disabled { opacity: 0.5; cursor: default; } -
- + + -