fix(hotkeys): fix the hotkey manager to not save the defaults (#3162)
This commit is contained in:
parent
4558540357
commit
a97fb2fc9a
8
platform/core/src/classes/Hotkey.ts
Normal file
8
platform/core/src/classes/Hotkey.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default interface Hotkey {
|
||||
commandName: string;
|
||||
commandOptions?: Record<string, unknown>;
|
||||
context?: string;
|
||||
keys: string[];
|
||||
label: string;
|
||||
isEditable?: boolean;
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
import objectHash from 'object-hash';
|
||||
import log from './../log.js';
|
||||
import log from '../log.js';
|
||||
import { hotkeys } from '../utils';
|
||||
import isequal from 'lodash.isequal';
|
||||
import Hotkey from './Hotkey';
|
||||
import ServicesManager from '../services/ServicesManager';
|
||||
|
||||
/**
|
||||
*
|
||||
@ -13,6 +16,8 @@ import { hotkeys } from '../utils';
|
||||
*/
|
||||
|
||||
export class HotkeysManager {
|
||||
private _servicesManager: ServicesManager;
|
||||
|
||||
constructor(commandsManager, servicesManager) {
|
||||
this.hotkeyDefinitions = {};
|
||||
this.hotkeyDefaults = [];
|
||||
@ -59,11 +64,17 @@ export class HotkeysManager {
|
||||
*
|
||||
* @param {HotkeyDefinition[] | Object} [hotkeyDefinitions=[]] Contains hotkeys definitions
|
||||
*/
|
||||
setHotkeys(hotkeyDefinitions = []) {
|
||||
setHotkeys(hotkeyDefinitions = [], key = 'hotkey-definitions') {
|
||||
try {
|
||||
const definitions = this.getValidDefinitions(hotkeyDefinitions);
|
||||
if (isequal(definitions, this.hotkeyDefaults)) {
|
||||
console.log('hotkeys REMOVING unused definition', key);
|
||||
localStorage.removeItem(key);
|
||||
} else {
|
||||
console.log('hotkeys setting local storage', key);
|
||||
localStorage.setItem(key, JSON.stringify(definitions));
|
||||
}
|
||||
definitions.forEach(definition => this.registerHotkeys(definition));
|
||||
localStorage.setItem('hotkey-definitions', JSON.stringify(definitions));
|
||||
} catch (error) {
|
||||
const { UINotificationService } = this._servicesManager.services;
|
||||
UINotificationService.show({
|
||||
@ -165,7 +176,14 @@ export class HotkeysManager {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
registerHotkeys(
|
||||
{ commandName, commandOptions = {}, keys, label, isEditable } = {},
|
||||
{
|
||||
commandName,
|
||||
commandOptions = {},
|
||||
context,
|
||||
keys,
|
||||
label,
|
||||
isEditable,
|
||||
}: Hotkey = {},
|
||||
extension
|
||||
) {
|
||||
if (!commandName) {
|
||||
@ -181,9 +199,9 @@ export class HotkeysManager {
|
||||
if (previouslyRegisteredDefinition) {
|
||||
const previouslyRegisteredKeys = previouslyRegisteredDefinition.keys;
|
||||
this._unbindHotkeys(commandName, previouslyRegisteredKeys);
|
||||
log.info(
|
||||
`[hotkeys] Unbinding ${commandName} with ${options} options from ${previouslyRegisteredKeys}`
|
||||
);
|
||||
// log.info(
|
||||
// `[hotkeys] Unbinding ${commandName} with ${options} options from ${previouslyRegisteredKeys}`
|
||||
// );
|
||||
}
|
||||
|
||||
// Set definition & bind
|
||||
@ -194,10 +212,11 @@ export class HotkeysManager {
|
||||
label,
|
||||
isEditable,
|
||||
};
|
||||
this._bindHotkeys(commandName, commandOptions, keys);
|
||||
log.info(
|
||||
`[hotkeys] Binding ${commandName} with ${options} options to ${keys}`
|
||||
);
|
||||
this._bindHotkeys(commandName, commandOptions, context, keys);
|
||||
// log.info(
|
||||
// `[hotkeys] Binding ${commandName} with ${options} from ${context ||
|
||||
// 'default'} options to ${keys}`
|
||||
// );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,7 +245,7 @@ export class HotkeysManager {
|
||||
* @param {string[]} keys - One or more key combinations that should trigger command
|
||||
* @returns {undefined}
|
||||
*/
|
||||
_bindHotkeys(commandName, commandOptions = {}, keys) {
|
||||
_bindHotkeys(commandName, commandOptions = {}, context, keys) {
|
||||
const isKeyDefined = keys === '' || keys === undefined;
|
||||
if (isKeyDefined) {
|
||||
return;
|
||||
@ -238,7 +257,11 @@ export class HotkeysManager {
|
||||
hotkeys.bind(combinedKeys, evt => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
this._commandsManager.runCommand(commandName, { evt, ...commandOptions });
|
||||
this._commandsManager.runCommand(
|
||||
commandName,
|
||||
{ evt, ...commandOptions },
|
||||
context
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import ExtensionManager from './ExtensionManager.js';
|
||||
import MODULE_TYPES from './MODULE_TYPES.js';
|
||||
import ExtensionManager from './ExtensionManager';
|
||||
import MODULE_TYPES from './MODULE_TYPES';
|
||||
import log from './../log.js';
|
||||
|
||||
jest.mock('./../log.js');
|
||||
|
||||
describe('ExtensionManager.js', () => {
|
||||
describe('ExtensionManager.ts', () => {
|
||||
let extensionManager, commandsManager, servicesManager, appConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -238,6 +238,9 @@ describe('ExtensionManager.js', () => {
|
||||
getCustomizationModule: () => {
|
||||
return [{}];
|
||||
},
|
||||
getStateSyncModule: () => {
|
||||
return [{}];
|
||||
},
|
||||
};
|
||||
|
||||
await extensionManager.registerExtension(extension);
|
||||
@ -245,7 +248,7 @@ describe('ExtensionManager.js', () => {
|
||||
// Registers 1 module per module type
|
||||
Object.keys(extensionManager.modules).forEach(moduleType => {
|
||||
const modulesForType = extensionManager.modules[moduleType];
|
||||
|
||||
console.log('moduleType', moduleType);
|
||||
expect(modulesForType.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,13 +1,59 @@
|
||||
import MODULE_TYPES from './MODULE_TYPES.js';
|
||||
import log from './../log.js';
|
||||
import MODULE_TYPES from './MODULE_TYPES';
|
||||
import log from '../log';
|
||||
import { AppConfig } from '../types/AppConfig';
|
||||
import { ServicesManager } from '../services';
|
||||
import { HotkeysManager, CommandsManager } from '../classes';
|
||||
|
||||
/**
|
||||
* This is the arguments given to create the extension.
|
||||
*/
|
||||
export interface ExtensionConstructor {
|
||||
servicesManager: ServicesManager;
|
||||
commandsManager: CommandsManager;
|
||||
hotkeysManager: HotkeysManager;
|
||||
appConfig: AppConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* The configuration of an extension.
|
||||
* This uses type as the extension manager only knows that the configuration
|
||||
* is an object of some sort, and doesn't know anything else about it.
|
||||
*/
|
||||
export type ExtensionConfiguration = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* The parameters passed to the extension.
|
||||
*/
|
||||
export interface ExtensionParams extends ExtensionConstructor {
|
||||
extensionManager: ExtensionManager;
|
||||
configuration?: ExtensionConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of an actual extension instance.
|
||||
* This is an interface as it declares possible calls, but extensions can
|
||||
* have more values than this.
|
||||
*/
|
||||
export interface Extension {
|
||||
preRegistration?: (p: ExtensionParams) => void;
|
||||
}
|
||||
|
||||
export type ExtensionRegister = {
|
||||
id: string;
|
||||
create: (p: ExtensionParams) => Extension;
|
||||
};
|
||||
|
||||
export default class ExtensionManager {
|
||||
private _commandsManager: CommandsManager;
|
||||
private _servicesManager: ServicesManager;
|
||||
private _hotkeysManager: HotkeysManager;
|
||||
|
||||
constructor({
|
||||
commandsManager,
|
||||
servicesManager,
|
||||
hotkeysManager,
|
||||
appConfig = {},
|
||||
}) {
|
||||
}: ExtensionConstructor) {
|
||||
this.modules = {};
|
||||
this.registeredExtensionIds = [];
|
||||
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
||||
@ -28,11 +74,17 @@ export default class ExtensionManager {
|
||||
this.activeDataSource = undefined;
|
||||
}
|
||||
|
||||
setActiveDataSource(dataSourceName) {
|
||||
public setActiveDataSource(dataSourceName: string): void {
|
||||
this.activeDataSource = dataSourceName;
|
||||
}
|
||||
|
||||
onModeEnter() {
|
||||
/**
|
||||
* Calls all the services and extension on mode enters.
|
||||
* The service onModeEnter is called first
|
||||
* Then registered extensions onModeEnter is called
|
||||
* This is supposed to setup the extension for a standard entry.
|
||||
*/
|
||||
public onModeEnter(): void {
|
||||
const {
|
||||
registeredExtensionIds,
|
||||
_servicesManager,
|
||||
@ -61,7 +113,7 @@ export default class ExtensionManager {
|
||||
});
|
||||
}
|
||||
|
||||
onModeExit() {
|
||||
public onModeExit(): void {
|
||||
const {
|
||||
registeredExtensionIds,
|
||||
_servicesManager,
|
||||
@ -97,7 +149,13 @@ export default class ExtensionManager {
|
||||
*
|
||||
* @param {Object[]} extensions - Array of extensions
|
||||
*/
|
||||
registerExtensions = async (extensions, dataSources = []) => {
|
||||
public registerExtensions = async (
|
||||
extensions: (
|
||||
| ExtensionRegister
|
||||
| [ExtensionRegister, ExtensionConfiguration]
|
||||
)[],
|
||||
dataSources: unknown[] = []
|
||||
): Promise<void> => {
|
||||
// Todo: we ideally should be able to run registrations in parallel
|
||||
// but currently since some extensions need to be registered before
|
||||
// others, we need to run them sequentially. We need a postInit hook
|
||||
@ -127,16 +185,16 @@ export default class ExtensionManager {
|
||||
* @param {Object} extension
|
||||
* @param {Object} configuration
|
||||
*/
|
||||
registerExtension = async (
|
||||
extension,
|
||||
public registerExtension = async (
|
||||
extension: ExtensionRegister,
|
||||
configuration = {},
|
||||
dataSources = []
|
||||
) => {
|
||||
): Promise<void> => {
|
||||
if (!extension) {
|
||||
throw new Error('Attempting to register a null/undefined extension.');
|
||||
}
|
||||
|
||||
let extensionId = extension.id;
|
||||
const extensionId = extension.id;
|
||||
|
||||
if (!extensionId) {
|
||||
// Note: Mode framework cannot function without IDs.
|
||||
@ -203,6 +261,7 @@ export default class ExtensionManager {
|
||||
case MODULE_TYPES.CONTEXT:
|
||||
case MODULE_TYPES.LAYOUT_TEMPLATE:
|
||||
case MODULE_TYPES.CUSTOMIZATION:
|
||||
case MODULE_TYPES.STATE_SYNC:
|
||||
case MODULE_TYPES.UTILITY:
|
||||
// Default for most extension points,
|
||||
// Just adds each entry ready for consumption by mode.
|
||||
@ -1,9 +1,11 @@
|
||||
import ExtensionManager from './ExtensionManager';
|
||||
import MODULE_TYPES from './MODULE_TYPES.js';
|
||||
import MODULE_TYPES from './MODULE_TYPES';
|
||||
|
||||
export default {
|
||||
const DEFAULT_EXPORTS = {
|
||||
ExtensionManager,
|
||||
MODULE_TYPES,
|
||||
};
|
||||
|
||||
export default DEFAULT_EXPORTS;
|
||||
|
||||
export { ExtensionManager, MODULE_TYPES };
|
||||
|
||||
7
platform/core/src/types/AppConfig.ts
Normal file
7
platform/core/src/types/AppConfig.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import Hotkey from '../classes/Hotkey';
|
||||
|
||||
export interface AppConfig {
|
||||
extensions?: string[];
|
||||
defaultDataSourceName?: string;
|
||||
hotkeys?: Record<string, Hotkey> | Hotkey[];
|
||||
}
|
||||
@ -3,5 +3,3 @@ export interface Command {
|
||||
commandOptions?: Record<string, unknown>;
|
||||
context?: string;
|
||||
}
|
||||
|
||||
export default Command;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/**
|
||||
* Just a function that consumes a single argument, with no return.
|
||||
*/
|
||||
type Consumer = (props: Record<string, unknown>) => void;
|
||||
export default Consumer;
|
||||
export type Consumer = (props: Record<string, unknown>) => void;
|
||||
|
||||
@ -24,4 +24,5 @@ export default interface Services {
|
||||
viewportGridService?: ViewportGridService;
|
||||
syncGroupService?: Record<string, unknown>;
|
||||
cornerstoneCacheService?: Record<string, unknown>;
|
||||
segmentationService?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
/** Defines a typescript type for study metadata */
|
||||
/** Defines a typescript interface for study metadata.
|
||||
* This defines the types for when using study metadata as interfaces.
|
||||
*/
|
||||
|
||||
export interface PatientMetadata extends Record<string, unknown> {
|
||||
PatientName?: string;
|
||||
@ -20,4 +22,3 @@ export interface InstanceMetadata extends SeriesMetadata {
|
||||
readonly SOPInstanceUID: string;
|
||||
InstanceNumber?: string | number;
|
||||
}
|
||||
export default StudyMetadata;
|
||||
|
||||
@ -1,29 +1,17 @@
|
||||
import {
|
||||
StudyMetadata,
|
||||
SeriesMetadata,
|
||||
InstanceMetadata,
|
||||
} from './StudyMetadata';
|
||||
|
||||
import Consumer from './Consumer';
|
||||
import { ExtensionManager } from '../extensions';
|
||||
import { CustomizationService, PubSubService } from '../services';
|
||||
import * as Extensions from '../extensions/ExtensionManager';
|
||||
import * as HangingProtocol from './HangingProtocol';
|
||||
import Command from './Command';
|
||||
import Services from './Services';
|
||||
import { CommandsManager } from '../classes';
|
||||
import Hotkey from '../classes/Hotkey';
|
||||
|
||||
export * from '../services/CustomizationService/types';
|
||||
// Separate out some generic types
|
||||
export * from './AppConfig';
|
||||
export * from './Consumer';
|
||||
export * from './Command';
|
||||
export * from './StudyMetadata';
|
||||
|
||||
export type {
|
||||
ExtensionManager,
|
||||
HangingProtocol,
|
||||
StudyMetadata,
|
||||
SeriesMetadata,
|
||||
InstanceMetadata,
|
||||
Consumer,
|
||||
PubSubService,
|
||||
CustomizationService,
|
||||
Command,
|
||||
Services,
|
||||
CommandsManager,
|
||||
};
|
||||
/**
|
||||
* Export the types used within the various services and managers, but
|
||||
* not the services/managers themselves, which are exported at the top level.
|
||||
*/
|
||||
export { Extensions, HangingProtocol, Services, Hotkey };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user