Maintenance Modals
Open Maintenance add/view/edit/delete modals from any Twig view using the global JavaScript API.
Quick start
This site already loads the proxy script globally. On a custom page, ensure /assets/maintenance/maintenance-modal.js is loaded (it lazy-loads the core scripts when you first open a modal).
1) Call a helper
Use one of the convenience helpers for common actions.
2) Or call
open()
Use
open()
when you need to choose the mode dynamically.
// The only required fields are table + mode.
// For edit/view/delete you must also pass id (or rowIndex).
MaintenanceModal.open({
table: 'm_module_type',
mode: 'edit',
id: '1665231610866'
});
API reference
Global object
Available as
window.MaintenanceModal. All methods return a Promise.
// Proxy (always present if maintenance-modal.js is loaded)
MaintenanceModal.ensureReady(): Promise<void>
MaintenanceModal.open(options): Promise<void>
MaintenanceModal.add(table): Promise<void>
MaintenanceModal.view(table, id): Promise<void>
MaintenanceModal.edit(table, id): Promise<void>
MaintenanceModal.remove(table, id): Promise<void>
open(options)
options
-
table
(string, required): The maintenance module table name (example:
m_module_type). -
mode
(string):
add/create,view,edit,delete/remove. Default isview. -
id
(string|number): Required for
view/edit/deleteif you don’t providerowIndex. -
rowIndex
(number): Optional alternative to
idwhen you already know the index in the cached records list. -
type
(string): Alias for
mode(the core accepts either). -
trigger
(Element): Proxy-only. The button/link to show as “loading” while scripts load. Defaults to
document.activeElementif it’s an element. -
loadingText
(string): Proxy-only. Default is
Opening….
Convenience helpers
// Add (create)
await MaintenanceModal.add('m_module_type');
// View
await MaintenanceModal.view('m_module_type', '1665231610866');
// Edit
await MaintenanceModal.edit('m_module_type', '1665231610866');
// Delete (shows a confirm flow)
await MaintenanceModal.remove('m_module_type', '1665231610866');
How it works (important details)
-
Lazy loading:
The proxy loads
/assets/maintenance/api.jsand/assets/maintenance/maintenance.json demand. -
Trigger loading state:
When you call a method from a focused button/link, the proxy sets
aria-busy, disables the trigger, and (optionally) swaps the text until the modal firesshown.bs.modal. -
Modal DOM is auto-created:
If
#maintenance-modal/#maintenance-confirm-modaldo not exist, the core script creates and appends them todocument.body. -
Record resolution:
For
view/edit/delete, the core tries to find the record in its cached list; if it can’t, it calls/api/maintenance/{table}/{id}and temporarily appends the record for the modal session. -
Bootstrap optional:
If Bootstrap’s JS (
window.bootstrap.Modal) is available it is used; otherwise a small fallback controller shows/hides the modal and still emitsshown.bs.modal/hidden.bs.modalevents.
Rich text fields
If a field is rendered as
<textarea data-field-type="rich-text">, the modal upgrades it to a lightweight editor (toolbar + contenteditable) and keeps the textarea in sync.
Proxy vs direct core scripts
There are two supported ways to enable Maintenance modals. Use the proxy for “any page” integration; use direct core scripts when you’re building a dedicated Maintenance screen and want the scripts available immediately.
Option A: Proxy (recommended for most pages)
-
Load:
Only
/assets/maintenance/maintenance-modal.js. -
Behavior:
Lazy-loads
api.js+maintenance.json first use. -
UX:
Supports
trigger+loadingTextto show “Opening…” on the clicked button. - Best for: Front/back pages that just need “open a modal” without maintaining the full Maintenance UI.
<script src="/assets/maintenance/maintenance-modal.js" defer></script>
<button type="button" onclick="MaintenanceModal.edit('m_module_type', '1665231610866')">
Edit
</button>
Option B: Direct core scripts (Maintenance screens)
-
Load:
/assets/maintenance/api.jsand/assets/maintenance/maintenance.js(in that order). -
Behavior:
No lazy-loading;
window.MaintenanceModalis defined by the core and has__ready: true. -
UX note:
Proxy-only options (
trigger,loadingText) are not used by the core. - Best for: The Maintenance admin pages that also render the list UI and need the whole toolkit.
<script src="/assets/maintenance/api.js"></script>
<script src="/assets/maintenance/maintenance.js"></script>
// Now MaintenanceModal is ready immediately.
MaintenanceModal.open({ table: 'm_module_type', mode: 'view', id: '1665231610866' });
Backend requirements
- Make sure the Maintenance API is accessible under /api/maintenance.
- The modal fetches module metadata and records on demand (and may fetch a single record by
idif it isn’t in the current cache). - The REST client used by the core supports:
config,modules,list,get,create,update,delete,form.
// Endpoints used by the built-in MaintenanceAPI client
GET /api/maintenance/config
GET /api/maintenance/modules
GET /api/maintenance/{table}
GET /api/maintenance/{table}/{id}
GET /api/maintenance/{table}/form
POST /api/maintenance/{table}
PUT /api/maintenance/{table}/{id}
DELETE /api/maintenance/{table}/{id}
Troubleshooting
-
“Missing Table” / “Unknown module selected”:
The
tableyou passed doesn’t exist in the Maintenance modules list returned by the backend. -
“Record Missing”:
The record wasn’t in the cached list and the
GET /api/maintenance/{table}/{id}call failed (or returned{ error: ... }). -
Nothing happens on click:
Check that
MaintenanceModalexists in the browser console and that/assets/maintenance/maintenance-modal.jsis loading without 404s.