Commandes et palette

Palette, raccourci, menu, barre d'outils, console et script convergent tous vers K.commands.execute(). La zone et la capacité y sont vérifiées une fois pour toutes, ce qui laisse un seul fichier à relire pour savoir ce qui peut s'exécuter et sous quelles conditions.

Objet commande

K.commands.register({ id: 'phreeqc.simulation.lancer', source: 'phreeqc', title: { fr: 'PHREEQC : lancer la simulation', en: 'PHREEQC: run simulation' }, category: 'geochimie', capability: 'db.write', zone: null, // 'local' pour reserver au mode developpeur keybinding: 'ctrl+alt+p', quickAccess: true, when: function (ctx) { return ctx.get('shell.ready') && ctx.get('kernel.zone') !== undefined; }, handler: function (args, ctx) { return fetch('/api/phreeqc/run', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(args) }).then(function (r) { return r.json(); }); } });
ChampTypeDescription
idstringRequis. Une commande sans identifiant lève.
title{fr, en} ou cléRésolu par K.resolveTitle().
handlerfunction(args, context). Synchrone ou promesse. Absent si declarative.
categorystringRegroupement dans la palette et le panneau Actions.
capabilitystringCapacité requise. Le cœur en est exempt.
zonestring'local' réserve la commande au mode développeur.
whenfunctionReçoit le service de contexte. Une exception vaut false.
keybindingstringCombinaison suggérée. La liaison effective vit dans une table séparée.
quickAccessboolProposée dans la section d'accès rapide.
declarativeboolDéclarée par manifeste, handler absent jusqu'à l'activation.
when est une fonction, pas une chaine. Elle reçoit le service de contexte et doit renvoyer un booléen. Une exception dans le prédicat rend la commande indisponible plutôt que de casser la palette.

Clés de contexte

Le magasin de contexte est un reflet de l'état courant contre lequel s'évaluent les prédicats. Il est ouvert : n'importe quelle vue peut poser une clé par K.context.set(), et les prédicats peuvent la lire.

Clé posée par le noyauValeur
kernel.zonedistribution ou local.
shell.readyBooléen. Posée par shell-dock.js quand les docks sont montés.
// Poser une cle depuis une vue K.context.set('selection.count', lignes.length); // S'abonner var off = K.context.onChange(function (cle, valeur) { if (cle === 'selection.count') rafraichir(); }); off.dispose();

Séquence de dispatch

#ContrôleRejet
1Résolution de l'identifiant.Commande inconnue: <id>
2Zone.Commande réservée à la zone locale
3Capacité, sauf pour le cœur.Capacité refusée: <cap>
4Prédicat when.Commande indisponible dans ce contexte
5Réveil de la source, si dormante.L'erreur d'activation est propagée.
6Présence du handler après activation.Commande sans gestionnaire après activation
7command.before, handler, command.after.Tout échec émet command.error et rejette.

Le réveil vient avant la résolution du handler : une commande déclarée par manifeste n'a pas encore de handler, c'est l'activation de sa source qui l'installe.

Un appel depuis la console ou depuis un script subit les sept mêmes contrôles qu'un clic dans l'interface. Aucun chemin d'exécution ne les contourne, y compris les commandes déclenchées par un workflow ou par l'assistant.

Lister ce qui est disponible

// Le filtrage de disponibilite est fait par le noyau, pour que chaque vue // n'ait pas a reimplementer la regle, donc a s'en ecarter. K.commands.list(); // disponibles ici et maintenant K.commands.list({ quickAccess: true }); // acces rapide K.commands.list({ category: 'geochimie' }); K.commands.list({ source: 'phreeqc' }); K.commands.list({ available: false }); // tout, y compris l'indisponible K.commands.isAvailable('phreeqc.simulation.lancer');

Surcharger une commande

K.commands.override(id, wrapper) enveloppe une commande sans toucher à l'original. La libération du jeton restaure exactement l'état antérieur. C'est le motif retenu pour les extensions du CRM, et la primitive sur laquelle reposent les personnalisations qui doivent survivre à une mise à jour du cœur.

var jeton = K.commands.override('app.donnees.importCSV', function (suivant, args, ctx) { if (!ctx.get('campagne.active')) { return Promise.reject(new Error('Déclarez une campagne avant d\'importer.')); } return suivant(args); }); jeton.dispose(); // la commande d'origine est restauree a l'identique

La palette

Ctrl + Shift + P   →   core.palette.open

La palette appelle K.commands.list() à chaque ouverture : elle n'affiche donc que les commandes disponibles dans le contexte courant, avec leur catégorie et leur raccourci. Une commande apportée par un plugin chargé en cours de session y figure sans redémarrage.

Palette de commandes IsoFind Figure 1 : Palette de commandes, filtrée à la frappe.

Pourquoi une commande est absente

CauseVérification
Zone local hors mode développeur. K.get('command', id).zone
Capacité non accordée à la source. K.get('command', id).capability, puis le fournisseur de capacités.
Prédicat when faux. K.context.all(), puis relire le prédicat.
Source non inscrite. K.get('command', id) rend null.

Journal des actions

Le panneau Journal s'alimente sur command.before, command.after et command.error, ainsi que sur les lignes écrites par K.log(). Il capte également la console.

Le journal est une trace de session, effacée au redémarrage. Il ne remplace pas le registre signé des modifications d'échantillons, chainé et non modifiable, décrit dans Traçabilité et intégrité HMAC. Pour un audit, c'est le registre signé qui fait foi.