The workbench and docks

The workbench (shell-dock.js) manages three tabbed docks, with resizing, drag-and-drop between zones and persistence. It installs itself on DOM ready, sets the shell.ready key, and then exposes K.shell.

Zones

ZoneKeyDefault sizeTypical use
Left dockleft280 pxNavigation: files, database browser
Right dockright340 pxContext: history, assistant, dashboard
Bottom dockbottom260 pxOutput: journal, problems, consoles
There are three docks, and no more. The central zone is not one of them: it is held by zone-centrale.js and exposed as K.zone, described on The tabbed central zone. Declaring a panel with dock: 'center' throws Zone de dock inconnue: to open a panel in the centre, go through K.shell.placer.

Registering a panel

K.whenShellReady(function () { K.shell.registerPanel({ id: 'phreeqc.console', source: 'phreeqc', title: { fr: 'Console PHREEQC', en: 'PHREEQC console' }, icon: ICON_SVG, dock: 'bottom', // REQUIRED: left, right or bottom factory: function (ctx) { var state = ctx.state || { last: null }; var zone = document.createElement('div'); zone.style.cssText = 'height:100%;overflow:auto;'; ctx.root.appendChild(zone); var token = K.events.on('phreeqc.resultat', function (e) { state.last = e.id; ctx.saveState(state); render(zone, e); }); return { dispose: function () { token.dispose(); } }; } }); });
FieldRequiredDescription
idYesThrows if missing. The workbench automatically creates the <id>.toggle command, category panneau.
dockYesThrows if the zone is unknown. It is the default zone: the user may move the panel elsewhere.
titleYesFR and EN labels, reused in the tab and in the toggle command.
factoryYesCalled on first open. An exception shows Panneau indisponible without breaking the dock.
sourceNocore by default.
iconNoInline SVG, using currentColor so it follows the active theme tokens.

The factory context

MemberDescription
ctx.panelIdThe panel identifier.
ctx.rootRoot DOM element, already inserted in the dock body.
ctx.stateThe persisted state, or null. A property, not a function.
ctx.saveState(o)Persists a serialisable object. Write is debounced.
ctx.close()Closes the panel from the inside.

The factory returns a controller whose dispose() is called on close, on move, and on every navigation.

A timer not cleared in dispose() keeps running after the panel is closed. For a panel that writes to the database, such as LIMS acquisition, this produces invisible writes: the panel is closed, the user believes the scan has stopped, and it has not.

Persistence and lifecycle

registerPanel Tab available Open factory(ctx) Navigation dispose, then factory

The layout is stored under isofind_shell_v1 and is not per-page: a panel opened on the dashboard is still open after navigating to Samples, but it has been destroyed and rebuilt. The illusion of permanence rests entirely on ctx.saveState().

Moving a panel

A tab can be dragged from one dock to another. Closed docks open during the drag, and the panel is destroyed and rebuilt on arrival: its instance lives inside its dock body, and reattaching it elsewhere without rebuilding would leave a panel whose rendering context no longer matches its parent.

A panel dragged back to its declared zone leaves no entry in the state: otherwise a saved layout would grow indefinitely with choices that are no longer choices.

K.shell.open(id); K.shell.close(id); K.shell.toggle(id); K.shell.isOpen(id); K.shell.move(id, 'right'); K.shell.zoneOf(id); K.shell.zones; // ['left','right','bottom'] K.shell.reset(); // closes everything, returns each panel to its declared zone

Snapshot and restore

var snap = K.shell.snapshot(); { docks: { left: { taille: 280, ouverts: ['core.fichiers'], actif: 'core.fichiers' }, right: { taille: 340, ouverts: [], actif: null }, bottom: { taille: 260, ouverts: ['core.journal'], actif: 'core.journal' } }, zones: { 'core.problemes': 'right' } // panels moved out of their declared dock } K.shell.restore(snap);
A snapshot contains only the layout: which panels, where, at what size. It does not contain the panels' internal state, their filter, their current sample or their SQL query. A layout repositions panels; it does not replay what they contained. Confusing the two would mean that applying a layout wipes out work in progress.

restore() destroys all live panels before rewriting the state, not after: they are children of the dock they are in today, and the next render would look for them where the layout places them, never removing them from their old parent.

Resetting

K.shell.reset(), or View › Reset layout, returns every panel to the zone its author declared and closes everything. It is the way out when a layout becomes unusable: a panel moved into a dock that is then collapsed cannot be found again except through the palette.

The four hosts of a panel

Since V2.0 the dock is no longer the only place a panel can live. The same panel, with the same factory contract, is displayed indifferently in a dock, in a tab of the central zone, in a floating window laid over the application, or in a separate system window.

HostFileWhat it adds
Dockshell-dock.jsThe three zones described above, tabbed and resizable.
Central zonezone-centrale.jsA tab, splittable and pinnable, for panels that need width.
Floating windowshell-flottant.jsA movable, resizable window inside the application frame.
Detached windowshell-detach.jsA system window, for a second screen.
K.shell.placer('core.historique', 'centre'); // dock, centre, flottant, fenetre K.shell.hote('core.historique'); // where it is, or null K.shell.ouvertQuelquePart('core.historique');

K.shell.placer acts as the single arbiter: it closes the panel wherever it currently is before opening it elsewhere, so two live instances of the same panel never coexist. The surfaces, the drop gestures and the detachable flag are covered on Surfaces and windows.