Repository navigation
Mobile Friendly People
Scope: all five pages - the people list, a person, the companies, a company, and the guide. Layers:
mobile.cssLAYER 42 (42a-42e). Nomobile.jsbranch - the header's β° drawer and the waffle already work, and nothing on these pages needs wrapping. Parent: MobileβFriendly Β· Techniques: Β§3, Β§11, Β§21, Β§23, Β§28, Β§31
People was built after the rollout, with mobile.css and mobile.js linked on every page, markers on all five, and a @media (max-width: 640px) block of its own in people.css that already turned every table into labelled blocks. Nothing spilled sideways. Measured at 360Γ740 through an explicitβwidth iframe, then looked at:
| Page | Found | Answer |
|---|---|---|
| Every page but Companies | π΄ Could not be scrolled by a finger. A person page was 9,712px of document in a 740px screen | Hand the scroller role to the page's own container (42a) |
| List | Search, Show and Company with their headings: 320px before the first person, every field 13px | A compact strip - search, then the two dropβdowns side by side: 109px. 16px fields |
| Every table | Every value labelled, empty ones too ("Job title:" over nothing); a ticket's subject given the same room as its date | A real card: identifier and status pill on line one, prose on its own line, labels only where a value means nothing alone |
| Company | Its people scrolled inside a 420px box inside the scrolling page | One scroller |
htmlBody: visible/hidden bodyH=740
docH: 9712/740
scroller: none
inbox.css gives <body> overflow: hidden, and LAYER 2 makes it a 100dvh flex column. A page whose own container never takes the scroller role is then taller than a body that clips - and because <html> is overflow: visible, the body's hidden propagates to the viewport. The window cannot be scrolled by a person.
It can be scrolled by code. window.scrollTo(0, 99999) moved it to scrollY = 8972, and the header went with it. A probe that scrolls programmatically and asserts the position changed would have passed this page.
π
overflow: hiddenstops the USER, notscrollTo(). A scroll assertion has to be made on an element whose computedoverflow-yisautoorscroll- which is what Β§28's one-line check asks for, and why it found nothing here. "Nothing qualifies" is the finding, not a probe failure.
The fix is 41a's, one module on:
body[data-mobile-module="people"] .ppl-page {
flex: 1 1 auto; min-height: 0; /* Β§28: or the content is the floor */
overflow-y: auto; overflow-x: hidden;
}The list page keeps its filter strip pinned and scrolls .ppl-main-list instead, so a search is always one tap away.
people.css had two blocks. The 900px one stacks the panes in a narrow desktop window and stays where it is. The 640px one was the phone design - and the Morning Checks round (LAYER 26) set the precedent: before styling a module for a phone, find out what is already styling it, and give it one home. It moved into LAYER 42 and now starts at 768 like everything else.
One shape for all eight tables, using two techniques already in the rollout:
-
Β§23's
flex: 1 1 60%on the identifier, so a status pill shares its line at the right; - the Domains round's forced line break - a zeroβheight, fullβwidth
tr::afterplaced byorder- so everything after line one starts at the left whatever the first line did.
A ticket's subject is a sentence, so it gets a full line (Β§11). The labels come from the data-label the module already stamps (its own translated headings), printed only on the columns that cannot speak for themselves: a priority word, a second name, a bare date or count. Self-describing values - an email, a pill, a job title - go unlabelled, and an empty cell is removed outright (td:empty { display: none }), so no heading is left over nothing.
Which status pill rides on line one is keyed on the column count for courses (.ppl-table:has(thead th:nth-child(4))), because a person's courses have a status in column 2 and a company's courses table has a bare count there.
The first screenshot of the list showed two kinds of card: a short email pulled the job title up beside it and a long one did not - Β§23's tell, the difference was the data. The email now takes a line of its own; every card is name / email / role and company.
"Show all" and the company page's people filter both work by setting hidden on rows. A card row is display: flex, which beats the browser's [hidden] { display: none }, so every hidden row would have reappeared. tr[hidden] { display: none } in the layer; proved by driving both (below).
At 360Γ740 on all five pages: nothing off either edge (left < 0 included), every field 16px, and on each page that has more than a screen of content the scroller found, scrolled to the end, and what is under the finger changed. Β§31's test on every control: a search for nobody took the list from 74 rows to the "Nobody matches." state and back to 74; the company filter took 75 people to 0; Show all went 10 β 50 with no hidden row visible before the tap.
Desktop control at 1100px on all five pages - fingerprint every element's box, disable mobile.css in place, fingerprint again: identical, 4,723 boxes, and no data-mobile-label stamped. The people.css change only removed rules below 640px.
- A device pass. Everything here is headless.
See also: People Β· MobileβFriendly Β· Techniques Β· Mobile: Domains (41a's scroller, the forced line break)
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- π§ͺ Developer tests
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- π Date & Time Formats
- Theming & Dark Mode
- ποΈ Recent β getting back to what you were doing
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
-
MobileβFriendly
- β³ π« Mobile: Tickets
- β³ π» Mobile: Assets
- β³ π Mobile: Calendar
- β³ π Mobile: Knowledge
- β³ π¦ Mobile: Service Status
- β³ πΌ Mobile: Watchtower
- β³ π§© Mobile: Problem Management
- β³ π Mobile: Change Management
- β³ πΏ Mobile: Software
- β³ β Mobile: Tasks
- β³ π Mobile: Forms
- β³ π Mobile: Contracts
- β³ π Mobile: Domains
- β³ π Mobile: People
- β³ π Mobile: Projects
- β³ π Mobile: LMS
- β³ πΊοΈ Mobile: CMDB
- β³ πΊοΈ Mobile: Network Mapper
- β³ π§ Mobile: Process Mapper
- β³ βοΈ Mobile: Workflow
- β³ π₯οΈ Mobile: System
- β³ π Mobile: Reporting
- β³ π Mobile: System Wiki
- β³ π Mobile: Self-Service Portal
- β³ π§° Mobile: Techniques & Tricks
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- β³ π‘οΈ CSRF protection (S4) β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- π CardDAV contact sync
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π REST API: Domains
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ π·οΈ REST API: Cost centres
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ π Rota copy and paste β Developer Deep Dive
- β³ β Checklists & SOPs
- β³ βοΈ Mandatory fields
- β³ π·οΈ Ticket categories
- β³ π₯ Assigning tickets to a team, and escalation
- β³ π’ One board across every company
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
-
β³
βοΈ Telegram channel - β³ β CSAT company scope and filters β Developer Guide
- β³ π₯ Microsoft Teams channel
- β³ π¨οΈ Mattermost channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ β Record previews
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ π¨ Telling the analyst a ticket is theirs
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ π Confidential tickets
- β³ π₯ Portal managers
- β³ π Who has seen a ticket
- β³ π Reading long tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π½ Just my tickets, or no closed ones
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Scheduled work in your own calendar
- Problem Management
- Tasks
- π Projects
-
Assets
- β³ π’ Moving an asset between companies
- β³ π Shared asset locations
- β³ π§βπΌ Assigning assets to analysts
- β³ π Warranty and lease alerts
- β³ π Saved table views
- β³ π¨οΈ Recording anything, and importing it
- β³ π·οΈ QR asset labels
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ π Linking equipment to tickets
- β³ βοΈ Follow-up tasks on a ticket
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
-
Forms
- β³ π¨ The form designer β Developer Guide
- β³ π Layout & the grid β Developer Guide
- β³ ποΈ Collections β grouping submissions
- β³ π Submissions as PDFs
- β³ β‘ What happens next β a form's own actions
- β³ π οΈ Sections & conditional logic β Developer Guide
- β³ π οΈ Lookup fields β Developer Guide
- β³ π‘οΈ Catalogue request approvals
- People
- Domains
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ π’ One board across every company
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)
- What this is
-
π Bugs resolved
- β³ πΌοΈ Logo and courses broke on Apache with PHP-FPM
- β³ π’ Chat tickets ignored your ticket numbering
- β³ π Dates shown as a dash, or in server time
- β³ π Assets β Users showed people from other companies
- β³ π Restricted analysts could read other modules' data
- β³ πΌοΈ Replies with a picture in the thread failed to send
- β³ π Reply attachments never reached the customer
- β³ π οΈ Outbound email attachments β Developer Guide
- β³ π A global SSO provider was missing from the portal
- β³ π Behind a proxy, the SSO redirect said http
- β³ βοΈ The portal tagline moved when you saved it
- β³ π¨ The portal settings screen forgot what you saved
- β³ π‘οΈ The approvals inbox said "Error" and nothing else
- β³ π A table's answers were missing from the PDF
- β³ β A single-select column let you tick every option
- β³ π The portal ignored a form's field widths
- β³ π The tasks board stopped taking clicks
- β³ ποΈ #121 The index list is out of date after upgrading
- β³ π #133 The calendar subscription was empty
- β³ π #131 Tasks always reopened on the board
- β³ π₯ #129 Every page returned HTTP 500 after upgrading
- β³ π³ #127 A PHP warning above the System page
- β³ π #126 Notes stamped with the server's clock
- β³ π Storing every date in UTC
- β³ πͺ The portal was down for everyone signed in
- β³ βοΈ #120 Workflow notes could never be written
- β³ βοΈ #123 Three errors when running Database Verification
- β³ π #122 The description box was a stub in the corner
- β³ π£ Demo data deleted real accounts
- β³ π #117 Sign-in redirected to the wrong address
- β³ π¨ #108 The priority dot was invisible
- β³ β±οΈ #116 Time logged from the right-click menu
- β³ π #114 API keys refused by our own guard
- β³ ποΈ #110 Assigning a task told nobody
- β³ πͺ #107 Signed out while still working
- β³ π #103 "Share with Requester" reached nobody
- β³ π #102 Search found nothing for hyphens
- β³ πͺ #101 Source code editor opened behind
- β³ βοΈ #88 Subtasks could not be ticked off
- β³ π» #84 Asset deep link selected nothing
- β³ π« #79 A new ticket arrived with no status
- β³ π§ #79 A ticket from email did not say so
- β³ π #78 Bell opened to nothing
- β³ π¬ #77 Mail only collected from Inbox
- β³ π #74 The default password could not be changed
- β³ π¦ #70 Renaming an impact level
- β³ π€ #67 App-only mailboxes could not send
- β³ π #45 Verify only ever worked for Microsoft
- β³ π #45 IMAP reported as not authenticated
- β³ βοΈ An email template stopped escaping itself
- β³ π The portal dashboard showed the wrong time
- β³ π’ The folder said 99 and the list showed 96