Skip to content

Commit

Permalink
[3533] Add a dedicated component to handle diagram subscription
Browse files Browse the repository at this point in the history
Bug: #3533
Signed-off-by: Michaël Charfadi <[email protected]>
  • Loading branch information
mcharfadi committed Jun 11, 2024
1 parent 6284ecb commit cd84581
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 229 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ More existing APIs will be migrated to this new common pattern.
- https://github.com/eclipse-sirius/sirius-web/issues/3595[#3595] [core] Avoid re-rendering the workbench when the selection does not really change
- https://github.com/eclipse-sirius/sirius-web/issues/3601[#3601] [sirius-web] Extract test helper classes to sirius-web-tests
- https://github.com/eclipse-sirius/sirius-web/issues/3597[#3597] [core] Improve the creation of `RepresentationEventProcessor`
- https://github.com/eclipse-sirius/sirius-web/issues/3533[#3553] [diagram] Add a dedicated component to handle diagram subscription


== v2024.5.0

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand All @@ -20,11 +20,12 @@
import java.util.concurrent.CompletableFuture;

import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessorRegistry;
import org.eclipse.sirius.components.collaborative.diagrams.dto.DropNodeCompatibilityEntry;
import org.eclipse.sirius.components.collaborative.diagrams.dto.GetDropNodeCompatibilitySuccessPayload;
import org.eclipse.sirius.components.collaborative.diagrams.dto.GetDropNodeCompatibiliyInput;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
import org.eclipse.sirius.components.graphql.api.IExceptionWrapper;
import org.eclipse.sirius.components.graphql.api.LocalContextConstants;

