From f7c382f4e61c0151fee60b736fd4f3d05809a42e Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Wed, 6 Mar 2024 16:01:04 +0100 Subject: [PATCH] Improve GLSP UI Extension mechanism for easier re-use of HTML elements - Allow more fine-grained definition of container and parent - Allow more fine-grained definition of container within parent - Replace hard-coded styles with 'hidden' class - Rework index file to define structure and use grid for layouting - Properly align ALL index files with same structure, loading and style - Remove workaround for toolbar height (48px adjustment) - Ensure Quick Action UI is still rendering correctly Minor fix: - Ensure that mouse move is only ever executed on drag --- integration/eclipse/index.html | 140 ++++++++++++------ integration/eclipse/src/index.css | 33 +++-- integration/standalone/index.html | 54 ++++++- integration/standalone/src/index.css | 30 ++-- integration/viewer/index.html | 130 ++++++++++++++-- integration/viewer/src/index.css | 30 ++-- packages/editor/src/diagram/di.config.ts | 8 +- packages/editor/src/diagram/diagram.css | 10 +- packages/editor/src/diagram/model.ts | 5 - packages/editor/src/index.ts | 1 + packages/editor/src/jump/jump-out-ui.ts | 10 +- .../editor/src/tools/change-bounds-tool.ts | 19 ++- .../ui-tools/quick-action/quick-action-ui.ts | 8 +- .../editor/src/ui-tools/tool-bar/tool-bar.css | 1 - .../editor/src/ui-tools/tool-bar/tool-bar.ts | 4 +- .../src/ui-tools/viewport/viewport-bar.ts | 9 +- .../ui-tools/viewport/viewport-commands.ts | 2 +- packages/editor/src/utils/ivy-ui-extension.ts | 94 ++++++++++++ packages/inscription/package.json | 6 +- .../src/inscription/inscription-ui.tsx | 36 +---- playwright/tests/page-objects/inscription.ts | 2 +- playwright/tests/page-objects/toolbar.ts | 2 +- playwright/tests/page-objects/viewport.ts | 4 +- .../tests/standalone/diagram/element.spec.ts | 10 +- .../standalone/key-listener/move.spec.ts | 8 +- .../tests/standalone/viewport/scroll.spec.ts | 12 +- yarn.lock | 30 ++-- 27 files changed, 484 insertions(+), 214 deletions(-) create mode 100644 packages/editor/src/utils/ivy-ui-extension.ts diff --git a/integration/eclipse/index.html b/integration/eclipse/index.html index 1969f7dd..224d35b1 100644 --- a/integration/eclipse/index.html +++ b/integration/eclipse/index.html @@ -8,61 +8,109 @@ Process Editor + + -
-
-
-
+
+
+
+ + +
+
+
+
-
-
-
-
- - +
+
+
+ + + + +
+
+
+
-
-
+
+
+
-
-
- -
- - + +
-
- + - + \ No newline at end of file diff --git a/integration/eclipse/src/index.css b/integration/eclipse/src/index.css index 0317cbb2..8cf18bdc 100644 --- a/integration/eclipse/src/index.css +++ b/integration/eclipse/src/index.css @@ -5,26 +5,29 @@ body { overflow: hidden; } -body { +#process-editor { display: grid; - grid-template-areas: 'sprotty inscription'; - grid-auto-columns: minmax(250px, 100%) min-content; -} -#sprotty { - grid-area: sprotty; - height: 100vh; + grid-template-columns: 1fr auto; /* Adjust the auto value based on sidebar width */ + grid-template-rows: auto 1fr; /* Adjust based on toolbar height */ + height: 100vh; /* Full viewport height */ } -#inscription { - grid-area: inscription; - background-color: var(--glsp-editor-background); - height: 100vh; + +#sprotty, +.main-widget { + grid-column: 1 / 2; + grid-row: 2 / 3; + position: relative; /* to ensure that absolute positioning of elements within the diagram work relative to the diagram. */ } -#inscription.hidden { - display: none; + +#ivy-tool-bar { + grid-column: 1 / 2; + grid-row: 1 / 2; } -.main-widget { - position: relative; +#inscription-ui { + grid-column: 2 / 3; + grid-row: 1 / 3; /* Spanning across both the rows */ + background-color: var(--glsp-editor-background); } .sprotty svg { diff --git a/integration/standalone/index.html b/integration/standalone/index.html index 17b57bb6..224d35b1 100644 --- a/integration/standalone/index.html +++ b/integration/standalone/index.html @@ -8,13 +8,26 @@ Process Editor + + + + + +
+
+
+ + +
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+ +
+
+ +
+ + + + \ No newline at end of file diff --git a/integration/viewer/src/index.css b/integration/viewer/src/index.css index 0317cbb2..a6f07cb2 100644 --- a/integration/viewer/src/index.css +++ b/integration/viewer/src/index.css @@ -5,26 +5,28 @@ body { overflow: hidden; } -body { +#process-editor { display: grid; - grid-template-areas: 'sprotty inscription'; - grid-auto-columns: minmax(250px, 100%) min-content; + grid-template-columns: 1fr auto; /* Adjust the auto value based on sidebar width */ + grid-template-rows: auto 1fr; /* Adjust based on toolbar height */ + height: 100vh; /* Full viewport height */ } + #sprotty { - grid-area: sprotty; - height: 100vh; -} -#inscription { - grid-area: inscription; - background-color: var(--glsp-editor-background); - height: 100vh; + grid-column: 1 / 2; + grid-row: 2 / 3; + position: relative; /* to ensure that absolute positioning of elements within the diagram work relative to the diagram. */ } -#inscription.hidden { - display: none; + +#ivy-tool-bar { + grid-column: 1 / 2; + grid-row: 1 / 2; } -.main-widget { - position: relative; +#inscription-ui { + grid-column: 2 / 3; + grid-row: 1 / 3; /* Spanning across both the rows */ + background-color: var(--glsp-editor-background); } .sprotty svg { diff --git a/packages/editor/src/diagram/di.config.ts b/packages/editor/src/diagram/di.config.ts index 99244b49..4b3f32db 100644 --- a/packages/editor/src/diagram/di.config.ts +++ b/packages/editor/src/diagram/di.config.ts @@ -3,8 +3,10 @@ import './diagram.css'; import { ConsoleLogger, CustomFeatures, + DefaultTypes, DeleteElementContextMenuItemProvider, FeatureModule, + GGraph, GLSPProjectionView, GModelElement, IView, @@ -17,7 +19,6 @@ import { moveFeature, selectFeature } from '@eclipse-glsp/client'; -import { DefaultTypes } from '@eclipse-glsp/protocol'; import { interfaces } from 'inversify'; import { ShowGridAction } from '@axonivy/process-editor-protocol'; @@ -44,7 +45,6 @@ import { EndEventNode, EventNode, GatewayNode, - IvyGGraph, LaneNode, MulitlineEditLabel, RotateLabel, @@ -77,9 +77,7 @@ const ivyDiagramModule = new FeatureModule((bind, unbind, isBound, rebind) => { configureCommand({ bind, isBound }, GridFeedbackCommand); const context = { bind, unbind, isBound, rebind }; - - configureIvyModelElement(DefaultTypes.GRAPH, IvyGGraph, GLSPProjectionView); - + configureIvyModelElement(DefaultTypes.GRAPH, GGraph, GLSPProjectionView); configureStartEvent(EventStartTypes.START); configureStartEvent(EventStartTypes.START_ERROR); configureStartEvent(EventStartTypes.START_SIGNAL); diff --git a/packages/editor/src/diagram/diagram.css b/packages/editor/src/diagram/diagram.css index 8a70881e..b9592e44 100644 --- a/packages/editor/src/diagram/diagram.css +++ b/packages/editor/src/diagram/diagram.css @@ -9,7 +9,8 @@ body { .sprotty { user-select: none; } -.sprotty > div:focus-visible { +.sprotty > div:focus-visible, +.sprotty-graph:focus { outline: none; } .sprotty svg:where(.sprotty-graph, .sprotty-empty) { @@ -306,3 +307,10 @@ g[class^='end'] .sprotty-node { svg { border: none; } + +/* UI Extension */ +.ui-extension.hidden { + display: none; + visibility: hidden; + opacity: 0; +} diff --git a/packages/editor/src/diagram/model.ts b/packages/editor/src/diagram/model.ts index 7266f528..df5fb911 100644 --- a/packages/editor/src/diagram/model.ts +++ b/packages/editor/src/diagram/model.ts @@ -12,7 +12,6 @@ import { editFeature, editLabelFeature, fadeFeature, - GGraph, hoverFeedbackFeature, isBoundsAware, isEditableLabel, @@ -47,10 +46,6 @@ import { WithCustomIcon } from './icon/model'; import { ActivityTypes, EdgeTypes, LabelType, LaneTypes } from './view-types'; import { multipleOutgoingEdgesFeature } from '../ui-tools/quick-action/edge/model'; -export class IvyGGraph extends GGraph { - scroll = { x: 0, y: -48 }; -} - export class LaneNode extends RectangularNode implements WithEditableLabel, ArgsAware { static readonly DEFAULT_FEATURES = [ boundsFeature, diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index ea2aca05..c6c7a894 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -28,5 +28,6 @@ export * from './ui-tools/tool-bar/button'; export * from './ui-tools/tool-bar/tool-bar'; export * from './ui-tools/viewport/viewport-commands'; export * from './ui-tools/viewport/viewport-bar'; +export * from './utils/ivy-ui-extension'; export * from './ivy-glsp-jsonrpc-client'; diff --git a/packages/editor/src/jump/jump-out-ui.ts b/packages/editor/src/jump/jump-out-ui.ts index 18ba2101..47710155 100644 --- a/packages/editor/src/jump/jump-out-ui.ts +++ b/packages/editor/src/jump/jump-out-ui.ts @@ -1,5 +1,4 @@ import { - AbstractUIExtension, Action, CommandExecutionContext, CommandReturn, @@ -16,9 +15,10 @@ import { inject, injectable, postConstruct } from 'inversify'; import { IvyIcons } from '@axonivy/ui-icons'; import { createElement, createIcon } from '../utils/ui-utils'; import { JumpAction } from '@axonivy/process-editor-protocol'; +import { IvyUIExtension } from '../utils/ivy-ui-extension'; @injectable() -export class JumpOutUi extends AbstractUIExtension { +export class JumpOutUi extends IvyUIExtension { static readonly ID = 'jumpOutUi'; @inject(TYPES.IActionDispatcher) protected readonly actionDispatcher: IActionDispatcher; @@ -26,16 +26,16 @@ export class JumpOutUi extends AbstractUIExtension { @inject(SelectionService) protected selectionService: SelectionService; @inject(EditorContextService) protected readonly editorContext: EditorContextService; - public id(): string { + id(): string { return JumpOutUi.ID; } - public containerClass(): string { + containerClass(): string { return 'jump-out-container'; } @postConstruct() - postConstruct(): void { + protected postConstruct(): void { this.feedbackDispatcher.registerFeedback(this, [JumpOutFeedbackAction.create()]); } diff --git a/packages/editor/src/tools/change-bounds-tool.ts b/packages/editor/src/tools/change-bounds-tool.ts index ba638eac..687090cd 100644 --- a/packages/editor/src/tools/change-bounds-tool.ts +++ b/packages/editor/src/tools/change-bounds-tool.ts @@ -111,12 +111,21 @@ export class IvyFeedbackMoveMouseListener extends FeedbackMoveMouseListener { mouseMove(target: GModelElement, event: MouseEvent): Action[] { this.lastMove = undefined; - const actions = super.mouseMove(target, event); - if (event.buttons !== 0 && this._isMouseDrag && this.hasRealMoved()) { - this.tool.quickActionUi.hideUi(); - addNegativeArea(target); + if (event.buttons === 0) { + return this.mouseUp(target, event); } - return actions; + if (this._isMouseDown) { + this._isMouseDrag = true; + } + if (this._isMouseDrag) { + const actions = super.mouseMove(target, event); + if (this.hasRealMoved()) { + this.tool.quickActionUi.hideUi(); + addNegativeArea(target); + } + return actions; + } + return []; } draggingMouseUp(target: GModelElement, event: MouseEvent): Action[] { diff --git a/packages/editor/src/ui-tools/quick-action/quick-action-ui.ts b/packages/editor/src/ui-tools/quick-action/quick-action-ui.ts index 8993fceb..c75fd67c 100644 --- a/packages/editor/src/ui-tools/quick-action/quick-action-ui.ts +++ b/packages/editor/src/ui-tools/quick-action/quick-action-ui.ts @@ -1,5 +1,4 @@ import { - AbstractUIExtension, Action, Bounds, BoundsAware, @@ -33,9 +32,10 @@ import { Menu } from '../menu/menu'; import { isQuickActionAware } from './model'; import { QuickAction, QuickActionLocation, QuickActionProvider } from './quick-action'; import { InfoQuickActionMenu, QuickActionMenu, ShowInfoQuickActionMenuAction, ShowQuickActionMenuAction } from './quick-action-menu-ui'; +import { IvyUIExtension } from '../../utils/ivy-ui-extension'; @injectable() -export class QuickActionUI extends AbstractUIExtension implements IActionHandler, ISelectionListener { +export class QuickActionUI extends IvyUIExtension implements IActionHandler, ISelectionListener { static readonly ID = 'quickActionsUi'; private activeQuickActions: QuickAction[] = []; private activeQuickActionBtn?: HTMLElement; @@ -145,10 +145,6 @@ export class QuickActionUI extends AbstractUIExtension implements IActionHandler ); } - hide(): void { - super.hide(); - } - protected onBeforeShow(containerElement: HTMLElement, root: Readonly, ...contextElementIds: string[]): void { containerElement.innerHTML = ''; const elements = getElements(contextElementIds, root); diff --git a/packages/editor/src/ui-tools/tool-bar/tool-bar.css b/packages/editor/src/ui-tools/tool-bar/tool-bar.css index c9624c36..2bc9cc5b 100644 --- a/packages/editor/src/ui-tools/tool-bar/tool-bar.css +++ b/packages/editor/src/ui-tools/tool-bar/tool-bar.css @@ -1,5 +1,4 @@ .ivy-tool-bar { - position: absolute; inset: 0; width: 100%; height: 48px; diff --git a/packages/editor/src/ui-tools/tool-bar/tool-bar.ts b/packages/editor/src/ui-tools/tool-bar/tool-bar.ts index 3907a655..a71b3955 100644 --- a/packages/editor/src/ui-tools/tool-bar/tool-bar.ts +++ b/packages/editor/src/ui-tools/tool-bar/tool-bar.ts @@ -1,5 +1,4 @@ import { - AbstractUIExtension, Action, DisposableCollection, EditorContextService, @@ -37,11 +36,12 @@ import { import { ShowToolBarOptionsMenuAction } from './options/action'; import { ToolBarOptionsMenu } from './options/options-menu-ui'; import { ShowToolBarMenuAction, ToolBarMenu } from './tool-bar-menu'; +import { IvyUIExtension } from '../../utils/ivy-ui-extension'; const CLICKED_CSS_CLASS = 'clicked'; @injectable() -export class ToolBar extends AbstractUIExtension implements IActionHandler, IEditModeListener, ISelectionListener { +export class ToolBar extends IvyUIExtension implements IActionHandler, IEditModeListener, ISelectionListener { static readonly ID = 'ivy-tool-bar'; @inject(TYPES.IActionDispatcher) protected readonly actionDispatcher: GLSPActionDispatcher; diff --git a/packages/editor/src/ui-tools/viewport/viewport-bar.ts b/packages/editor/src/ui-tools/viewport/viewport-bar.ts index 04fe75d6..fd1cc637 100644 --- a/packages/editor/src/ui-tools/viewport/viewport-bar.ts +++ b/packages/editor/src/ui-tools/viewport/viewport-bar.ts @@ -1,6 +1,5 @@ import { Action, - AbstractUIExtension, EditorContextService, GLSPActionDispatcher, IActionHandler, @@ -9,17 +8,19 @@ import { IToolManager, SetUIExtensionVisibilityAction, SetViewportAction, - TYPES - , SelectionService } from '@eclipse-glsp/client'; + TYPES, + SelectionService +} from '@eclipse-glsp/client'; import { inject, injectable } from 'inversify'; import { CenterButton, FitToScreenButton, OriginScreenButton, ViewportBarButton } from './button'; import { createElement, createIcon } from '../../utils/ui-utils'; import { QuickActionUI } from '../quick-action/quick-action-ui'; import { EnableViewportAction, SetViewportZoomAction } from '@axonivy/process-editor-protocol'; +import { IvyUIExtension } from '../../utils/ivy-ui-extension'; @injectable() -export class ViewportBar extends AbstractUIExtension implements IActionHandler { +export class ViewportBar extends IvyUIExtension implements IActionHandler { static readonly ID = 'ivy-viewport-bar'; @inject(TYPES.IActionDispatcher) protected readonly actionDispatcher: GLSPActionDispatcher; diff --git a/packages/editor/src/ui-tools/viewport/viewport-commands.ts b/packages/editor/src/ui-tools/viewport/viewport-commands.ts index 357b6022..7dae2ae0 100644 --- a/packages/editor/src/ui-tools/viewport/viewport-commands.ts +++ b/packages/editor/src/ui-tools/viewport/viewport-commands.ts @@ -53,7 +53,7 @@ export class OriginViewportCommand extends BoundsAwareViewportCommand { } getNewViewport(_bounds: Bounds, _model: GModelRoot): Viewport | undefined { - return { zoom: 1, scroll: { x: 0, y: -48 } }; + return { zoom: 1, scroll: { x: 0, y: 0 } }; } } diff --git a/packages/editor/src/utils/ivy-ui-extension.ts b/packages/editor/src/utils/ivy-ui-extension.ts new file mode 100644 index 00000000..5fca25aa --- /dev/null +++ b/packages/editor/src/utils/ivy-ui-extension.ts @@ -0,0 +1,94 @@ +import { AbstractUIExtension } from '@eclipse-glsp/client'; +import { injectable } from 'inversify'; + +@injectable() +export abstract class IvyUIExtension extends AbstractUIExtension { + static UI_EXTENSION_CLASS = 'ui-extension'; + + protected get diagramContainerId(): string { + return this.options.baseDiv; + } + + protected get parentContainerSelector(): string { + return '#' + this.diagramContainerId; + } + + protected get containerSelector(): string { + return '#' + this.id(); + } + + protected get initialized(): boolean { + return !!this.containerElement; + } + + protected initialize(): boolean { + if (this.initialized) { + return true; + } + try { + this.containerElement = this.getOrCreateContainer(); + this.initializeContainer(this.containerElement); + this.initializeContents(this.containerElement); + } catch (error) { + const msg = error instanceof Error ? error.message : `Could not retrieve container element for UI extension ${this.id}`; + this.logger.error(this, msg); + return false; + } + return true; + } + + protected getOrCreateContainer(): HTMLElement { + if (this.containerElement) { + return this.containerElement; + } + const existingContainer = this.getContainer(); + if (existingContainer) { + return existingContainer; + } + const parent = this.getParentContainer(); + if (!parent || !parent.isConnected) { + throw new Error(`Could not obtain attached parent for initializing UI extension ${this.id}`); + } + const container = this.createContainer(parent); + this.insertContainerIntoParent(container, parent); + return container; + } + + protected getContainer(): HTMLElement | null { + return document.querySelector(this.containerSelector); + } + + protected createContainer(parent: HTMLElement): HTMLElement { + const container = document.createElement('div'); + container.id = parent.id + '_' + this.id(); + return container; + } + + protected initializeContainer(container: HTMLElement): void { + container.classList.add(IvyUIExtension.UI_EXTENSION_CLASS, this.containerClass()); + } + + protected getParentContainer(): HTMLElement { + return document.querySelector(this.parentContainerSelector)!; + } + + protected insertContainerIntoParent(container: HTMLElement, parent: HTMLElement): void { + parent.insertBefore(container, parent.firstChild); + } + + protected setContainerVisible(visible: boolean): void { + if (visible) { + this.containerElement?.classList.remove('hidden'); + } else { + this.containerElement?.classList.add('hidden'); + } + } + + protected isContainerVisible(): boolean { + return this.containerElement && !this.containerElement.classList.contains('hidden'); + } + + protected toggleContainerVisible(): void { + this.setContainerVisible(!this.isContainerVisible()); + } +} diff --git a/packages/inscription/package.json b/packages/inscription/package.json index eaa2a55f..8c5745f0 100644 --- a/packages/inscription/package.json +++ b/packages/inscription/package.json @@ -10,9 +10,9 @@ "url": "https://github.com/axonivy/glsp-editor-client" }, "dependencies": { - "@axonivy/inscription-core": "~11.3.0-next.1026", - "@axonivy/inscription-editor": "~11.3.0-next.1026", - "@axonivy/inscription-protocol": "~11.3.0-next.1026", + "@axonivy/inscription-core": "~11.3.0-next.1028", + "@axonivy/inscription-editor": "~11.3.0-next.1028", + "@axonivy/inscription-protocol": "~11.3.0-next.1028", "@axonivy/process-editor": "11.3.0-next", "@eclipse-glsp/client": "~2.1.0", "react": "^18.2.0", diff --git a/packages/inscription/src/inscription/inscription-ui.tsx b/packages/inscription/src/inscription/inscription-ui.tsx index c41739cb..b4c81658 100644 --- a/packages/inscription/src/inscription/inscription-ui.tsx +++ b/packages/inscription/src/inscription/inscription-ui.tsx @@ -1,17 +1,15 @@ import { InscriptionClientJsonRpc, IvyScriptLanguage } from '@axonivy/inscription-core'; import { ClientContextProvider, MonacoEditorUtil, ThemeContextProvider, initQueryClient } from '@axonivy/inscription-editor'; import { InscriptionClient, InscriptionContext } from '@axonivy/inscription-protocol'; -import { SwitchThemeActionHandler } from '@axonivy/process-editor'; +import { SwitchThemeActionHandler, IvyUIExtension } from '@axonivy/process-editor'; import { SwitchThemeAction } from '@axonivy/process-editor-protocol'; import { - AbstractUIExtension, Action, GArgument, GModelRoot, IActionHandler, ISelectionListener, SelectionService, - SetUIExtensionVisibilityAction, isNotUndefined, isOpenable } from '@eclipse-glsp/client'; @@ -26,8 +24,8 @@ import { EnableInscriptionAction, ToggleInscriptionAction } from './action'; const JSX = { createElement: React.createElement }; @injectable() -export class InscriptionUi extends AbstractUIExtension implements IActionHandler, ISelectionListener { - static readonly ID = 'inscriptionUi'; +export class InscriptionUi extends IvyUIExtension implements IActionHandler, ISelectionListener { + static readonly ID = 'inscription-ui'; @inject(SelectionService) protected readonly selectionService: SelectionService; @inject(SwitchThemeActionHandler) @optional() protected switchThemeHandler?: SwitchThemeActionHandler; @@ -52,20 +50,6 @@ export class InscriptionUi extends AbstractUIExtension implements IActionHandler return 'inscription-ui-container'; } - protected initialize() { - const baseDiv = document.getElementById('inscription'); - if (!baseDiv) { - this.logger.warn(this, `Could not obtain inscription base container for initializing UI extension ${this.id}`, this); - return false; - } - this.containerElement = this.getOrCreateContainer(baseDiv.id); - this.initializeContents(this.containerElement); - if (baseDiv) { - baseDiv.insertBefore(this.containerElement, baseDiv.firstChild); - } - return true; - } - protected initializeContents(containerElement: HTMLElement) { this.changeUiVisiblitiy(false); this.inscriptionContext = this.initInscriptionContext(); @@ -115,7 +99,7 @@ export class InscriptionUi extends AbstractUIExtension implements IActionHandler handle(action: Action) { if (EnableInscriptionAction.is(action)) { this.action = action; - return SetUIExtensionVisibilityAction.create({ extensionId: InscriptionUi.ID, visible: true }); + this.initialize(); } if (ToggleInscriptionAction.is(action)) { if (!this.inscriptionElement) { @@ -146,18 +130,10 @@ export class InscriptionUi extends AbstractUIExtension implements IActionHandler } private changeUiVisiblitiy(force?: boolean) { - const baseDiv = document.getElementById('inscription'); - if (!baseDiv) { - return; - } if (force !== undefined) { - if (force) { - baseDiv.classList.remove('hidden'); - } else { - baseDiv.classList.add('hidden'); - } + this.setContainerVisible(force); } else { - baseDiv.classList.toggle('hidden'); + this.toggleContainerVisible(); } window.dispatchEvent(new CustomEvent('resize')); } diff --git a/playwright/tests/page-objects/inscription.ts b/playwright/tests/page-objects/inscription.ts index 19367479..88bc87c5 100644 --- a/playwright/tests/page-objects/inscription.ts +++ b/playwright/tests/page-objects/inscription.ts @@ -6,7 +6,7 @@ export class Inscription { constructor(page: Page) { this.page = page; - this.view = this.page.locator('#inscription'); + this.view = this.page.locator('#inscription-ui'); } locator() { diff --git a/playwright/tests/page-objects/toolbar.ts b/playwright/tests/page-objects/toolbar.ts index bfe7861d..b71dc953 100644 --- a/playwright/tests/page-objects/toolbar.ts +++ b/playwright/tests/page-objects/toolbar.ts @@ -16,7 +16,7 @@ export class Toolbar { constructor(page: Page) { this.page = page; - this.toolbar = this.page.locator('#sprotty_ivy-tool-bar'); + this.toolbar = this.page.locator('#ivy-tool-bar'); this.toolbarMenu = new Menu(page, this.toolbar.locator('.tool-bar-menu')); this.optionsMenu = new OptionsMenu(page, this.toolbar.locator('.tool-bar-options-menu')); this.defaultTool = this.toolbar.locator('#btn_default_tools'); diff --git a/playwright/tests/page-objects/viewport.ts b/playwright/tests/page-objects/viewport.ts index 8705e159..298f96d2 100644 --- a/playwright/tests/page-objects/viewport.ts +++ b/playwright/tests/page-objects/viewport.ts @@ -2,7 +2,7 @@ import { expect, type Locator, type Page } from '@playwright/test'; import { Point } from './types'; import { graphLocator } from './graph'; -export const ORIGIN_VIEWPORT = 'scale(1) translate(0,48)' as const; +export const ORIGIN_VIEWPORT = 'scale(1) translate(0,0)' as const; export class ViewportBar { protected readonly page: Page; @@ -73,6 +73,6 @@ export class ViewportBar { } private gridPosition(gridMove: Point) { - return new RegExp(`background-position: ${8 + gridMove.x}px ${56 + gridMove.y}px;`); + return new RegExp(`background-position: ${8 + gridMove.x}px ${8 + gridMove.y}px;`); } } diff --git a/playwright/tests/standalone/diagram/element.spec.ts b/playwright/tests/standalone/diagram/element.spec.ts index 9f20dfb1..0b3d9d91 100644 --- a/playwright/tests/standalone/diagram/element.spec.ts +++ b/playwright/tests/standalone/diagram/element.spec.ts @@ -38,13 +38,13 @@ test.describe('diagram', () => { const bottomRightHandleBounds = await bottomRightHandle.boundingBox(); const topLeftHandle = element.getResizeHandle('top-left'); const topLeftHandleBounds = await topLeftHandle.boundingBox(); - await element.expectPosition({ x: 240, y: 122 }); + await element.expectPosition({ x: 240, y: 170 }); await element.expectSize(112, 60); await element.resize(bottomRightHandle, { x: 800, y: 700 }); await processEditor.resetSelection(); await element.select(); - await element.expectPosition({ x: 240, y: 122 }); - await element.expectSize(560, 532); + await element.expectPosition({ x: 240, y: 170 }); + await element.expectSize(560, 484); expect(topLeftHandleBounds).toStrictEqual(await topLeftHandle.boundingBox()); expect(bottomRightHandleBounds).not.toStrictEqual(await bottomRightHandle.boundingBox()); }); @@ -58,13 +58,13 @@ test.describe('diagram', () => { const bottomRightHandleBounds = await bottomRightHandle.boundingBox(); const topLeftHandle = element.getResizeHandle('top-left'); const topLeftHandleBounds = await topLeftHandle.boundingBox(); - await element.expectPosition({ x: 240, y: 122 }); + await element.expectPosition({ x: 240, y: 170 }); await element.expectSize(112, 60); await element.resize(topLeftHandle, { x: 300, y: 200 }); await processEditor.resetSelection(); await element.select(); await element.expectPosition({ x: 304, y: 154 }); - await element.expectSize(48, 28); + await element.expectSize(48, 76); expect(bottomRightHandleBounds).toStrictEqual(await bottomRightHandle.boundingBox()); expect(topLeftHandleBounds).not.toStrictEqual(await topLeftHandle.boundingBox()); }); diff --git a/playwright/tests/standalone/key-listener/move.spec.ts b/playwright/tests/standalone/key-listener/move.spec.ts index 92c16c79..d3894fa4 100644 --- a/playwright/tests/standalone/key-listener/move.spec.ts +++ b/playwright/tests/standalone/key-listener/move.spec.ts @@ -67,15 +67,15 @@ test.describe('move with arrow keys', () => { await viewport.expectGraphTransform(ORIGIN_VIEWPORT); await page.keyboard.press('ArrowUp'); - await viewport.expectGraphTransform('scale(1) translate(0,56)'); + await viewport.expectGraphTransform('scale(1) translate(0,8)'); await page.keyboard.press('ArrowLeft'); - await viewport.expectGraphTransform('scale(1) translate(8,56)'); + await viewport.expectGraphTransform('scale(1) translate(8,8)'); await page.keyboard.press('ArrowDown'); - await viewport.expectGraphTransform('scale(1) translate(8,48)'); + await viewport.expectGraphTransform('scale(1) translate(8,0)'); await page.keyboard.press('ArrowRight'); - await viewport.expectGraphTransform('scale(1) translate(0,48)'); + await viewport.expectGraphTransform('scale(1) translate(0,0)'); }); }); diff --git a/playwright/tests/standalone/viewport/scroll.spec.ts b/playwright/tests/standalone/viewport/scroll.spec.ts index 9fc931a2..3e838fd9 100644 --- a/playwright/tests/standalone/viewport/scroll.spec.ts +++ b/playwright/tests/standalone/viewport/scroll.spec.ts @@ -14,10 +14,10 @@ test.describe('viewport bar', () => { test('scroll vertical', async ({ page }) => { await page.mouse.wheel(0, 100); - await expectScroll('scale(1) translate(0,-52)', { x: 0, y: -100 }); + await expectScroll('scale(1) translate(0,-100)', { x: 0, y: -100 }); await page.mouse.wheel(0, -200); - await expectScroll('scale(1) translate(0,148)', { x: 0, y: 100 }); + await expectScroll('scale(1) translate(0,100)', { x: 0, y: 100 }); await page.mouse.wheel(0, 100); await expectScroll(ORIGIN_VIEWPORT, { x: 0, y: 0 }); @@ -25,10 +25,10 @@ test.describe('viewport bar', () => { test('scroll horizontal', async ({ page }) => { await page.mouse.wheel(100, 0); - await expectScroll('scale(1) translate(-100,48)', { x: -100, y: 0 }); + await expectScroll('scale(1) translate(-100,0)', { x: -100, y: 0 }); await page.mouse.wheel(-200, 0); - await expectScroll('scale(1) translate(100,48)', { x: 100, y: 0 }); + await expectScroll('scale(1) translate(100,0)', { x: 100, y: 0 }); await page.mouse.wheel(100, 0); await expectScroll(ORIGIN_VIEWPORT, { x: 0, y: 0 }); @@ -37,10 +37,10 @@ test.describe('viewport bar', () => { test('scroll horizontal (shift)', async ({ page }) => { await page.keyboard.down('Shift'); await page.mouse.wheel(0, 100); - await expectScroll('scale(1) translate(-100,48)', { x: -100, y: 0 }); + await expectScroll('scale(1) translate(-100,0)', { x: -100, y: 0 }); await page.mouse.wheel(0, -200); - await expectScroll('scale(1) translate(100,48)', { x: 100, y: 0 }); + await expectScroll('scale(1) translate(100,0)', { x: 100, y: 0 }); await page.mouse.wheel(0, 100); await expectScroll(ORIGIN_VIEWPORT, { x: 0, y: 0 }); diff --git a/yarn.lock b/yarn.lock index 3b26e968..986e0379 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,25 +7,25 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@axonivy/inscription-core@11.3.0-next.1026+cc6e9c2", "@axonivy/inscription-core@~11.3.0-next.1026": - version "11.3.0-next.1026" - resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-core/-/inscription-core-11.3.0-next.1026.tgz#cfc8636989dedbec2b4ce63f037b1517fa63aef9" - integrity sha512-Qu2NbbnHEOLL2BxrUh1NBuYmD5fr/giPNnJhy+0gMQ5ZUad3oD/1IcbFFBPawc5WBRjuAnkWqsW/Xypxo2Em1w== +"@axonivy/inscription-core@11.3.0-next.1028+1c12a00", "@axonivy/inscription-core@~11.3.0-next.1028": + version "11.3.0-next.1028" + resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-core/-/inscription-core-11.3.0-next.1028.tgz#ff14fc707a204f3a70bcc465f827ab3cc7f2474d" + integrity sha512-jegqhf7+p4cjuMG14RBHyWVb0RXVp4YITd7E4M6c5FtuIiDWN61PXjBr6lmDB0Ecy0L5cjY8IZx3Kmn7Xc/V5A== dependencies: - "@axonivy/inscription-protocol" "11.3.0-next.1026+cc6e9c2" + "@axonivy/inscription-protocol" "11.3.0-next.1028+1c12a00" "@axonivy/jsonrpc" "11.3.0-next.71" monaco-editor "^0.44.0" monaco-editor-workers "^0.44.0" monaco-languageclient "^6.6.1" vscode-languageserver-protocol "^3.17.5" -"@axonivy/inscription-editor@~11.3.0-next.1026": - version "11.3.0-next.1026" - resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-editor/-/inscription-editor-11.3.0-next.1026.tgz#066a0be6644b8f1412e7c10605bd3f11bbc733fe" - integrity sha512-MHsqZGk80gA9esPIg0dYWTLcqRq0NYjFgERd6ap3NFbrkCOEQHs7Rxe8lKjt8o2lKKwEBIfX6w112+80/4enrg== +"@axonivy/inscription-editor@~11.3.0-next.1028": + version "11.3.0-next.1028" + resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-editor/-/inscription-editor-11.3.0-next.1028.tgz#68be23c209450b018432a0419a85473bc292bc50" + integrity sha512-QN3Th2tPyrguL2HJNIrSfiUAFTvBJhT5uCuZU3yUpnqQ7xPFRkcj8RGnITy9IMFBWB0D+aIo6r6GoQ3pt5KrXA== dependencies: - "@axonivy/inscription-core" "11.3.0-next.1026+cc6e9c2" - "@axonivy/inscription-protocol" "11.3.0-next.1026+cc6e9c2" + "@axonivy/inscription-core" "11.3.0-next.1028+1c12a00" + "@axonivy/inscription-protocol" "11.3.0-next.1028+1c12a00" "@monaco-editor/react" "^4.6.0" "@radix-ui/react-accordion" "^1.1.2" "@radix-ui/react-checkbox" "^1.0.4" @@ -45,10 +45,10 @@ react-aria "^3.31.0" react-error-boundary "^4.0.12" -"@axonivy/inscription-protocol@11.3.0-next.1026+cc6e9c2", "@axonivy/inscription-protocol@~11.3.0-next.1026": - version "11.3.0-next.1026" - resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-protocol/-/inscription-protocol-11.3.0-next.1026.tgz#af9b15e0d1eb52e0115dbe9cda93419476d82c93" - integrity sha512-e1NfpMS2kf9dFxr4fIvayCMN5bB0pGpBsRv8iuyx6gAcqrPcVBr+UqU2MlLvi2Q3U+07UBiCrIuQ3Nr6Hk5Mkw== +"@axonivy/inscription-protocol@11.3.0-next.1028+1c12a00", "@axonivy/inscription-protocol@~11.3.0-next.1028": + version "11.3.0-next.1028" + resolved "https://npmjs-registry.ivyteam.ch/@axonivy/inscription-protocol/-/inscription-protocol-11.3.0-next.1028.tgz#b5ca50e14e0efbe2b2d68bf6708f1472443186e4" + integrity sha512-PhSPBWUakO5xqypGtXe5IqNTXkcftgTaZg0JPahTSRAxi6+7VGoUrBaxTFWl44X1YtY2lH6YTZTzDSAHNsEvGQ== "@axonivy/jsonrpc@11.3.0-next.71": version "11.3.0-next.71"