Skip to content

Commit

Permalink
[3887] Memoize diagram representation
Browse files Browse the repository at this point in the history
Bug: #3887
Signed-off-by: Michaël Charfadi <michael.charfadi@obeosoft.com>
  • Loading branch information
mcharfadi committed Aug 28, 2024
1 parent db03783 commit 79e0b1b
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 119 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ A migration participant has been added to automatically keep compatible all diag
- https://github.com/eclipse-sirius/sirius-web/issues/3793[#3793] [sirius-web] Add mechanism to retrieve the parent object of an element in the tree representation
- https://github.com/eclipse-sirius/sirius-web/issues/3880[#3880] [sirius-web] Make some tests methods more generic
- https://github.com/eclipse-sirius/sirius-web/issues/3834[#3834] [deck] Add more variables for DeckDescription
- https://github.com/eclipse-sirius/sirius-web/issues/3887[#3887] [diagram] Memoize diagram representation (improve performance when selecting an element on large diagram)

== v2024.7.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import { gql, OnDataOptions, useQuery, useSubscription } from '@apollo/client';
import { RepresentationComponentProps, useMultiToast } from '@eclipse-sirius/sirius-components-core';
import { useEffect, useState } from 'react';
import { memo, useEffect, useState } from 'react';
import { ReactFlowProvider } from 'reactflow';
import { DiagramContext } from '../contexts/DiagramContext';
import { DiagramDescriptionContext } from '../contexts/DiagramDescriptionContext';
Expand Down Expand Up @@ -78,131 +78,129 @@ export const getDiagramDescription = gql`
const isDiagramRefreshedEventPayload = (payload: GQLDiagramEventPayload): payload is GQLDiagramRefreshedEventPayload =>
payload.__typename === 'DiagramRefreshedEventPayload';

export const DiagramRepresentation = ({
editingContextId,
representationId,
readOnly,
}: RepresentationComponentProps) => {
const [state, setState] = useState<DiagramRepresentationState>({
id: crypto.randomUUID(),
diagramRefreshedEventPayload: null,
payload: null,
complete: false,
message: null,
});
const { addErrorMessage } = useMultiToast();
export const DiagramRepresentation = memo(
({ editingContextId, representationId, readOnly }: RepresentationComponentProps) => {
const [state, setState] = useState<DiagramRepresentationState>({
id: crypto.randomUUID(),
diagramRefreshedEventPayload: null,
payload: null,
complete: false,
message: null,
});
const { addErrorMessage } = useMultiToast();

const variables: GQLDiagramEventVariables = {
input: {
id: state.id,
editingContextId,
diagramId: representationId,
},
};
const variables: GQLDiagramEventVariables = {
input: {
id: state.id,
editingContextId,
diagramId: representationId,
},
};

const onData = ({ data }: OnDataOptions<GQLDiagramEventData>) => {
if (data.data) {
const { diagramEvent } = data.data;
if (isDiagramRefreshedEventPayload(diagramEvent)) {
setState((prevState) => ({ ...prevState, diagramRefreshedEventPayload: diagramEvent }));
const onData = ({ data }: OnDataOptions<GQLDiagramEventData>) => {
if (data.data) {
const { diagramEvent } = data.data;
if (isDiagramRefreshedEventPayload(diagramEvent)) {
setState((prevState) => ({ ...prevState, diagramRefreshedEventPayload: diagramEvent }));
}
setState((prevState) => ({ ...prevState, payload: diagramEvent }));
}
setState((prevState) => ({ ...prevState, payload: diagramEvent }));
}
};
};

const {
loading: diagramDescriptionLoading,
data: diagramDescriptionData,
error: diagramDescriptionError,
} = useQuery<GQLDiagramDescriptionData, GQLDiagramDescriptionVariables>(getDiagramDescription, {
variables: {
editingContextId,
representationId,
},
skip: state.diagramRefreshedEventPayload === null,
});
const {
loading: diagramDescriptionLoading,
data: diagramDescriptionData,
error: diagramDescriptionError,
} = useQuery<GQLDiagramDescriptionData, GQLDiagramDescriptionVariables>(getDiagramDescription, {
variables: {
editingContextId,
representationId,
},
skip: state.diagramRefreshedEventPayload === null,
});

useEffect(() => {
if (!diagramDescriptionLoading) {
setState((prevState) => ({
...prevState,
diagramDescription: diagramDescriptionData?.viewer.editingContext.representation.description,
}));
}
if (diagramDescriptionError) {
const { message } = diagramDescriptionError;
addErrorMessage(message);
}
}, [diagramDescriptionLoading, diagramDescriptionData, diagramDescriptionError]);
useEffect(() => {
if (!diagramDescriptionLoading) {
setState((prevState) => ({
...prevState,
diagramDescription: diagramDescriptionData?.viewer.editingContext.representation.description,
}));
}
if (diagramDescriptionError) {
const { message } = diagramDescriptionError;
addErrorMessage(message);
}
}, [diagramDescriptionLoading, diagramDescriptionData, diagramDescriptionError]);

const onComplete = () => {
setState((prevState) => ({ ...prevState, diagramRefreshedEventPayload: null, complete: true }));
};
const onComplete = () => {
setState((prevState) => ({ ...prevState, diagramRefreshedEventPayload: null, complete: true }));
};

const { error } = useSubscription<GQLDiagramEventData>(subscription, {
variables,
fetchPolicy: 'no-cache',
onData,
onComplete,
});
const { error } = useSubscription<GQLDiagramEventData>(subscription, {
variables,
fetchPolicy: 'no-cache',
onData,
onComplete,
});

const diagramDescription: GQLDiagramDescription | undefined =
diagramDescriptionData?.viewer.editingContext.representation.description;
const diagramDescription: GQLDiagramDescription | undefined =
diagramDescriptionData?.viewer.editingContext.representation.description;

if (state.message) {
return <div>{state.message}</div>;
}
if (error) {
return <div>{error.message}</div>;
}
if (state.complete) {
return <div>The representation is not available anymore</div>;
}
if (!state.diagramRefreshedEventPayload || !diagramDescription) {
return <div></div>;
}
if (state.message) {
return <div>{state.message}</div>;
}
if (error) {
return <div>{error.message}</div>;
}
if (state.complete) {
return <div>The representation is not available anymore</div>;
}
if (!state.diagramRefreshedEventPayload || !diagramDescription) {
return <div></div>;
}

return (
<ReactFlowProvider>
<DiagramContext.Provider
value={{
editingContextId,
diagramId: representationId,
refreshEventPayloadId: state.diagramRefreshedEventPayload.id,
payload: state.payload,
readOnly,
}}>
<DiagramDescriptionContext.Provider value={{ diagramDescription }}>
<StoreContextProvider>
<DiagramDirectEditContextProvider>
<DiagramPaletteContextProvider>
<DiagramElementPaletteContextProvider>
<ConnectorContextProvider>
<DropNodeContextProvider>
<NodeContextProvider>
<div
style={{ display: 'inline-block', position: 'relative' }}
data-representation-kind="diagram"
data-representation-label={state.diagramRefreshedEventPayload.diagram.metadata.label}>
<MarkerDefinitions />
<FullscreenContextProvider>
<DialogContextProvider>
<DiagramRenderer
key={state.diagramRefreshedEventPayload.diagram.id}
diagramRefreshedEventPayload={state.diagramRefreshedEventPayload}
/>
</DialogContextProvider>
</FullscreenContextProvider>
</div>
</NodeContextProvider>
</DropNodeContextProvider>
</ConnectorContextProvider>
</DiagramElementPaletteContextProvider>
</DiagramPaletteContextProvider>
</DiagramDirectEditContextProvider>
</StoreContextProvider>
</DiagramDescriptionContext.Provider>
</DiagramContext.Provider>
</ReactFlowProvider>
);
};
return (
<ReactFlowProvider>
<DiagramContext.Provider
value={{
editingContextId,
diagramId: representationId,
refreshEventPayloadId: state.diagramRefreshedEventPayload.id,
payload: state.payload,
readOnly,
}}>
<DiagramDescriptionContext.Provider value={{ diagramDescription }}>
<StoreContextProvider>
<DiagramDirectEditContextProvider>
<DiagramPaletteContextProvider>
<DiagramElementPaletteContextProvider>
<ConnectorContextProvider>
<DropNodeContextProvider>
<NodeContextProvider>
<div
style={{ display: 'inline-block', position: 'relative' }}
data-representation-kind="diagram"
data-representation-label={state.diagramRefreshedEventPayload.diagram.metadata.label}>
<MarkerDefinitions />
<FullscreenContextProvider>
<DialogContextProvider>
<DiagramRenderer
key={state.diagramRefreshedEventPayload.diagram.id}
diagramRefreshedEventPayload={state.diagramRefreshedEventPayload}
/>
</DialogContextProvider>
</FullscreenContextProvider>
</div>
</NodeContextProvider>
</DropNodeContextProvider>
</ConnectorContextProvider>
</DiagramElementPaletteContextProvider>
</DiagramPaletteContextProvider>
</DiagramDirectEditContextProvider>
</StoreContextProvider>
</DiagramDescriptionContext.Provider>
</DiagramContext.Provider>
</ReactFlowProvider>
);
}
);

0 comments on commit 79e0b1b

Please sign in to comment.