diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 824c09b829..562ea3cee4 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -70,6 +70,7 @@ Switch all usage of the logger to the fluent API to prepare for the addition of - https://github.com/eclipse-sirius/sirius-web/issues/6250[#6250] [selection] Move the selection dialog default settings to the backend Improve the log message used when logging exceptions. - https://github.com/eclipse-sirius/sirius-web/issues/6366[#6366] [diagram] Extract layout tools in several hooks. +- https://github.com/eclipse-sirius/sirius-web/issues/6336[#6336] [diagram] Move the retrieval of the connector tools in a dedicated hook. diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.tsx index d7277faccd..bd40681522 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.tsx @@ -11,69 +11,24 @@ * Obeo - initial API and implementation *******************************************************************************/ -import { gql, useQuery } from '@apollo/client'; import { IconOverlay, useMultiToast } from '@eclipse-sirius/sirius-components-core'; import ListItemIcon from '@mui/material/ListItemIcon'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Typography from '@mui/material/Typography'; import { Edge, Node, useReactFlow } from '@xyflow/react'; -import { memo, useContext, useEffect } from 'react'; -import { DiagramContext } from '../../contexts/DiagramContext'; -import { DiagramContextValue } from '../../contexts/DiagramContext.types'; +import { memo, useEffect } from 'react'; import { EdgeData, NodeData } from '../DiagramRenderer.types'; -import { - ConnectorContextualMenuProps, - GetConnectorToolsData, - GetConnectorToolsVariables, - GQLDiagramDescription, - GQLRepresentationDescription, - GQLTool, -} from './ConnectorContextualMenu.types'; +import { ConnectorContextualMenuProps, GQLTool } from './ConnectorContextualMenu.types'; import { useConnector } from './useConnector'; +import { useConnectorPaletteContents } from './useConnectorPaletteContents'; import { useSingleClickOnTwoDiagramElementTool } from './useSingleClickOnTwoDiagramElementTool'; import { useTemporaryEdge } from './useTemporaryEdge'; -export const getConnectorToolsQuery = gql` - query getConnectorTools( - $editingContextId: ID! - $representationId: ID! - $sourceDiagramElementId: ID! - $targetDiagramElementId: ID! - ) { - viewer { - editingContext(editingContextId: $editingContextId) { - representation(representationId: $representationId) { - description { - ... on DiagramDescription { - connectorTools( - sourceDiagramElementId: $sourceDiagramElementId - targetDiagramElementId: $targetDiagramElementId - ) { - id - label - iconURL - ... on SingleClickOnTwoDiagramElementsTool { - dialogDescriptionId - } - } - } - } - } - } - } - } -`; - -const isDiagramDescription = ( - representationDescription: GQLRepresentationDescription -): representationDescription is GQLDiagramDescription => representationDescription.__typename === 'DiagramDescription'; - const ConnectorContextualMenuComponent = memo(({}: ConnectorContextualMenuProps) => { - const { editingContextId, diagramId } = useContext(DiagramContext); const { connection, position, onConnectorContextualMenuClose } = useConnector(); const { addTempConnectionLine, removeTempConnectionLine } = useTemporaryEdge(); - const { addMessages, addErrorMessage } = useMultiToast(); + const { addMessages } = useMultiToast(); const { screenToFlowPosition } = useReactFlow, Edge>(); const { invokeConnectorTool, data: invokeSingleClickOnTwoDiagramElementToolCalled } = useSingleClickOnTwoDiagramElementTool(); @@ -89,29 +44,7 @@ const ConnectorContextualMenuComponent = memo(({}: ConnectorContextualMenuProps) const sourceDiagramElementId = connectionSource?.dataset.id ?? ''; const targetDiagramElementId = connectionTarget?.dataset.id ?? ''; - const variables: GetConnectorToolsVariables = { - editingContextId, - representationId: diagramId, - sourceDiagramElementId, - targetDiagramElementId, - }; - const { loading, data, error } = useQuery(getConnectorToolsQuery, { - variables, - skip: !connectionSource || !connectionTarget, - }); - - useEffect(() => { - if (error) { - addErrorMessage(error.message); - } - }, [error]); - - const connectorTools: GQLTool[] = []; - const representationDescription: GQLRepresentationDescription | null | undefined = - data?.viewer.editingContext?.representation?.description; - if (representationDescription && isDiagramDescription(representationDescription)) { - representationDescription.connectorTools.forEach((tool) => connectorTools.push(tool)); - } + const { connectorTools, loading } = useConnectorPaletteContents(sourceDiagramElementId, targetDiagramElementId); useEffect(() => { if (connectorTools.length > 1) { @@ -120,11 +53,10 @@ const ConnectorContextualMenuComponent = memo(({}: ConnectorContextualMenuProps) }, [connection, connectorTools.length]); useEffect(() => { - if (!loading && connection && data && connectorTools.length === 0) { - onConnectorContextualMenuClose(); + if (!loading && connection && connectorTools.length === 0) { addMessages([{ body: 'No edge found between source and target selected', level: 'WARNING' }]); } - }, [loading, data, connection, connectorTools.length]); + }, [loading, connectorTools, connection, connectorTools.length]); useEffect(() => { return () => removeTempConnectionLine(); @@ -141,7 +73,7 @@ const ConnectorContextualMenuComponent = memo(({}: ConnectorContextualMenuProps) invokeConnectorTool(tool, sourceDiagramElementId, targetDiagramElementId, cursorPositionX, cursorPositionY); }; - if (!data || connectorTools.length <= 1) { + if (!connectorTools || connectorTools.length <= 1) { return null; } diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.types.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.types.ts index 868a5a6016..f3823391c0 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.types.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/ConnectorContextualMenu.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023, 2025 Obeo. + * Copyright (c) 2023, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -20,6 +20,10 @@ export interface ConnectorContextualMenuState { tool: GQLSingleClickOnTwoDiagramElementsTool | null; } +export interface GQLInvokeSingleClickOnTwoDiagramElementsToolVariables { + input: GQLInvokeSingleClickOnTwoDiagramElementsToolInput; +} + export interface GetConnectorToolsVariables { editingContextId: string; representationId: string; @@ -42,33 +46,6 @@ export interface GQLToolVariable { export type GQLToolVariableType = 'STRING' | 'OBJECT_ID' | 'OBJECT_ID_ARRAY'; -export interface GetConnectorToolsData { - viewer: GQLViewer; -} - -export interface GQLViewer { - editingContext: GQLEditingContext | null; -} - -export interface GQLEditingContext { - representation: GQLRepresentationMetadata | null; -} - -export interface GQLRepresentationMetadata { - description: GQLRepresentationDescription; -} - -export interface GQLRepresentationDescription { - __typename: string; -} - -export interface GQLDiagramDescription extends GQLRepresentationDescription { - connectorTools: GQLTool[]; -} - -export interface GQLInvokeSingleClickOnTwoDiagramElementsToolVariables { - input: GQLInvokeSingleClickOnTwoDiagramElementsToolInput; -} export interface GQLInvokeSingleClickOnTwoDiagramElementsToolInput { id: string; editingContextId: string; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.tsx new file mode 100644 index 0000000000..3d98e7aa32 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.tsx @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +import { gql, useQuery } from '@apollo/client'; +import { useContext, useEffect } from 'react'; + +import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; +import { DiagramContext } from '../../contexts/DiagramContext'; +import { DiagramContextValue } from '../../contexts/DiagramContext.types'; +import { + GetConnectorToolsData, + GetConnectorToolsVariables, + GQLDiagramDescription, + GQLRepresentationDescription, + GQLTool, + UseConnectorPaletteContentValue, +} from './useConnectorPaletteContents.types'; + +export const getConnectorToolsQuery = gql` + query getConnectorTools( + $editingContextId: ID! + $representationId: ID! + $sourceDiagramElementId: ID! + $targetDiagramElementId: ID! + ) { + viewer { + editingContext(editingContextId: $editingContextId) { + representation(representationId: $representationId) { + description { + ... on DiagramDescription { + connectorTools( + sourceDiagramElementId: $sourceDiagramElementId + targetDiagramElementId: $targetDiagramElementId + ) { + id + label + iconURL + ... on SingleClickOnTwoDiagramElementsTool { + dialogDescriptionId + } + } + } + } + } + } + } + } +`; + +const isDiagramDescription = ( + representationDescription: GQLRepresentationDescription +): representationDescription is GQLDiagramDescription => representationDescription.__typename === 'DiagramDescription'; + +export const useConnectorPaletteContents = ( + sourceDiagramElementId: string, + targetDiagramElementId: string +): UseConnectorPaletteContentValue => { + const { diagramId, editingContextId } = useContext(DiagramContext); + const { addErrorMessage } = useMultiToast(); + + const { + data, + loading, + error: paletteError, + } = useQuery(getConnectorToolsQuery, { + variables: { + editingContextId, + representationId: diagramId, + sourceDiagramElementId, + targetDiagramElementId, + }, + }); + + const description: GQLRepresentationDescription | undefined = + data?.viewer.editingContext?.representation?.description; + + const connectorTools: GQLTool[] | null = + description && isDiagramDescription(description) ? description.connectorTools : []; + + useEffect(() => { + if (paletteError) { + addErrorMessage(paletteError.message); + } + }, [paletteError]); + + return { connectorTools, loading }; +}; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.types.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.types.ts new file mode 100644 index 0000000000..fed990c48f --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/connector/useConnectorPaletteContents.types.ts @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2026 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ + +export interface GetConnectorToolsVariables { + editingContextId: string; + representationId: string; + sourceDiagramElementId: string; + targetDiagramElementId: string; +} + +export interface UseConnectorPaletteContentValue { + connectorTools: GQLTool[]; + loading: boolean; +} + +export interface GetConnectorToolsData { + viewer: GQLViewer; +} + +export interface GQLViewer { + editingContext: GQLEditingContext | null; +} + +export interface GQLEditingContext { + representation: GQLRepresentationMetadata | null; +} + +export interface GQLRepresentationMetadata { + description: GQLRepresentationDescription; +} + +export interface GQLRepresentationDescription { + __typename: string; +} + +export interface GQLDiagramDescription extends GQLRepresentationDescription { + connectorTools: GQLTool[]; +} + +export interface GQLTool { + id: string; + label: string; + iconURL: string[]; + __typename: string; +}