From 1a166ce10851a0961ddec5e2b07718699cd7af42 Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov Date: Wed, 11 Dec 2024 17:02:00 +0400 Subject: [PATCH 1/4] wip --- .../integration-test/project-view/actions.ts | 4 +- .../project-view/componentBrowser.spec.ts | 17 +-- .../graphNodeVisualization.spec.ts | 2 +- .../integration-test/project-view/locate.ts | 4 +- .../project-view/nodeComments.spec.ts | 8 +- .../components/ComponentBrowser.vue | 2 +- .../project-view/components/ComponentMenu.vue | 4 +- .../project-view/components/GraphEditor.vue | 11 +- .../GraphEditor/CreateNodeFromPortButton.vue | 111 ++++++++++++++++++ .../components/GraphEditor/GraphNode.vue | 12 +- .../GraphEditor/GraphNodeOutputPorts.vue | 16 ++- .../GraphEditor/GraphVisualization.vue | 4 +- .../components/SmallPlusButton.vue | 35 ------ .../providers/graphEditorState.ts | 15 +++ 14 files changed, 173 insertions(+), 72 deletions(-) create mode 100644 app/gui/src/project-view/components/GraphEditor/CreateNodeFromPortButton.vue delete mode 100644 app/gui/src/project-view/components/SmallPlusButton.vue create mode 100644 app/gui/src/project-view/providers/graphEditorState.ts diff --git a/app/gui/integration-test/project-view/actions.ts b/app/gui/integration-test/project-view/actions.ts index 96743db1f575..00522b0410aa 100644 --- a/app/gui/integration-test/project-view/actions.ts +++ b/app/gui/integration-test/project-view/actions.ts @@ -66,9 +66,9 @@ export async function dragNodeByBinding(page: Page, nodeBinding: string, x: numb } /** Move mouse away to avoid random hover events and wait for any circular menus to disappear. */ -export async function ensureNoCircularMenusVisibleDueToHovering(page: Page) { +export async function ensureNoComponentMenusVisibleDueToHovering(page: Page) { await page.mouse.move(-1000, 0) - await expect(locate.circularMenu(page)).toBeHidden() + await expect(locate.componentMenu(page)).toBeHidden() } /** Ensure no nodes are selected. */ diff --git a/app/gui/integration-test/project-view/componentBrowser.spec.ts b/app/gui/integration-test/project-view/componentBrowser.spec.ts index 3e49c831d834..0f42c66fd7a7 100644 --- a/app/gui/integration-test/project-view/componentBrowser.spec.ts +++ b/app/gui/integration-test/project-view/componentBrowser.spec.ts @@ -73,25 +73,20 @@ test('Different ways of opening Component Browser', async ({ page }) => { await expectAndCancelBrowser(page, '', 'selected') }) -test('Opening Component Browser with small plus buttons', async ({ page }) => { +test('Opening Component Browser from output port buttons', async ({ page }) => { await actions.goToGraph(page) // Small (+) button shown when node is hovered - await page.keyboard.press('Escape') - await page.mouse.move(100, 80) - await expect(locate.smallPlusButton(page)).toBeHidden() await locate.graphNodeIcon(locate.graphNodeByBinding(page, 'selected')).hover() - await expect(locate.smallPlusButton(page)).toBeVisible() - await locate.smallPlusButton(page).click() + await expect(locate.createNodeFromPort(page)).toBeVisible() + await locate.createNodeFromPort(page).click() await expectAndCancelBrowser(page, '', 'selected') - // Small (+) button shown when node is sole selection + // Small (+) button shown when node is selected await page.keyboard.press('Escape') - await page.mouse.move(300, 300) - await expect(locate.smallPlusButton(page)).toBeHidden() await locate.graphNodeByBinding(page, 'selected').click() - await expect(locate.smallPlusButton(page)).toBeVisible() - await locate.smallPlusButton(page).click() + await expect(locate.createNodeFromPort(page)).toBeVisible() + await locate.createNodeFromPort(page).click() await expectAndCancelBrowser(page, '', 'selected') }) diff --git a/app/gui/integration-test/project-view/graphNodeVisualization.spec.ts b/app/gui/integration-test/project-view/graphNodeVisualization.spec.ts index bf8556275791..af27ca9159c9 100644 --- a/app/gui/integration-test/project-view/graphNodeVisualization.spec.ts +++ b/app/gui/integration-test/project-view/graphNodeVisualization.spec.ts @@ -9,7 +9,7 @@ test('Node can open and load visualization', async ({ page }) => { await actions.goToGraph(page) const node = locate.graphNode(page).last() await node.click({ position: { x: 8, y: 8 } }) - await expect(locate.circularMenu(page)).toExist() + await expect(locate.componentMenu(page)).toExist() await locate.toggleVisualizationButton(page).click() await expect(locate.anyVisualization(page)).toExist() await expect(locate.loadingVisualization(page)).toHaveCount(0) diff --git a/app/gui/integration-test/project-view/locate.ts b/app/gui/integration-test/project-view/locate.ts index e57546a852a2..d302b429765c 100644 --- a/app/gui/integration-test/project-view/locate.ts +++ b/app/gui/integration-test/project-view/locate.ts @@ -79,11 +79,11 @@ export const graphEditor = componentLocator('.GraphEditor') export const codeEditor = componentLocator('.CodeEditor') export const anyVisualization = componentLocator('.GraphVisualization') export const loadingVisualization = componentLocator('.LoadingVisualization') -export const circularMenu = componentLocator('.CircularMenu') +export const componentMenu = componentLocator('.ComponentMenu') export const addNewNodeButton = componentLocator('.PlusButton') export const componentBrowser = componentLocator('.ComponentBrowser') export const nodeOutputPort = componentLocator('.outputPortHoverArea') -export const smallPlusButton = componentLocator('.SmallPlusButton') +export const createNodeFromPort = componentLocator('.CreateNodeFromPortButton') export const editorRoot = componentLocator('.CodeMirror') export const nodeComment = componentLocator('.GraphNodeComment') export const nodeCommentContent = componentLocator('.GraphNodeComment div[contentEditable]') diff --git a/app/gui/integration-test/project-view/nodeComments.spec.ts b/app/gui/integration-test/project-view/nodeComments.spec.ts index c9e386cae4e0..d48c1f7ece7e 100644 --- a/app/gui/integration-test/project-view/nodeComments.spec.ts +++ b/app/gui/integration-test/project-view/nodeComments.spec.ts @@ -22,8 +22,8 @@ test('Start editing comment via menu', async ({ page }) => { await actions.goToGraph(page) const node = locate.graphNodeByBinding(page, 'final') await node.click() - await locate.circularMenu(node).getByRole('button', { name: 'More' }).click() - await locate.circularMenu(node).getByRole('button', { name: 'Comment' }).click() + await locate.componentMenu(node).getByRole('button', { name: 'More' }).click() + await locate.componentMenu(node).getByRole('button', { name: 'Comment' }).click() await expect(locate.nodeCommentContent(node)).toBeFocused() }) @@ -60,8 +60,8 @@ test('Add new comment via menu', async ({ page }) => { const nodeComment = locate.nodeCommentContent(node) await node.click() - await locate.circularMenu(node).getByRole('button', { name: 'More' }).click() - await locate.circularMenu(node).getByRole('button', { name: 'Comment' }).click() + await locate.componentMenu(node).getByRole('button', { name: 'More' }).click() + await locate.componentMenu(node).getByRole('button', { name: 'Comment' }).click() await expect(locate.nodeCommentContent(node)).toBeFocused() const NEW_COMMENT = 'New comment text' await nodeComment.fill(NEW_COMMENT) diff --git a/app/gui/src/project-view/components/ComponentBrowser.vue b/app/gui/src/project-view/components/ComponentBrowser.vue index 235594858052..db798b33329f 100644 --- a/app/gui/src/project-view/components/ComponentBrowser.vue +++ b/app/gui/src/project-view/components/ComponentBrowser.vue @@ -380,7 +380,7 @@ const handler = componentBrowserBindings.handler({ :nodeSize="inputSize" :nodePosition="nodePosition" :scale="1" - :isCircularMenuVisible="false" + :isComponentMenuVisible="false" :isFullscreen="false" :isFullscreenAllowed="false" :isResizable="false" diff --git a/app/gui/src/project-view/components/ComponentMenu.vue b/app/gui/src/project-view/components/ComponentMenu.vue index 8911369d59ee..e40d7ceaa84b 100644 --- a/app/gui/src/project-view/components/ComponentMenu.vue +++ b/app/gui/src/project-view/components/ComponentMenu.vue @@ -13,7 +13,7 @@ const isDropdownOpened = ref(false) @@ -33,8 +29,8 @@ const hovered = ref(false) --strokeWidth: 1.5px; --leftOffset: 16px; --topOffset: 40px; - --color-dimmed: color-mix(in oklab, var(--node-color-port) 60%, white 40%); - --color: var(--node-color-port); + --color-dimmed: color-mix(in oklab, var(--color-node-primary) 60%, white 40%); + --color: var(--color-node-primary); } .connection { @@ -43,7 +39,7 @@ const hovered = ref(false) var(--output-port-hovered-extra-width) * var(--direct-hover-animation) ); width: var(--width); - height: calc((var(--topOffset) - var(--direct-hover-offset) + 1px) * var(--hover-animation)); + height: calc((var(--topOffset) - var(--direct-hover-offset) + 2px) * var(--hover-animation)); transform: translate( calc(var(--port-clip-start) * (100% + 1px) + var(--leftOffset) - var(--width) / 2), calc(var(--node-size-y) + var(--direct-hover-offset) - var(--output-port-overlap)) @@ -93,7 +89,8 @@ const hovered = ref(false) transition: color 0.2s ease; } } -.newNodeHoverArea { + +.hoverArea { --margin: 4px; --width: calc(var(--radius) * 2 + var(--margin) * 2); fill: transparent; diff --git a/app/gui/src/project-view/components/GraphEditor/GraphNode.vue b/app/gui/src/project-view/components/GraphEditor/GraphNode.vue index 7f2d35db52ad..671175240107 100644 --- a/app/gui/src/project-view/components/GraphEditor/GraphNode.vue +++ b/app/gui/src/project-view/components/GraphEditor/GraphNode.vue @@ -17,7 +17,6 @@ import GraphNodeOutputPorts from '@/components/GraphEditor/GraphNodeOutputPorts. import GraphVisualization from '@/components/GraphEditor/GraphVisualization.vue' import type { NodeCreationOptions } from '@/components/GraphEditor/nodeCreation' import PointFloatingMenu from '@/components/PointFloatingMenu.vue' -import SmallPlusButton from '@/components/SmallPlusButton.vue' import SvgIcon from '@/components/SvgIcon.vue' import { useDoubleClick } from '@/composables/doubleClick' import { usePointer, useResizeObserver } from '@/composables/events' diff --git a/app/gui/src/project-view/providers/graphEditorState.ts b/app/gui/src/project-view/providers/graphEditorState.ts index 8d395b986771..5d200d6828a3 100644 --- a/app/gui/src/project-view/providers/graphEditorState.ts +++ b/app/gui/src/project-view/providers/graphEditorState.ts @@ -9,7 +9,7 @@ export interface GraphEditorState { } export { provideGraphEditorState, useGraphEditorState } -const { provideFn: provideGraphEditorState, injectFn: useGraphEditorState } = createContextStore( +const [provideGraphEditorState, useGraphEditorState] = createContextStore( 'Graph editor state', identity, ) From 0c116ee4db2d7a2471bbde29add214a6c43ad107 Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov Date: Tue, 17 Dec 2024 16:20:06 +0400 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df253fba6e9..5ac8c6d31d0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Next Next Release +#### Enso IDE + +- [Round ‘Add component’ button under the component menu replaced by a small + button protruding from the output port.][11836]. + +[11836]: https://github.com/enso-org/enso/pull/11836 + #### Enso Language & Runtime - [Intersection types & type checks][11600] From da6ddc57e3949b72c6f8107d5e1524fc7d054b09 Mon Sep 17 00:00:00 2001 From: Ilya Bogdanov Date: Wed, 18 Dec 2024 15:36:52 +0400 Subject: [PATCH 4/4] Fix integration test --- .../project-view/typesOnNodeHover.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/gui/integration-test/project-view/typesOnNodeHover.spec.ts b/app/gui/integration-test/project-view/typesOnNodeHover.spec.ts index 32811c648382..eea37fd602d7 100644 --- a/app/gui/integration-test/project-view/typesOnNodeHover.spec.ts +++ b/app/gui/integration-test/project-view/typesOnNodeHover.spec.ts @@ -15,17 +15,17 @@ async function assertTypeLabelOnNode( ) { // Ensure the visualization button won't be covered by any other parts of another node (e.g. a comment). await bringNodeToFront(page, node) - await node.hover({ position: { x: 8, y: 8 } }) - await locate.toggleVisualizationButton(node).click() + await node.hover({ position: { x: 8, y: 8 }, force: true }) + await locate.toggleVisualizationButton(node).click({ force: true }) const targetLabel = node.locator('.node-type').first() await expect(targetLabel).toHaveText(type.short) await expect(targetLabel).toHaveAttribute('title', type.full) - await locate.toggleVisualizationButton(node).click() + await locate.toggleVisualizationButton(node).click({ force: true }) await actions.deselectNodes(page) } async function bringNodeToFront(page: Page, node: Locator) { - await node.click({ position: { x: 8, y: 8 } }) + await node.click({ position: { x: 0, y: 8 }, force: true }) await page.keyboard.press('Escape') }