Files
ohif-viewer/platform/core/src/classes/CommandsManager.js
T
Igor Octaviano 55a580659e feat!: Ability to configure cornerstone tools via extension configuration (#1229)
* Fix ExtensionManager bug and add test to bandaid

* Add tools configuration to extension manager preinit

* Fix reducing of configs

* Merge internal with external configs

* Merge internal with external configs

* Remove dialog from init in measurementstable

* Testing injected configuration

* New way to set config

* Add new prop to dialog provider to allow disabling last position

* Remove code from preinit in cornerstone

* Add new prop to dialog provider to allow disabling last position

* Add centralize to dialogs

* Reorder dialogs when adding them

* Fix draggable styles (cursor)

* Remove repositioning methods from labelling flow and remove overlay from labelling manager

* Fix empty array being set in bringToFront

* Add new command to update table and pass commands manager to modules/preinit hook

* Ad UIContextMenu service / factory

* Use new contextmenu service in measurementspanel extension

* Use dialogs for arrow annotate in default

* Remove positioning funcionality from tool context menu

* Add context menu service

* Pass commandsModule to extension

* Update edit description dialog and simple dialog to position relative

* Remove style code from labelling flow and manager

* Remove eventdata from labelling

* Remove labelling code from measurement init

* Add commandsmanager to provider

* Update contextmenu provider and service

* Add touchstart and mouseclick to hide contextmenu

* Hide labelling if click/touch

* Remove labelling and context menu dead code

* Fix undefined bug if ViewerMain grid has no children

* Fix broken prop on context menu

* Update commandsmodule based on master

* Fix broken configuration

* Update script tag config

* Remove cornerstone from toolcontextmenu

* Remove cornerstone from toolcontextmenu

* Split labelling and context menu providers

* Split labelling and context menu providers

* Update test

* Destructure extensions into new array

* CR Update: Move default arrow config to cornerstone instead of default

* CR Update: Fix app configuration props structure

* CR Update: Fix app configuration prop in script tag and extract commands manager from providers

* CR Update: Create custom providers to use commandsManager

* CR Update: Use services directly in measurementspanel

* CR Update: Pass components to providers

* CR Update: Remove position from dialog

* CR Update: fix dialog prop check

* CR Update: Fix comments

* CR Update: Update documentation

* CR Update: Add test default configuration

* CR Update: Add default empy array to extensions

* CR Update: Update i18n configuration all ot match current function configuration

* CR Update: Add defaults to injected dependencies in configuration and extension configuration

* CR Update: Add defaults to configuration with no args

* Update documentation

* CR Update: Add default for tools

* CR Update: Update config object to i18n

* CR Update: spread defaults

* CR Update: Add tool configuration example to cornerstone extension

* CR Update: Add tool configuration to netlify (testing)

* CR Update: Remove netlify config for tools

* CR Update: Rollback changes to i18n to be fixed later

* CR Update: Update documentation and pass whole cornerstone config object instead of tools key

SEE: https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-both-and-breaking-change-footer

BREAKING CHANGE: modifies the exposed react <App /> components props. The contract for providing configuration for the app has changed. Please reference updated documentation for guidance.
2019-12-09 12:47:23 -05:00

190 lines
5.1 KiB
JavaScript

import log from '../log.js';
/**
* The definition of a command
*
* @typedef {Object} CommandDefinition
* @property {Function} commandFn - Command to call
* @property {Array} storeContexts - Array of string of modules required from store
* @property {Object} options - Object of params to pass action
*/
/**
* The Commands Manager tracks named commands (or functions) that are scoped to
* a context. When we attempt to run a command with a given name, we look for it
* in our active contexts. If found, we run the command, passing in any application
* or call specific data specified in the command's definition.
*
* NOTE: A more robust version of the CommandsManager lives in v1. If you're looking
* to extend this class, please check it's source before adding new methods.
*/
export class CommandsManager {
constructor({ getAppState, getActiveContexts } = {}) {
this.contexts = {};
if (!getAppState || !getActiveContexts) {
log.warn(
'CommandsManager was instantiated without getAppState() or getActiveContexts()'
);
}
this._getAppState = getAppState;
this._getActiveContexts = getActiveContexts;
}
/**
* Allows us to create commands "per context". An example would be the "Cornerstone"
* context having a `SaveImage` command, and the "VTK" context having a `SaveImage`
* command. The distinction of a context allows us to call the command in either
* context, and have faith that the correct command will be run.
*
* @method
* @param {string} contextName - Namespace for commands
* @returns {undefined}
*/
createContext(contextName) {
if (!contextName) {
return;
}
if (this.contexts[contextName]) {
return this.clearContext(contextName);
}
this.contexts[contextName] = {};
}
/**
* Returns all command definitions for a given context
*
* @method
* @param {string} contextName - Namespace for commands
* @returns {Object} - the matched context
*/
getContext(contextName) {
const context = this.contexts[contextName];
if (!context) {
return;
}
return context;
}
/**
* Clears all registered commands for a given context.
*
* @param {string} contextName - Namespace for commands
* @returns {undefined}
*/
clearContext(contextName) {
if (!contextName) {
return;
}
this.contexts[contextName] = {};
}
/**
* Register a new command with the command manager. Scoped to a context, and
* with a definition to assist command callers w/ providing the necessary params
*
* @method
* @param {string} contextName - Namespace for command; often scoped to the extension that added it
* @param {string} commandName - Unique name identifying the command
* @param {CommandDefinition} definition - {@link CommandDefinition}
*/
registerCommand(contextName, commandName, definition) {
if (typeof definition !== 'object') {
return;
}
const context = this.getContext(contextName);
if (!context) {
return;
}
context[commandName] = definition;
}
/**
* Finds a command with the provided name if it exists in the specified context,
* or a currently active context.
*
* @method
* @param {String} commandName - Command to find
* @param {String} [contextName] - Specific command to look in. Defaults to current activeContexts
*/
getCommand(commandName, contextName) {
let contexts = [];
if (contextName) {
const context = this.getContext(contextName);
if (context) {
contexts.push(context);
}
} else {
const activeContexts = this._getActiveContexts();
activeContexts.forEach(activeContext => {
const context = this.getContext(activeContext);
if (context) {
contexts.push(context);
}
});
}
if (contexts.length === 0) {
return;
}
let foundCommand;
contexts.forEach(context => {
if (context[commandName]) {
foundCommand = context[commandName];
}
});
return foundCommand;
}
/**
*
* @method
* @param {String} commandName
* @param {Object} [options={}] - Extra options to pass the command. Like a mousedown event
* @param {String} [contextName]
*/
runCommand(commandName, options = {}, contextName) {
const definition = this.getCommand(commandName, contextName);
if (!definition) {
log.warn(`Command "${commandName}" not found in current context`);
return;
}
const { commandFn, storeContexts } = definition;
const definitionOptions = definition.options;
let commandParams = {};
const appState = this._getAppState();
storeContexts.forEach(context => {
commandParams[context] = appState[context];
});
commandParams = Object.assign(
{},
commandParams, // Required store contexts
definitionOptions, // "Command configuration"
options // "Time of call" info
);
if (typeof commandFn !== 'function') {
log.warn(`No commandFn was defined for command "${commandName}"`);
return;
} else {
return commandFn(commandParams);
}
}
}
export default CommandsManager;