-
Notifications
You must be signed in to change notification settings - Fork 16
Mobile Friendly Problem Management
Problem Management is the seventh module made mobileβfriendly, after Tickets, Assets, Calendar, Knowledge, Service Status and Watchtower. Same hard rule: one @media (max-width: 768px) block, desktop byteβidentical.
π§° Codeβlevel catalogue of the techniques: Mobile: Techniques & Tricks.
Shipped as #1181, commit 854e3532. LAYER 22.
| Page | State |
|---|---|
problem-management/ β list, detail and modals |
Done β sidebar β header strip, filters β chip row, pane hiding, modal sheets (LAYER 22) |
problem-management/settings/ |
Done β inherits the shared settings layers |
problem-management/help.php |
Done β inherits 16h from the Calendar round |
viewport = 360 docScrollW = 872 CONTAINED = false
sidebar = 250px .pm-main = 110px
Two separate problems, and only one of them was the obvious one.
872px wide is the iOS reflowβtoβdesktop trap, and β exactly as with Watchtower β the cause was the shared header row rather than anything in this module. Opting in fixed it outright.
The 110px list did not move. A 250px fixed sidebar beside a flexible pane leaves the pane whatever is left, and on a 360px screen that is a third of the width for the actual content. The page was contained, scrollable, and useless.
π This is the clearest demonstration yet that
docScrollW === innerWidthis the floor, not the finish line. Every automated check passed on a screen showing a 110px column of problems.
It holds three things: Search, New problem, and the status filters. Stacked asβis that is ~250px of a 640px screen before the first problem appears.
.pm-sidebar {
display: grid;
grid-template-columns: 1fr 1fr; /* the two buttons share a line */
gap: 8px;
border-right: none;
border-bottom: 1px solid var(--border, #e5e7eb);
}
.pm-sidebar h3,
.pm-sidebar #pmStatusFilters { grid-column: 1 / -1; } /* these span both */A twoβcolumn grid with selective spanning is a tidy way to say "these two side by side, everything else full width" without adding a wrapper element to the markup.
#pmStatusFilters {
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
scrollbar-width: none;
}
#pmStatusFilters::-webkit-scrollbar { display: none; }
.pm-filter { flex: 0 0 auto; white-space: nowrap; }Same scrollbarβhiding idiom as .detail-tabs, .sw-filter-tabs and the settings .tabs β the bar is redundant on touch and eats a row of height on a narrow desktop window.
Why not a
<select>? Because each chip carries its count, and the counts are half the value of the control β "are there any open ones at all?" is answered without opening anything. A dropdown hides exactly the information you came for.
.pm-modal-content { width: 100%; max-width: none !important; margin: 0; border-radius: 0; min-height: 100%; }LAYER 3 promotes every .modal-content to a fullβscreen sheet β but this module has its own .pm-modal-content, so none of that reached it. Three dialogs (link incidents, link change, detect problems) stayed as 92%βwidth centred boxes with a 40px margin.
π Check the module's modal class before assuming LAYER 3 covers it. A module that rolled its own is invisible to a rule keyed on the shared name, and there is nothing in the measurements to tell you β a centred box on a phone is contained.
Three modules in a row shipped with no mobile.js at all, which makes a fourth feel like failure. It is not β the test is what the page actually does.
This module was already masterβdetail: pmOpenDetail() hides #pmListView and shows #pmDetailView in the same pane. Nothing needed restructuring. The only fault was that the sidebar stayed on screen while you read a problem, spending ~140px of a 640px screen on controls for the list you had just left.
var openDetail = window.pmOpenDetail;
window.pmOpenDetail = function () {
var out = openDetail.apply(this, arguments);
Promise.resolve(out).then(function () {
var dv = document.getElementById('pmDetailView');
if (dv && dv.style.display !== 'none') setPane('detail');
});
return out;
};Both functions are topβlevel declarations, so they are properties of the global object and can be wrapped from mobile.js with no edit to problem-management.js β see Techniques Β§1.
Two details worth copying:
-
Mark the pane only after the promise resolves.
pmOpenDetailis async and bails on a failed fetch. Marking up front would leave the sidebar hidden behind an error toast, with the list underneath and no way back to it. -
The state is an attribute, the hiding is CSS.
body[data-pm-pane="detail"] .pm-sidebar { display: none }sits inside the@mediablock, and the wrapper refuses to set the attribute unlessmq.matchesβ so desktop never sees it even if the JS runs.
| Check | Result |
|---|---|
| List / detail / modal, each at 360px | β contained, zero uncontained elements |
| Pane cycle: list β detail β back | β
sidebar grid β none β grid
|
| Help and Settings at 360px | β contained, zero uncontained |
| Desktop control @ 1100 / 1200 / 1400px | sidebar 250px throughout, body not flex |
data-pm-pane on desktop |
β never appears, at any point in the same cycle |
mobile.js parse check |
β
PARSED_OK β with a negative control
|
That last row matters. A parse harness that cannot fail proves nothing, so the same page was loaded with a deliberately broken script alongside: it reported Uncaught SyntaxError, which is what makes the clean result meaningful.
Driving all three states β not just the page as it loads β is the reason the modal fault was found at all. A page that renders one view at a time is oneβview verified.
- The AI "Detect problems" suggestions list ticket numbers as plain text. They come from a model rather than the database, so linking them needs a serverβside numberβid resolve that would also quietly validate the model's output β see discussion #91. Not a mobile issue, but it shows up here.
-
The detail view's field grid is two columns even at 360px (
PRIORITY/ASSIGNED TO). It reads fine with short values; a long assignee name would be tight.
Ed found the History panel's What column running off the right-hand edge. Measuring the other two tables on the same page found the same fault in a quieter and worse form.
| Table | Measured at 360px | |
|---|---|---|
| History | 345px in a 328px section | spills β the half a person notices |
| Linked incidents | 294px, "fits" | subject cell 82 Γ 134px β seven lines for one sentence |
| Fix (linked change) | same shape | same |
π Overflow gets reported; crushing does not. The two that squeezed passed every automated check β contained, nothing uncontained, no overflow β while being less readable than the one that visibly broke.
All three became card feeds, by the rule now written up as Techniques Β§11: every one of them has a column holding prose (What, Subject, Title), and a sentence can be neither scrolled sideways nor squeezed into 82px.
History now reads the way the module's own notes already do β a quiet when Β· who line, then the change itself:
15/07/2026, 01:17:50 Β· Administrator
changed linked_incident to "LUN-779-88063"
Two details worth copying:
-
The meta cells are
display: inline, not a flex row. Flex blockifies its items, so a flex column cannot put two cells on one line. Plaininlineon two adjacent cells does. -
:has(.pm-when)scopes the history-only rules. Three tables share the.pm-tableclass; that one class appears only on audit rows, so the markup needed no change at all to tell them apart.
<td colspan> β the first and last child of its row β so any rule keyed on either position swallows it. Asserted explicitly: "No change linked yet." still renders after the change.
Desktop control: display: table, table-header-group, table-row, table-cell, header row visible, four columns, at 1100px and 1400px.
- MobileβFriendly β the overview and the rollout state
- Mobile: Techniques & Tricks β the codeβlevel catalogue
- Problem Management β the module itself
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
- π Date & Time Formats
- Theming & Dark Mode
- β¨οΈ 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: 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
- 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
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Scheduled work in your own calendar
- 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)