From f0d7c6af55129186c4fa99caab11988d97fcaea0 Mon Sep 17 00:00:00 2001 From: Nils Petter Fremming Date: Wed, 19 Jun 2024 15:33:40 +0200 Subject: [PATCH 01/10] Add options as a part of the achiteture --- .../architecture/base/commands/BaseCommand.ts | 16 ++- .../base/commands/BaseOptionCommand.ts | 41 +++++++ .../concreteCommands/SetSpeedOptionCommand.ts | 46 ++++++++ .../base/domainObjects/DomainObject.ts | 4 +- .../concrete/config/StoryBookConfig.ts | 2 + .../components/Architecture/CommandButton.tsx | 42 ++++--- .../Architecture/DomainObjectPanel.tsx | 20 +++- .../components/Architecture/OptionButton.tsx | 111 ++++++++++++++++++ .../src/components/Architecture/Utilities.tsx | 47 ++++++++ 9 files changed, 300 insertions(+), 29 deletions(-) create mode 100644 react-components/src/architecture/base/commands/BaseOptionCommand.ts create mode 100644 react-components/src/architecture/base/concreteCommands/SetSpeedOptionCommand.ts create mode 100644 react-components/src/components/Architecture/OptionButton.tsx create mode 100644 react-components/src/components/Architecture/Utilities.tsx diff --git a/react-components/src/architecture/base/commands/BaseCommand.ts b/react-components/src/architecture/base/commands/BaseCommand.ts index f78a685e8f6..274c0d8d200 100644 --- a/react-components/src/architecture/base/commands/BaseCommand.ts +++ b/react-components/src/architecture/base/commands/BaseCommand.ts @@ -2,7 +2,7 @@ * Copyright 2024 Cognite AS */ -import { type TranslateKey } from '../utilities/TranslateKey'; +import { type TranslateDelegate, type TranslateKey } from '../utilities/TranslateKey'; import { clear, remove } from '../utilities/extensions/arrayExtensions'; type UpdateDelegate = (command: BaseCommand) => void; @@ -44,7 +44,7 @@ export abstract class BaseCommand { // ================================================= public get name(): string { - return this.tooltip.fallback ?? this.tooltip.key; + return this.tooltip.fallback; } public get shortCutKey(): string | undefined { @@ -55,8 +55,8 @@ export abstract class BaseCommand { return { fallback: '' }; } - public get icon(): string { - return 'Unknown'; + public get icon(): string | undefined { + return undefined; // Means no icon } public get buttonType(): string { @@ -128,4 +128,12 @@ export abstract class BaseCommand { listener(this); } } + + public getLabel(translate: TranslateDelegate): string { + const { key, fallback } = this.tooltip; + if (key === undefined) { + return fallback; + } + return translate(key, fallback); + } } diff --git a/react-components/src/architecture/base/commands/BaseOptionCommand.ts b/react-components/src/architecture/base/commands/BaseOptionCommand.ts new file mode 100644 index 00000000000..4321a51a1eb --- /dev/null +++ b/react-components/src/architecture/base/commands/BaseOptionCommand.ts @@ -0,0 +1,41 @@ +/*! + * Copyright 2024 Cognite AS + */ + +import { type RevealRenderTarget } from '../renderTarget/RevealRenderTarget'; +import { BaseCommand } from './BaseCommand'; +import { RenderTargetCommand } from './RenderTargetCommand'; + +/** + * Base class for all command and tools. These are object that can do a + * user interaction with the system. It also have enough information to + * generate the UI for the command. + */ + +export abstract class BaseOptionCommand extends BaseCommand { + private _options: BaseCommand[] | undefined = undefined; + + // ================================================== + // VIRTUAL METHODS + // ================================================== + + public createOptions(): BaseCommand[] { + return []; // Override this to add options + } + + // ================================================== + // INSTANCE METHODS + // ================================================== + + public getOptions(renderTarget: RevealRenderTarget): BaseCommand[] { + if (this._options === undefined) { + this._options = this.createOptions(); + for (const option of this._options) { + if (option instanceof RenderTargetCommand) { + option.attach(renderTarget); + } + } + } + return this._options; + } +} diff --git a/react-components/src/architecture/base/concreteCommands/SetSpeedOptionCommand.ts b/react-components/src/architecture/base/concreteCommands/SetSpeedOptionCommand.ts new file mode 100644 index 00000000000..3c81e8e1f9b --- /dev/null +++ b/react-components/src/architecture/base/concreteCommands/SetSpeedOptionCommand.ts @@ -0,0 +1,46 @@ +/*! + * Copyright 2024 Cognite AS + */ + +import { type BaseCommand } from '../commands/BaseCommand'; +import { BaseOptionCommand } from '../commands/BaseOptionCommand'; +import { RenderTargetCommand } from '../commands/RenderTargetCommand'; +import { type TranslateKey } from '../utilities/TranslateKey'; + +export class SetSpeedOptionCommand extends BaseOptionCommand { + // ================================================== + // OVERRIDES + // ================================================== + + public override get tooltip(): TranslateKey { + return { key: 'SPEED', fallback: 'Speed' }; + } + + public override createOptions(): BaseCommand[] { + return [new SpeedCommand(1), new SpeedCommand(2), new SpeedCommand(4)]; + } +} + +class SpeedCommand extends RenderTargetCommand { + static currentSpeed: number = 1; + private readonly _value; + + public constructor(value: number) { + super(); + this._value = value; + } + + public override get tooltip(): TranslateKey { + return { fallback: 'x' + this._value.toString() }; + } + + public override get isChecked(): boolean { + return this._value === SpeedCommand.currentSpeed; + } + + public override invokeCore(): boolean { + // this.renderTarget.flexibleCameraManager; + SpeedCommand.currentSpeed = this._value; + return true; + } +} diff --git a/react-components/src/architecture/base/domainObjects/DomainObject.ts b/react-components/src/architecture/base/domainObjects/DomainObject.ts index 4b93b116463..520e83db5cf 100644 --- a/react-components/src/architecture/base/domainObjects/DomainObject.ts +++ b/react-components/src/architecture/base/domainObjects/DomainObject.ts @@ -323,8 +323,8 @@ export abstract class DomainObject { // VIRTUAL METHODS: Others // ================================================== - public get icon(): string { - return 'Unknown'; + public get icon(): string | undefined { + return undefined; } /** diff --git a/react-components/src/architecture/concrete/config/StoryBookConfig.ts b/react-components/src/architecture/concrete/config/StoryBookConfig.ts index adee0bac141..bd2685a53c8 100644 --- a/react-components/src/architecture/concrete/config/StoryBookConfig.ts +++ b/react-components/src/architecture/concrete/config/StoryBookConfig.ts @@ -19,6 +19,7 @@ import { type BaseTool } from '../../base/commands/BaseTool'; import { ToggleMetricUnitsCommand } from '../../base/concreteCommands/ToggleMetricUnitsCommand'; import { MeasurementTool } from '../measurements/MeasurementTool'; import { ClipTool } from '../clipping/ClipTool'; +import { SetSpeedOptionCommand } from '../../base/concreteCommands/SetSpeedOptionCommand'; export class StoryBookConfig extends BaseRevealConfig { // ================================================== @@ -37,6 +38,7 @@ export class StoryBookConfig extends BaseRevealConfig { new FitViewCommand(), new SetAxisVisibleCommand(), new ToggleMetricUnitsCommand(), + new SetSpeedOptionCommand(), undefined, new ExampleTool(), new MeasurementTool(), diff --git a/react-components/src/components/Architecture/CommandButton.tsx b/react-components/src/components/Architecture/CommandButton.tsx index fa104b2c53a..96422486ae1 100644 --- a/react-components/src/components/Architecture/CommandButton.tsx +++ b/react-components/src/components/Architecture/CommandButton.tsx @@ -9,6 +9,9 @@ import { useTranslation } from '../i18n/I18n'; import { type BaseCommand } from '../../architecture/base/commands/BaseCommand'; import { type RevealRenderTarget } from '../../architecture/base/renderTarget/RevealRenderTarget'; import { RenderTargetCommand } from '../../architecture/base/commands/RenderTargetCommand'; +import { OptionButton } from './OptionButton'; +import { BaseOptionCommand } from '../../architecture/base/commands/BaseOptionCommand'; +import { getButtonType, getIcon, getTooltipPlacement } from './Utilities'; export const CommandButtons = ({ commands, @@ -27,7 +30,11 @@ export const CommandButtons = ({ }; export const CreateCommandButton = (command: BaseCommand, isHorizontal = false): ReactElement => { - return ; + if (command instanceof BaseOptionCommand) { + return ; + } else { + return ; + } }; export const CommandButton = ({ @@ -45,7 +52,7 @@ export const CommandButton = ({ const [isEnabled, setEnabled] = useState(true); const [isVisible, setVisible] = useState(true); const [uniqueId, setUniqueId] = useState(0); - const [icon, setIcon] = useState('Copy'); + const [icon, setIcon] = useState(undefined); useEffect(() => { function update(command: BaseCommand): void { @@ -53,7 +60,7 @@ export const CommandButton = ({ setEnabled(command.isEnabled); setVisible(command.isVisible); setUniqueId(command.uniqueId); - setIcon(command.icon as IconType); + setIcon(getIcon(command)); } update(newCommand); newCommand.addEventListener(update); @@ -65,23 +72,18 @@ export const CommandButton = ({ if (!isVisible) { return <>; } - const placement = isHorizontal ? 'top' : 'right'; - const { key, fallback } = newCommand.tooltip; - // This was the only way it went through compiler: (more button types will be added in the future) - const type = newCommand.buttonType; - if (type !== 'ghost' && type !== 'ghost-destructive' && type !== 'primary') { - return <>; - } - const text = key === undefined ? fallback : t(key, fallback); + const placement = getTooltipPlacement(isHorizontal); + const tooltip = newCommand.getLabel(t); return ( - +