-
-
Notifications
You must be signed in to change notification settings - Fork 27
Mobile Friendly Process Mapper
The sixteenth module, and the first where the honest answer is that a phone can read the thing but not build it. Three pages β the mapper itself, the stepβtypes settings screen and the guide. Shipped in #1415β#1418, mobile.css v124 / mobile.js v49, LAYER 30.
Read MobileβFriendly first for the strategy and the one hard rule, and Techniques & Tricks for the catalogue this round draws on.
Β§22 exists to split drag into the kind that survives touch and the kind that does not, and this canvas is squarely the second:
process-mapper.js : 11 Γ mousedown / mousemove / mouseup
0 Γ touchstart / touchmove / pointerdown
A step cannot be moved with a finger. And every perβstep action β edit label, add a note, link to a URL, create a connected step β lives behind a contextmenu listener, which a touch screen has no way to fire. Between them that is the whole of authoring.
π Say what the round is for, out loud, before building it. A toolbar whose buttons halfβrespond is worse than a screen that is honestly readβonly. The round was scoped to making a map readable: reach the list, open a map, pan around it, read the steps, and manage step types in settings.
β And then it grew, because Ed asked a question and the answer was measured rather than assumed β see the selection sheet below. Positioning still needs a mouse; editing what a box says does not.
β And the enabler was already there: .pm-canvas is overflow: auto, so panning is native touch scrolling and needed no JavaScript at all. Measured on a real map: canvas scrollWidth 1546 inside a clientWidth of 358, panned to x=1188, nine steps rendered.
Run before touching anything, and it decided most of the round:
| Grep | Result |
|---|---|
a preβexisting @media
|
none β no repeat of the LMS trap |
localStorage |
none |
:hover revealing a control |
π΄ one, and it hides the navigation β below |
the page's own style.display writes |
39 β anything positional needed care |
| its own modal class | π΄ .pm-modal / .pm-modal-overlay, invisible to LAYER 3 |
Process Mapper β Settings β Left panel offers Show on hover: the 260px process list collapses to a 16px strip that expands when the cursor approaches. It is a sensible desktop preference and it is stored per analyst.
On a phone nothing hovers. An analyst who turned it on at their desk arrives to a 16px sliver with no way to open it β every process map in the system behind a control a finger cannot operate.
β This is Β§26 crossed with the savedβdesktopβmode trap that the tickets popβout (#762) and the knowledge editor (#1000) both sprang. The remedy is the same in all three: leave the stored preference alone and neutralise its effect at phone width. The class stays on the element and comes back untouched above 768px.
The list becomes a slideβin sheet either way, because 260px of a 360px screen leaves about 100px of canvas.
Ed tested the first build and reported it in one sentence:
"when I tap processes on the hamburger menu it flashes for a split second then vanishes"
The attribute flipped, the scrim appeared, and the panel did not move. The reason is a specificity trap that is easy to walk into and gives no warning at all.
The closed rule was written as a selector list so it could catch the hover mode too:
[data-mobile-module="process-mapper"] .pm-sidebar, /* (0,2,0) */
[data-mobile-module="process-mapper"] .pm-layout.sidebar-hover .pm-sidebar { /* (0,4,0) */
transform: translateX(-100%);
visibility: hidden;
}
body[data-mobile-module="process-mapper"][data-pm-sidebar="open"] .pm-sidebar { /* (0,3,1) */
transform: translateX(0);
}A selector list carries its specificity per selector. (0,3,1) beats the first and loses to the second β so the sheet opened for anyone on the default preference and stayed shut for anyone on hover. Ed was on hover, so for him it never worked once.
π Adding a variant to a CLOSED rule silently raises the bar its OPEN rule has to clear. Mirror the variants on both halves of an open/closed pair, or the pair only half works β and it will be the less common configuration that breaks, which is the hardest kind to notice.
Mirrored, the open rule's second selector is (0,5,1) and wins.
data-pm-sidebar="open" and reported the panel's box. The box was correct β it was still at left: -310. A state assertion has to check the thing the state is for, not that the state was set.
With the sheet finally opening, a screenshot showed the process names cut to a letter or two β "Sβ¦", "Iβ¦", "Aβ¦" β with + New and the search box side by side.
.pm-sidebar is Problem Management's class as well. In LAYER 22 pm- means Problem Management; in LAYER 30 it means Process Mapper. And LAYER 22's block is unscoped:
.pm-sidebar { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 10px 12px; β¦ }So one module's entire layout mode was arranging another module's panel.
β Β§15 in its sharpest form so far. It has always warned about a shared component class; this is two modules that independently picked the same threeβletter prefix, which no amount of reading one module's CSS would reveal.
Restated in this layer rather than by scoping LAYER 22, because Problem Management's pages carry no module marker to scope it to β giving them one is a change to a shipped module and belongs in its own round, not as a side effect of opening a new one. Recorded as owed.
left: 0, visible, with six items in it, and every one of those numbers was true.
Ed, partβway through:
"push back if this is a bad idea but do you think it would be good if we had a little bar at the bottom which shows the currently selected item (box, lane, group etc.) with a little edit button"
The instinct was right and the answer was better than the question, because the module already had most of it β which is only knowable by driving a tap and watching what happens:
tap a step β mousedown fires (browsers synthesise the compatibility mouse
events after a tap), step gains .selected, and
.pm-detail-panel opens with "Step Details" in it
Steps, groups, lanes, connectors and annotations each already have their own detail body and translated title. So the answer was not a new bar with an Edit button β that would have put two taps where one already worked, and needed a new component and new strings to do it. It was to take the module's own 320px rightβhand column and move it to the bottom.
π Before building what somebody asks for, check whether the module already does it badly. A feature request is often a layout complaint wearing a costume.
β The half of the request that shaped the design was the half not about the bar: shows the currently selected item. A sheet that covers the map tells you what you are editing and hides which thing it is. So it takes 58dvh, the canvas is capped to the strip above it, and the selected item is scrolled into that strip. Measured: the step moved from y=411 (behind the sheet) to y=186, fully above it.
The scroll did nothing, and the reason was one line of output:
canvasScroll = 0,0 (max 1186,0)
The canvas scrolls sideways across a wide map, but its content is no taller than its box β so scrollTop has a maximum of zero. There was nowhere to scroll to. padding-bottom on the scroller did not buy the range either (its steps are absolutely positioned). Capping .pm-canvas-wrap to 42dvh does, and it gives the honest layout as well: map above, details below, rather than a sheet floating over a canvas that still believes it is full height.
And then it still read as 0,0 β because MutationObserver callbacks are microtasks, and the probe was reading synchronously in the same task. After a tick: 0,225, exactly the arithmetic. The third time this rollout that check what you actually measured has been the answer rather than a code change.
-
30a β the shell.
.pm-layoutisheight: calc(100vh - 48px), the fourth module in a row (21, 27, 29, this). Handed back to LAYER 2's100dvhflex column, withmin-height: 0so Β§28 does not bite. - 30c β the toolbar, measured at 749px inside 360. It scrolls sideways in its own box rather than being hidden: some of it (export, the map picker) works by tap perfectly well, and a control you can see and not use is more honest than one that has vanished.
-
30d β
.pm-modalpromoted to a fullβscreen sheet. Fourth module to roll its own modal class, and as always nothing in the measurements complains: a 90%βwide centred box is perfectly contained. - 30e β settings, six columns (Shape Β· Name Β· Colour Β· Order Β· Active Β· Actions) as a card feed, with Β§21 labels on colour, order and active. The shape swatch rides beside the name rather than taking a line.
β Zero new locale keys. The sheet button reads process-mapper.nav.processes β the module's own name for that list, already translated wherever the namespace exists.
-
All three pages contained at 360px, from
docScrollW=837. - Each has a scroller that reaches its end (Β§28, now part of the routine rather than an afterthought): help 10,952px, settings 344px, and the mapper's canvas panned to x=1188 of 1546.
-
The sheet driven open in BOTH sidebar modes β the default and the hover preference β landing at
left: 0, 310px,visible, withelementFromPointat its centre returning the panel rather than the scrim, six processes listed, and tapping one closing it. -
Desktop control at 1100px: the button is
display: none, the body attribute is absent, the toolbar'soverflow-xis back tovisible, settings is a real<table>withtable-header-group, and zerodata-mobile-labelis stamped anywhere. - π Problem Management measured as a positive control at 360px and 1100px, because this round writes rules against a class it shares. Unchanged at both:
static grid w=360andstatic block w=250. -
The Β§25 audit: 83 files, +166/β166, every line a
?v=bump; the module's own diff is three pages Γ three lines of optβin.
- Authoring on a phone. Deliberate, and explained at the top.
-
Problem Management's LAYER 22 block is unscoped. It is wrong in principle even though nothing is broken today β the next module whose classes start
pm-will hit it too. It needs a module marker on Problem Management's pages, which is its own small round.
- MobileβFriendly Β· Techniques & Tricks
- Process Mapper β what the module does
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: 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
-
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
- β³ π’ 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