diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 031800075a4..abbe38e44a4 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -25,6 +25,7 @@ More existing APIs will be migrated to this new common pattern. * `public Optional acquireRepresentationEventProcessor(IRepresentationConfiguration configuration, IInput input)`; * `Flux getSubscription(String editingContextId, IRepresentationConfiguration representationConfiguration, IInput input);` - https://github.com/eclipse-sirius/sirius-web/issues/3623[#3623] [form] Remove `IWidgetSubscriptionManagerFactory` + - https://github.com/eclipse-sirius/sirius-web/issues/3634[#3634] [sirius-web] Removes `GraphQLNodeStyleFragment` from `NodeTypeRegistry`, you can contribute additional payloads for custom nodes with the extension point `apolloClientOptionsDocumentTransformConfigurersExtensionPoint` === Dependency update @@ -73,6 +74,7 @@ More existing APIs will be migrated to this new common pattern. This dialog presents diagram elements in a tree and allows to select them and update their visibility and status (e.g. hide, show, collapse). + image:doc/screenshots/diagramFilterView.png[Diagram Filter View, 70%] +- https://github.com/eclipse-sirius/sirius-web/issues/3634[#3634] [sirius-web] Add an extension point to transform GraphQL documents === Improvements diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.ts index 271738f49f8..c89fddd2c72 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.ts @@ -16,7 +16,6 @@ import { NodeTypeContextValue } from './NodeContext.types'; const value: NodeTypeContextValue = { nodeConverters: [], nodeLayoutHandlers: [], - graphQLNodeStyleFragments: [], nodeTypeContributions: [], }; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.types.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.types.ts index 3a1754d8c22..9ae863ed992 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.types.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/contexts/NodeContext.types.ts @@ -12,7 +12,6 @@ *******************************************************************************/ import { NodeProps } from 'reactflow'; import { INodeConverter } from '../converter/ConvertEngine.types'; -import { GraphQLNodeStyleFragment } from '../graphql/subscription/nodeFragment.types'; import { NodeData } from '../renderer/DiagramRenderer.types'; import { INodeLayoutHandler } from '../renderer/layout/LayoutEngine.types'; @@ -24,7 +23,6 @@ export interface NodeTypeContributionProps { export type NodeTypeContributionElement = React.ReactElement; export interface NodeTypeContextValue { - graphQLNodeStyleFragments: GraphQLNodeStyleFragment[]; nodeLayoutHandlers: INodeLayoutHandler[]; nodeConverters: INodeConverter[]; nodeTypeContributions: NodeTypeContributionElement[]; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramEventSubscription.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramEventSubscription.ts index e214eeb1d1e..c58ec8a9f65 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramEventSubscription.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramEventSubscription.ts @@ -12,9 +12,8 @@ *******************************************************************************/ import { diagramFragment } from './diagramFragment'; -import { GraphQLNodeStyleFragment } from './nodeFragment.types'; -export const diagramEventSubscription = (contributions: GraphQLNodeStyleFragment[]) => ` +export const diagramEventSubscription = ` subscription diagramEvent($input: DiagramEventInput!) { diagramEvent(input: $input) { ... on ErrorPayload { @@ -35,5 +34,5 @@ subscription diagramEvent($input: DiagramEventInput!) { } } -${diagramFragment(contributions)} +${diagramFragment} `; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramFragment.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramFragment.ts index 677c53529ea..31930ef6fcc 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramFragment.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/diagramFragment.ts @@ -14,9 +14,8 @@ import { edgeFragment } from './edgeFragment'; import { insideLabelFragment, labelFragment, outsideLabelFragment } from './labelFragment'; import { nodeFragment } from './nodeFragment'; -import { GraphQLNodeStyleFragment } from './nodeFragment.types'; -export const diagramFragment = (contributions: GraphQLNodeStyleFragment[]) => ` +export const diagramFragment = ` fragment diagramFragment on Diagram { id targetObjectId @@ -73,7 +72,7 @@ fragment diagramFragment on Diagram { } } -${nodeFragment(contributions)} +${nodeFragment} ${edgeFragment} ${labelFragment} ${insideLabelFragment} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.ts index 8d0830bdb06..5d753b92374 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.ts @@ -10,9 +10,8 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { GraphQLNodeStyleFragment } from './nodeFragment.types'; -export const nodeFragment = (contributions: GraphQLNodeStyleFragment[]) => ` +export const nodeFragment = ` fragment nodeFragment on Node { id type @@ -48,14 +47,6 @@ fragment nodeFragment on Node { ... on IconLabelNodeStyle { background } - ${contributions.map( - (nodeStyle) => - ` - ... on ${nodeStyle.type} { - ${nodeStyle.fields} - } - ` - )} } childrenLayoutStrategy { __typename diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.types.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.types.ts index 985f33ec475..2a0dca751ff 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.types.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/graphql/subscription/nodeFragment.types.ts @@ -91,8 +91,3 @@ export interface GQLImageNodeStyle extends GQLNodeStyle { export interface GQLIconLabelNodeStyle extends GQLNodeStyle { background: string; } - -export interface GraphQLNodeStyleFragment { - type: string; - fields: string; -} diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts index 592e31e8edf..d653a02a194 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/index.ts @@ -24,7 +24,7 @@ export type { GQLNodeDescription } from './graphql/query/nodeDescriptionFragment export type { GQLDiagram, GQLNodeLayoutData } from './graphql/subscription/diagramFragment.types'; export type { GQLEdge } from './graphql/subscription/edgeFragment.types'; export { GQLViewModifier } from './graphql/subscription/nodeFragment.types'; -export type { GQLNode, GQLNodeStyle, GraphQLNodeStyleFragment } from './graphql/subscription/nodeFragment.types'; +export type { GQLNode, GQLNodeStyle } from './graphql/subscription/nodeFragment.types'; export { BorderNodePosition as BorderNodePosition } from './renderer/DiagramRenderer.types'; export type { Diagram, NodeData } from './renderer/DiagramRenderer.types'; export { Label } from './renderer/Label'; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/representation/DiagramRepresentation.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/representation/DiagramRepresentation.tsx index 7dcbec8c969..c1596aaaba8 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/representation/DiagramRepresentation.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/representation/DiagramRepresentation.tsx @@ -13,18 +13,15 @@ import { gql, OnDataOptions, useQuery, useSubscription } from '@apollo/client'; import { RepresentationComponentProps, useMultiToast } from '@eclipse-sirius/sirius-components-core'; -import { useContext, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { ReactFlowProvider } from 'reactflow'; import { DiagramContext } from '../contexts/DiagramContext'; import { DiagramDescriptionContext } from '../contexts/DiagramDescriptionContext'; -import { NodeTypeContext } from '../contexts/NodeContext'; -import { NodeTypeContextValue } from '../contexts/NodeContext.types'; import { diagramEventSubscription } from '../graphql/subscription/diagramEventSubscription'; import { GQLDiagramEventPayload, GQLDiagramRefreshedEventPayload, } from '../graphql/subscription/diagramEventSubscription.types'; -import { GraphQLNodeStyleFragment } from '../graphql/subscription/nodeFragment.types'; import { ConnectorContextProvider } from '../renderer/connector/ConnectorContext'; import { DiagramRenderer } from '../renderer/DiagramRenderer'; import { DiagramDirectEditContextProvider } from '../renderer/direct-edit/DiagramDirectEditContext'; @@ -44,7 +41,7 @@ import { } from './DiagramRepresentation.types'; import { StoreContextProvider } from './StoreContext'; -const subscription = (contributions: GraphQLNodeStyleFragment[]) => gql(diagramEventSubscription(contributions)); +const subscription = gql(diagramEventSubscription); export const getDiagramDescription = gql` query getDiagramDescription($editingContextId: ID!, $representationId: ID!) { @@ -139,9 +136,7 @@ export const DiagramRepresentation = ({ setState((prevState) => ({ ...prevState, diagramRefreshedEventPayload: null, complete: true })); }; - const { graphQLNodeStyleFragments } = useContext(NodeTypeContext); - - const { error } = useSubscription(subscription(graphQLNodeStyleFragments), { + const { error } = useSubscription(subscription, { variables, fetchPolicy: 'no-cache', onData, diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.tsx b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.tsx index fd7380a4196..2292a781d8b 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.tsx @@ -17,7 +17,6 @@ import { DiagramRepresentationConfigurationProps } from './DiagramRepresentation export const defaultNodeTypeRegistry: NodeTypeContextValue = { nodeConverters: [], nodeLayoutHandlers: [], - graphQLNodeStyleFragments: [], nodeTypeContributions: [], }; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.types.ts b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.types.ts index 6c93cc75551..038f2cb9ea1 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.types.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/diagrams/DiagramRepresentationConfiguration.types.ts @@ -12,7 +12,6 @@ *******************************************************************************/ import { - GraphQLNodeStyleFragment, INodeConverter, INodeLayoutHandler, NodeData, @@ -24,7 +23,6 @@ export interface DiagramRepresentationConfigurationProps { } export interface NodeTypeRegistry { - graphQLNodeStyleFragments: GraphQLNodeStyleFragment[]; nodeLayoutHandlers: INodeLayoutHandler[]; nodeConverters: INodeConverter[]; nodeTypeContributions: NodeTypeContributionElement[]; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClient.ts b/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClient.ts index b4375884613..e6d7a6aef2e 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClient.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClient.ts @@ -15,6 +15,7 @@ import { ApolloClient, ApolloClientOptions, DefaultOptions, + DocumentTransform, HttpLink, HttpOptions, InMemoryCache, @@ -34,6 +35,7 @@ import { } from '../views/project-browser/list-projects-area/useProjects.fragments'; import { apolloClientOptionsConfigurersExtensionPoint, + apolloClientOptionsDocumentTransformConfigurersExtensionPoint, cacheOptionsConfigurersExtensionPoint, httpOptionsConfigurersExtensionPoint, webSocketOptionsConfigurersExtensionPoint, @@ -102,12 +104,21 @@ export const useCreateApolloClient = (httpOrigin: string, wsOrigin: string): Apo }, }; + const { data: documentTransforms } = useData(apolloClientOptionsDocumentTransformConfigurersExtensionPoint); + + const documentTransformToLoad = documentTransforms.reduce( + (documentTransforms: DocumentTransform, documentTransform: DocumentTransform) => + documentTransforms.concat(documentTransform) + ); + let apolloClientOptions: ApolloClientOptions = { link, cache, connectToDevTools: true, defaultOptions, + documentTransform: documentTransformToLoad, }; + const { data: apolloClientOptionsConfigurers } = useData(apolloClientOptionsConfigurersExtensionPoint); apolloClientOptionsConfigurers.forEach((configurer) => { apolloClientOptions = configurer(apolloClientOptions); diff --git a/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClientExtensionPoints.tsx b/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClientExtensionPoints.tsx index dfbe4a2b28f..1612b4c0080 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClientExtensionPoints.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/graphql/useCreateApolloClientExtensionPoints.tsx @@ -11,6 +11,7 @@ * Obeo - initial API and implementation *******************************************************************************/ +import { DocumentTransform } from '@apollo/client'; import { DataExtensionPoint } from '@eclipse-sirius/sirius-components-core'; import { ApolloClientOptionsConfigurer, @@ -38,3 +39,10 @@ export const apolloClientOptionsConfigurersExtensionPoint: DataExtensionPoint +> = { + identifier: 'apolloClient#apolloClientOptionsDocumenTransformConfigurers', + fallback: [], +}; diff --git a/packages/sirius-web/frontend/sirius-web-application/src/index.ts b/packages/sirius-web/frontend/sirius-web-application/src/index.ts index 2a4ec0a6300..c59298dce17 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/index.ts +++ b/packages/sirius-web/frontend/sirius-web-application/src/index.ts @@ -23,6 +23,7 @@ export { } from './graphql/useCreateApolloClient.types'; export { apolloClientOptionsConfigurersExtensionPoint, + apolloClientOptionsDocumentTransformConfigurersExtensionPoint, cacheOptionsConfigurersExtensionPoint, httpOptionsConfigurersExtensionPoint, webSocketOptionsConfigurersExtensionPoint, diff --git a/packages/sirius-web/frontend/sirius-web/src/index.tsx b/packages/sirius-web/frontend/sirius-web/src/index.tsx index c4861854d9a..053a3ccf637 100644 --- a/packages/sirius-web/frontend/sirius-web/src/index.tsx +++ b/packages/sirius-web/frontend/sirius-web/src/index.tsx @@ -11,14 +11,17 @@ * Obeo - initial API and implementation *******************************************************************************/ import { loadDevMessages, loadErrorMessages } from '@apollo/client/dev'; +import { ExtensionRegistry } from '@eclipse-sirius/sirius-components-core'; import { NodeTypeContribution } from '@eclipse-sirius/sirius-components-diagrams'; import { DiagramRepresentationConfiguration, NodeTypeRegistry, SiriusWebApplication, + apolloClientOptionsDocumentTransformConfigurersExtensionPoint, } from '@eclipse-sirius/sirius-web-application'; import ReactDOM from 'react-dom'; import { httpOrigin, wsOrigin } from './core/URL'; +import { ellipseNodeStyleDocumentTransform } from './nodes/ElipseNodeDocumentTransform'; import { EllipseNode } from './nodes/EllipseNode'; import { EllipseNodeConverter } from './nodes/EllipseNodeConverter'; import { EllipseNodeLayoutHandler } from './nodes/EllipseNodeLayoutHandler'; @@ -34,20 +37,21 @@ if (process.env.NODE_ENV !== 'production') { loadErrorMessages(); } +const registry = new ExtensionRegistry(); + +registry.putData(apolloClientOptionsDocumentTransformConfigurersExtensionPoint, { + identifier: `siriusWeb_${apolloClientOptionsDocumentTransformConfigurersExtensionPoint.identifier}`, + data: [ellipseNodeStyleDocumentTransform], +}); + const nodeTypeRegistry: NodeTypeRegistry = { - graphQLNodeStyleFragments: [ - { - type: 'EllipseNodeStyle', - fields: `borderColor borderSize borderStyle background`, - }, - ], nodeLayoutHandlers: [new EllipseNodeLayoutHandler()], nodeConverters: [new EllipseNodeConverter()], nodeTypeContributions: [], }; ReactDOM.render( - + , document.getElementById('root') diff --git a/packages/sirius-web/frontend/sirius-web/src/nodes/ElipseNodeDocumentTransform.ts b/packages/sirius-web/frontend/sirius-web/src/nodes/ElipseNodeDocumentTransform.ts new file mode 100644 index 00000000000..4ddc678adcf --- /dev/null +++ b/packages/sirius-web/frontend/sirius-web/src/nodes/ElipseNodeDocumentTransform.ts @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2024 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 { DocumentTransform } from '@apollo/client'; +import { DocumentNode, FieldNode, InlineFragmentNode, Kind, SelectionNode, visit } from 'graphql'; + +const shouldTransform = (document: DocumentNode) => { + return ( + document.definitions[0] && + document.definitions[0].kind === Kind.OPERATION_DEFINITION && + document.definitions[0].name?.value === 'diagramEvent' + ); +}; + +const isNodeStyleFragment = (field: FieldNode) => { + if (field.name.value === 'style') { + const inLinesFragment = field.selectionSet.selections + .filter((selection) => selection.kind === Kind.INLINE_FRAGMENT) + .map((inlineFragment: InlineFragmentNode) => inlineFragment.typeCondition.name.value); + if (inLinesFragment.includes('RectangularNodeStyle') && inLinesFragment.includes('ImageNodeStyle')) { + return true; + } + } + return false; +}; + +const borderColorField: SelectionNode = { + kind: Kind.FIELD, + name: { + kind: Kind.NAME, + value: 'borderColor', + }, +}; + +const borderSizeField: SelectionNode = { + kind: Kind.FIELD, + name: { + kind: Kind.NAME, + value: 'borderSize', + }, +}; + +const borderStyleField: SelectionNode = { + kind: Kind.FIELD, + name: { + kind: Kind.NAME, + value: 'borderStyle', + }, +}; + +const backgroundField: SelectionNode = { + kind: Kind.FIELD, + name: { + kind: Kind.NAME, + value: 'background', + }, +}; + +export const ellipseNodeStyleDocumentTransform = new DocumentTransform((document) => { + if (shouldTransform(document)) { + const transformedDocument = visit(document, { + Field(field) { + if (!isNodeStyleFragment(field)) { + return undefined; + } + + const selections = field.selectionSet?.selections ?? []; + + const ellipseNodeStyleInlineFragment: InlineFragmentNode = { + kind: Kind.INLINE_FRAGMENT, + selectionSet: { + kind: Kind.SELECTION_SET, + selections: [borderColorField, borderSizeField, borderStyleField, backgroundField], + }, + typeCondition: { + kind: Kind.NAMED_TYPE, + name: { + kind: Kind.NAME, + value: 'EllipseNodeStyle', + }, + }, + }; + + return { + ...field, + selectionSet: { + ...field.selectionSet, + selections: [...selections, ellipseNodeStyleInlineFragment], + }, + }; + }, + }); + + return transformedDocument; + } + return document; +});