-
Notifications
You must be signed in to change notification settings - Fork 15
Mobile Friendly Service Status
Service Status is the fifth module made mobileβfriendly, after Tickets, Assets, Calendar and Knowledge. Same hard rule: one @media (max-width: 768px) block, desktop byteβidentical.
π§° Codeβlevel catalogue of the techniques: Mobile: Techniques & Tricks.
Why Service Status? "Is the VPN down?" is a question people ask you in corridors. It is also the smallest module brought along so far β and the first that needed no JavaScript at all.
Shipped in one round: #1003.
| Page | State |
|---|---|
service-status/ β the board |
Done β twoβup service grid, incidents as a card feed, modal reflow (LAYER 18) |
service-status/settings/ |
Done β LAYER 15e, plus the new .tab-content > table scroller it exposed |
service-status/help.php |
Done β inherits 16h from the Calendar round |
Zero lines of mobile.js. The board has no sidebar, no pane stack and nothing worth wrapping, so the shared shell β waffle drawer, views hamburger, company switcher β is the whole of its behaviour. The existing guard chain already falls through to that correctly, so the module was brought along by three <link> tags, one <body> attribute and a CSS layer.
π Not every module needs a branch. Four in a row had one, which made a fifth feel inevitable. Check what the page actually does before writing one β this one only ever needed CSS.
The board goes twoβup. The service grid was already repeat(auto-fill, minmax(200px, 1fr)), so it reflows on its own β but a 200px floor gives exactly one column at 360px, and a dozen services becomes a dozen fullβwidth cards you scroll past. That loses the thing a board is for. Dropping the floor to 150px fits two (2Γ150 + 10 gap = 310, inside the 336 available) and roughly halves the scroll.
π "It reflows" is not the same as "it works". A singleβcolumn autoβfit grid is technically responsive and practically a list. The question to ask is what the component is for: a status board exists to be scanned, so density matters more than card size.
The description line also loses its min-height: 16px. That reservation keeps desktop cards aligned; twoβup on a phone it is dead space in every card, and the name plus the badge is the point.
Incidents become a card feed. Four columns β title, status, affected services, updated β and every one of them selfβdescribes: a title, a coloured status badge, coloured service tags, a date. Reading order carries the meaning, so no labels are needed and nothing is lost.
.incident-table, .incident-table tbody,
.incident-table tr, .incident-table td { display: block !important; }
.incident-table thead { display: none !important; }
β οΈ !importantis required here, and not for the usual reason. The page's own JS setstable.style.display = 'table'inline every time it renders rows, and an inline style beats an ordinary author rule. Without it the card feed works until the first refresh and then silently reverts. Grep a module forstyle.displaybefore converting one of its tables.
Every cell's contents carry a class from the renderer (.incident-title, .incident-status, .incident-services-list, .incident-date), so the card is styled by name, never by cell position.
The incident modal gets the LAYER 3 sheet treatment plus its own bespoke chrome: Delete on its own fullβwidth row, and min-width: 0 on the affectedβservice <select> so the selectβplusβremove pair can shrink instead of overflowing.
LAYER 15e has always scrolled settings tables β but only .settings-section-body table. Half the settings pages in the product put a bare <table> straight inside the .tab-content: all three of Service Status', and three on the Assets settings page that has been live since #937.
Those had looked fine to the overflow check for exactly the reason the Calendar settings page did: .container carries overflow-y: auto, and per spec a nonβvisible value on one axis computes the other to auto, so the page silently became the horizontal scroller. Contained, and unusable.
body[data-mobile-page="settings"] .tab-content > table:not(.lookup-table) {
display: block; overflow-x: auto; overscroll-behavior-x: contain;
white-space: nowrap; max-width: 100%;
}A scroller and not a card feed, on purpose. These are 6β and 7βcolumn config tables whose columns include unlabelled booleans β Resolved?, Default?. Reading order can carry three or four selfβdescribing values; it cannot carry seven, so these keep their header row. That is the same judgement as the incident feed above, reached the other way.
β οΈ :not(.lookup-table)is loadβbearing. This selector is (0,2,2); 16i's cardβfeed rules are (0,2,1), so on the Calendar's categories table β which is both β this one wins. It happens to be harmless (the conflicting declarations land on different elements, which was measured), but relying on that is a trap for whoever edits either rule next. The exclusion states the intent: a.lookup-tableis a card feed, everything else scrolls.
Same harness as the previous rounds β the real authenticated pages driven headless, asserted not eyeballed, at 360px and 1400px.
- The board's column count is measured by counting cards that share a top edge: 2 at 360px, 6 at 1400px.
- The inlineβ
display:tableoverride is asserted directly, because that is the one thing that would silently regress on the next render. - The desktop control asserts the inverse of every mobile claim: incidents still a real table, headers still shown, board still multiβcolumn.
- The sweep includes the shipped Assets and Calendar settings pages, because the 15e change reaches both. Assets' tables now report
scrollWidth 498 > clientWidth 272β contained and scrollable where before they were contained and crushed. - A dedicated conflict harness checks the Calendar card feed survived the new higherβspecificity rule: rows still blocks, headers still dropped, cells still wrapping, actions still pinned.
β οΈ And the harness earned its keep twice on formatting. Both times I appended a paragraph to an existing CSS comment and closed it early, orphaning text outside the block β which makes the parser drop the rule that follows. Both times the braceβbalance and columnβ0 checks passed happily and three assertions went red. A CSS comment edit is a code edit.
Still owed: a real device pass with Ed.
- The status board polls; there is no pullβtoβrefresh.
- The settings config tables scroll sideways rather than reflow β deliberate (above), but a 7βcolumn table is still a 7βcolumn table on a phone.
-
aria-labelsweep across the injected chrome is still owed, moduleβwide.
- CSS:
assets/css/mobile.cssβ LAYER 18, plus the.tab-content > tableaddition to LAYER 15e. - JS: none.
- Optβin wiring:
service-status/index.php,settings/index.php,help.php(currentlymobile.css?v=37,mobile.js?v=19β on all eighteen pages that link them). - Changelog: #1003.
- Parent: MobileβFriendly Β· Siblings: Tickets, Assets, Calendar, Knowledge Β· Techniques: Mobile: Techniques & Tricks Β· Module: Service Status.
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
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
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- 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: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- 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
- β³ 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)