import graphql.schema.DataFetchingEnvironment;
Expand All @@ -37,21 +38,24 @@
*/
@QueryDataFetcher(type = "DiagramDescription", field = "dropNodeCompatibility")
public class DiagramDescriptionDropNodeCompatibilityDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<List<DropNodeCompatibilityEntry>>> {
private final IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry;

public DiagramDescriptionDropNodeCompatibilityDataFetcher(IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry) {
this.editingContextEventProcessorRegistry = Objects.requireNonNull(editingContextEventProcessorRegistry);
private final IExceptionWrapper exceptionWrapper;
private final IEditingContextDispatcher editingContextDispatcher;

public DiagramDescriptionDropNodeCompatibilityDataFetcher(IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) {
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
}

@Override
public CompletableFuture<List<DropNodeCompatibilityEntry>> get(DataFetchingEnvironment environment) throws Exception {
Map<String, Object> localContext = environment.getLocalContext();
String editingContextId = Optional.ofNullable(localContext.get(LocalContextConstants.EDITING_CONTEXT_ID)).map(Object::toString).orElse(null);
String representationId = Optional.ofNullable(localContext.get(LocalContextConstants.REPRESENTATION_ID)).map(Object::toString).orElse(null);
if (editingContextId != null && representationId != null) {
GetDropNodeCompatibiliyInput input = new GetDropNodeCompatibiliyInput(UUID.randomUUID(), editingContextId, representationId);
var editingContextId = Optional.ofNullable(localContext.get(LocalContextConstants.EDITING_CONTEXT_ID)).map(Object::toString);
var representationId = Optional.ofNullable(localContext.get(LocalContextConstants.REPRESENTATION_ID)).map(Object::toString);

return this.editingContextEventProcessorRegistry.dispatchEvent(input.editingContextId(), input)
if (editingContextId.isPresent() && representationId.isPresent()) {
GetDropNodeCompatibiliyInput input = new GetDropNodeCompatibiliyInput(UUID.randomUUID(), editingContextId.get(), representationId.get());
return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchQuery(input.editingContextId(), input), input)
.filter(GetDropNodeCompatibilitySuccessPayload.class::isInstance)
.map(GetDropNodeCompatibilitySuccessPayload.class::cast)
.map(GetDropNodeCompatibilitySuccessPayload::entries)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,37 @@
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
import React from 'react';
import { DiagramContextValue } from './DiagramContext.types';
import React, { useState } from 'react';
import { DiagramContextProviderProps, DiagramContextValue } from './DiagramContext.types';

const value: DiagramContextValue = {
editingContextId: '',
diagramId: '',
refreshEventPayloadId: '',
readOnly: false,
refreshEventPayloadId: '',
setRefreshEventPayloadId: () => {},
};

export const DiagramContext = React.createContext<DiagramContextValue>(value);

export const DiagramContextProvider = ({
diagramId,
editingContextId,
readOnly,
children,
}: DiagramContextProviderProps) => {
const [refreshEventPayloadId, setRefreshEventPayloadId] = useState<string>('');

return (
<DiagramContext.Provider
value={{
diagramId,
editingContextId,
readOnly,
refreshEventPayloadId,
setRefreshEventPayloadId,
}}>
{children}
</DiagramContext.Provider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
* Obeo - initial API and implementation
*******************************************************************************/

import { Dispatch, SetStateAction } from 'react';

export interface DiagramContextValue {
editingContextId: string;
diagramId: string;
readOnly: boolean;
refreshEventPayloadId: string;
setRefreshEventPayloadId: Dispatch<SetStateAction<string>>;
}

export interface DiagramContextProviderProps {
editingContextId: string;
diagramId: string;
readOnly: boolean;
children: React.ReactNode;
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const DiagramRenderer = memo(({ diagramRefreshedEventPayload }: DiagramRe
const { readOnly } = useContext<DiagramContextValue>(DiagramContext);
const { diagramDescription } = useDiagramDescription();
const { getEdges, onEdgesChange, getNodes, setEdges, setNodes } = useStore();
const { setRefreshEventPayloadId } = useContext<DiagramContextValue>(DiagramContext);
const nodes = getNodes();
const edges = getEdges();

Expand Down Expand Up @@ -132,6 +133,7 @@ export const DiagramRenderer = memo(({ diagramRefreshedEventPayload }: DiagramRe

setNodes(convertedDiagram.nodes);
setEdges(convertedDiagram.edges);
setRefreshEventPayloadId(diagramRefreshedEventPayload.id);
fitToScreen();
} else if (cause === 'refresh') {
const previousDiagram: RawDiagram = {
Expand All @@ -145,6 +147,7 @@ export const DiagramRenderer = memo(({ diagramRefreshedEventPayload }: DiagramRe

setNodes(laidOutDiagram.nodes);
setEdges(laidOutDiagram.edges);
setRefreshEventPayloadId(diagramRefreshedEventPayload.id);
closeAllPalettes();

synchronizeLayoutData(diagramRefreshedEventPayload.id, laidOutDiagram);
Expand Down Expand Up @@ -285,80 +288,85 @@ export const DiagramRenderer = memo(({ diagramRefreshedEventPayload }: DiagramRe
);

return (
<ReactFlow
nodes={nodes}
nodeTypes={nodeTypes}
onNodesChange={handleNodesChange}
edges={edges}
edgeTypes={edgeTypes}
edgesUpdatable={!readOnly}
onKeyDown={onKeyDown}
onConnect={onConnect}
onConnectStart={onConnectStart}
onConnectEnd={onConnectEnd}
connectionLineComponent={ConnectionLine}
onEdgesChange={handleEdgesChange}
onEdgeUpdate={reconnectEdge}
onPaneClick={handlePaneClick}
onEdgeClick={handleDiagramElementCLick}
onNodeClick={handleDiagramElementCLick}
onMove={handleMove}
nodeDragThreshold={1}
onDrop={onDrop}
onDragOver={onDragOver}
onNodeDrag={handleNodeDrag}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
onNodeMouseEnter={onNodeMouseEnter}
onNodeMouseLeave={onNodeMouseLeave}
onSelectionStart={handleSelectionStart}
onSelectionEnd={handleSelectionEnd}
maxZoom={40}
minZoom={0.1}
snapToGrid={snapToGrid}
snapGrid={useMemo(() => [GRID_STEP, GRID_STEP], [])}
connectionMode={ConnectionMode.Loose}
zoomOnDoubleClick={false}
connectionLineType={ConnectionLineType.SmoothStep}
ref={ref}>
{snapToGrid ? (
<>
<Background
id="small-grid"
style={{ backgroundColor }}
variant={BackgroundVariant.Lines}
gap={GRID_STEP}
color={smallGridColor}
/>
<Background
id="large-grid"
variant={BackgroundVariant.Lines}
gap={10 * GRID_STEP}
offset={1}
color={largeGridColor}
/>
</>
) : (
<Background style={{ backgroundColor }} color={backgroundColor} />
)}
<DiagramPanel
<div
style={{ display: 'inline-block', position: 'relative' }}
data-representation-kind="diagram"
data-representation-label={diagramRefreshedEventPayload.diagram.metadata.label}>
<ReactFlow
nodes={nodes}
nodeTypes={nodeTypes}
onNodesChange={handleNodesChange}
edges={edges}
edgeTypes={edgeTypes}
edgesUpdatable={!readOnly}
onKeyDown={onKeyDown}
onConnect={onConnect}
onConnectStart={onConnectStart}
onConnectEnd={onConnectEnd}
connectionLineComponent={ConnectionLine}
onEdgesChange={handleEdgesChange}
onEdgeUpdate={reconnectEdge}
onPaneClick={handlePaneClick}
onEdgeClick={handleDiagramElementCLick}
onNodeClick={handleDiagramElementCLick}
onMove={handleMove}
nodeDragThreshold={1}
onDrop={onDrop}
onDragOver={onDragOver}
onNodeDrag={handleNodeDrag}
onNodeDragStart={onNodeDragStart}
onNodeDragStop={onNodeDragStop}
onNodeMouseEnter={onNodeMouseEnter}
onNodeMouseLeave={onNodeMouseLeave}
onSelectionStart={handleSelectionStart}
onSelectionEnd={handleSelectionEnd}
maxZoom={40}
minZoom={0.1}
snapToGrid={snapToGrid}
onSnapToGrid={onSnapToGrid}
helperLines={helperLinesEnabled}
onHelperLines={setHelperLinesEnabled}
reactFlowWrapper={ref}
/>
<GroupPalette
x={groupPalettePosition?.x}
y={groupPalettePosition?.y}
isOpened={isGroupPaletteOpened}
refElementId={groupPaletteRefElementId}
hidePalette={hideGroupPalette}
/>
<DiagramPalette diagramElementId={diagramRefreshedEventPayload.diagram.id} />
{diagramDescription.debug ? <DebugPanel reactFlowWrapper={ref} /> : null}
<ConnectorContextualMenu />
{helperLinesEnabled ? <HelperLines horizontal={horizontalHelperLine} vertical={verticalHelperLine} /> : null}
</ReactFlow>
snapGrid={useMemo(() => [GRID_STEP, GRID_STEP], [])}
connectionMode={ConnectionMode.Loose}
zoomOnDoubleClick={false}
connectionLineType={ConnectionLineType.SmoothStep}
ref={ref}>
{snapToGrid ? (
<>
<Background
id="small-grid"
style={{ backgroundColor }}
variant={BackgroundVariant.Lines}
gap={GRID_STEP}
color={smallGridColor}
/>
<Background
id="large-grid"
variant={BackgroundVariant.Lines}
gap={10 * GRID_STEP}
offset={1}
color={largeGridColor}
/>
</>
) : (
<Background style={{ backgroundColor }} color={backgroundColor} />
)}
<DiagramPanel
snapToGrid={snapToGrid}
onSnapToGrid={onSnapToGrid}
helperLines={helperLinesEnabled}
onHelperLines={setHelperLinesEnabled}
reactFlowWrapper={ref}
/>
<GroupPalette
x={groupPalettePosition?.x}
y={groupPalettePosition?.y}
isOpened={isGroupPaletteOpened}
refElementId={groupPaletteRefElementId}
hidePalette={hideGroupPalette}
/>
<DiagramPalette diagramElementId={diagramRefreshedEventPayload.diagram.id} />
{diagramDescription.debug ? <DebugPanel reactFlowWrapper={ref} /> : null}
<ConnectorContextualMenu />
{helperLinesEnabled ? <HelperLines horizontal={horizontalHelperLine} vertical={verticalHelperLine} /> : null}
</ReactFlow>
</div>
);
});
Loading

0 comments on commit cd84581

Please sign in to comment.