diff --git a/package.json b/package.json index c82cd7a69c0..b7cffdb2d00 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "ohif-monorepo-root", "private": true, - "packageManager": "yarn@1.22.22", "workspaces": { "packages": [ "platform/*", diff --git a/platform/core/src/classes/CommandsManager.ts b/platform/core/src/classes/CommandsManager.ts index e6ef1e91236..0138521f90a 100644 --- a/platform/core/src/classes/CommandsManager.ts +++ b/platform/core/src/classes/CommandsManager.ts @@ -19,8 +19,12 @@ import { Command, Commands, ComplexCommand } from '../types/Command'; * to extend this class, please check it's source before adding new methods. */ export class CommandsManager { - constructor({} = {}) { - this.contexts = {}; + private contexts = {}; + // Has the reverse order in which contexts are created, used for the default ordering + private contextOrder = new Array(); + + constructor(_options = {}) { + // No-op } /** @@ -33,7 +37,7 @@ export class CommandsManager { * @param {string} contextName - Namespace for commands * @returns {undefined} */ - createContext(contextName) { + createContext(contextName, priority?: number) { if (!contextName) { return; } @@ -43,6 +47,8 @@ export class CommandsManager { } this.contexts[contextName] = {}; + // Add the context name to the start of the list. + this.contextOrder.splice(0, 0, contextName); } /** @@ -104,34 +110,22 @@ export class CommandsManager { * * @method * @param {String} commandName - Command to find - * @param {String} [contextName] - Specific command to look in. Defaults to current activeContexts + * @param {String} [contextName] - Specific command to look in. Defaults to current activeContexts. + * Also allows an array of contexts to look in. */ - getCommand = (commandName: string, contextName?: string) => { + getCommand = (commandName: string, contextName: string | string[] = this.contextOrder) => { const contexts = []; - if (contextName) { + if (Array.isArray(contextName)) { + contexts.push(...contextName.map(name => this.getContext(name)).filter(it => !!it)); + } else if (contextName) { const context = this.getContext(contextName); if (context) { contexts.push(context); } - } else { - Object.keys(this.contexts).forEach(contextName => { - contexts.push(this.getContext(contextName)); - }); - } - - if (contexts.length === 0) { - return; } - let foundCommand; - contexts.forEach(context => { - if (context[commandName]) { - foundCommand = context[commandName]; - } - }); - - return foundCommand; + return contexts.find(context => !!context[commandName])?.[commandName]; }; /** @@ -141,7 +135,7 @@ export class CommandsManager { * @param {Object} [options={}] - Extra options to pass the command. Like a mousedown event * @param {String} [contextName] */ - public runCommand(commandName: string, options = {}, contextName?: string) { + public runCommand(commandName: string, options = {}, contextName?: string | string[]) { const definition = this.getCommand(commandName, contextName); if (!definition) { log.warn(`Command "${commandName}" not found in current context`); diff --git a/platform/docs/docs/platform/managers/commands.md b/platform/docs/docs/platform/managers/commands.md index 1f07f31a9f8..8727f98932a 100644 --- a/platform/docs/docs/platform/managers/commands.md +++ b/platform/docs/docs/platform/managers/commands.md @@ -7,21 +7,30 @@ sidebar_label: Commands Manager ## Overview -The `CommandsManager` is a class defined in the `@ohif/core` project. The Commands Manager tracks named commands (or functions) that are scoped to +The `CommandsManager` is a class defined in the `@ohif/core` project. +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 +in our active contexts, in the order specified. +If found, we run the command, passing in any application or call specific data specified in the command's definition. -> Note: A single instance of `CommandsManager` should be defined in the consuming application, and it is used when constructing the `ExtensionManager`. +The order specified is the REVERSE of the order the modules are registered in +for the mode dependency. That is, the last module registered has the highest priority +and will be searched first for commands. This has nothing to do with when the +command itself is registered, although registrations for the same command in different +modules in the same context will also use last registration wins. + +> Note: A single instance of `CommandsManager` should be defined in the consuming +application, and it is used when constructing the `ExtensionManager`. A `simplified skeleton` of the `CommandsManager` is shown below: ```js export class CommandsManager { - constructor({ getActiveContexts } = {}) { - this.contexts = {}; - this._getActiveContexts = getActiveContexts; - } + contexts = {}; + contextOrder = []; + + constructor(_ignoredConfig) {} getContext(contextName) { const context = this.contexts[contextName]; @@ -33,6 +42,7 @@ export class CommandsManager { createContext(contextName) { /** ... **/ this.contexts[contextName] = {}; + this.contextOrder.push at beginning(contextName) } @@ -43,6 +53,11 @@ export class CommandsManager { context[commandName] = definition; } + getCommand(commandName, contextName) { + const useContext = contextName || first context having commandName in contextOrder + return useContext[commandName]; + } + runCommand(commandName, options = {}, contextName) { const definition = this.getCommand(commandName, contextName); /**...**/ @@ -64,33 +79,13 @@ export class CommandsManager { ### Instantiating -When we instantiate the `CommandsManager`, we are passing two methods: - -- `getAppState` - Should return the application's state when called (Not implemented in `v3`) -- `getActiveContexts` - Should return the application's active contexts when - called - -These methods are used internally to help determine which commands are currently -valid, and how to provide them with any state they may need at the time they are -called. - -```js title="platform/app/src/appInit.js" -const commandsManagerConfig = { - getAppState: () => {}, - /** Used by commands to determine active context */ - getActiveContexts: () => [ - 'VIEWER', - 'DEFAULT', - 'ACTIVE_VIEWPORT::CORNERSTONE', - ], -}; - -const commandsManager = new CommandsManager(commandsManagerConfig); -``` +No methods or configuration is used within the construction. ## Commands/Context Registration -The `ExtensionManager` handles registering commands and creating contexts, so you don't need to register all your commands manually. Simply, create a `commandsModule` in your extension, and it will get automatically registered in the `context` provided. +The `ExtensionManager` handles registering commands and creating contexts, so you +don't need to register all your commands manually. Simply, create a `commandsModule` +in your extension, and it will get automatically registered in the `context` provided. A *simplified version* of this registration is shown below to give an idea about the process. @@ -173,7 +168,7 @@ use `runCommand(commandName, options = {}, contextName)`. commandsManager.runCommand('speak', { command: 'hello' }); // Run command, from Default context -commandsManager.runCommand('speak', { command: 'hello' }, ['DEFAULT']); +commandsManager.runCommand('speak', { command: 'hello' }, 'DEFAULT'); // Returns all commands for a given context commandsManager.getContext('string');