Skip to content

Commit

Permalink
[3774] Add an extension point to contribute custom tools
Browse files Browse the repository at this point in the history
Bug: #3774
Signed-off-by: Florian ROUËNÉ <[email protected]>
  • Loading branch information
frouene committed Jul 22, 2024
1 parent e8a321d commit 1aaf6d9
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 217 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ As a result, the following maven modules have been deleted: `sirius-web-sample-a
- https://github.com/eclipse-sirius/sirius-web/issues/3676[#3676] [representation] Remove the label from representation subscriptions and from graphql types.
+ Also remove the label from representation metadata (and sometimes the whole metadata) when the label or metadata were not needed.
- https://github.com/eclipse-sirius/sirius-web/issues/1470[#1470] [view] Since the computation of converted description ID has changed, the identifier of existing representations is not valid anymore, and these representations cannot be opened.
- https://github.com/eclipse-sirius/sirius-web/issues/2759[#2759] [diagram] Update some API relative to the diagram:
- https://github.com/eclipse-sirius/sirius-web/issues/2759[#2759] [diagram] Update some API relative to the diagram:
- https://github.com/eclipse-sirius/sirius-web/issues/1470[#1470] [view] Since the computation of converted description ID has changed, the identifier of existing representations is not valid anymore, and these representations cannot be opened.

* The `NodeTool#selectionDescription` attribute of type `SelectionDescription` has been renamed into `dialogDescription` and is now of type `DialogDescription`.
* The `SelectionDescription` type has been renamed into `SelectionDialogDescription` and inherit from `DialogDescription`.
Expand Down Expand Up @@ -81,7 +82,7 @@ The new implementation still uses URIs, but URIs now have the following pattern:
Thanks to this change, the various form based representations (details, related elements, representations, etc) can now have dedicated features such as specific inputs or additional payloads for their subscriptions.
- https://github.com/eclipse-sirius/sirius-web/issues/3794[#3794] [view] In diagram view DSL, _NodeLabelStyle#showIcon_ has been change to _NodeLabelStyle#showIconExpression_, allowing to dynamically change this style option depending on a condition evaluated at runtime.
A migration participant has been added to automatically keep compatible all diagram descriptions created before 2024.9.0.

- https://github.com/eclipse-sirius/sirius-web/issues/3774[#3774] [sirius-web] Add an extension point to contribute custom tools to the diagram palette

== v2024.7.0

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
= How to contribute custom tool to a Diagram palette
= How to use the extension points to extend the frontend

This document shows the steps needed for an application to contribute its own custom tools.
Sirius-web is an example of an application using the various sirius-component modules.
A user may want to configure certain parts of this application.
Several extension points have been provided to enable a sirius-web-based application to customize its frontend.

An example of a simple tool is available on _Papaya::OperationalActivity_ node to illustrate (see _PapayaOperationActivityLabelDetailToolContribution.tsx_ and _EditProjectView.tsx_).
== How to use the tool extension point

== The tool component
=== The tool component

By contributing a new custom tool, you add a React component to the palette.
This component must use as props `DiagramPaletteToolContributionComponentProps`.
This component must use as props `PaletteToolComponentProps`.
To avoid inconsistency palette representation, we encourage the use of a simple icon, but by definition, you can contribute what you want as a React component.
If needed, this icon can open a modal with more complex UI.

Expand All @@ -19,16 +21,25 @@ To retrieve the _editingContextId_ and the _representationId_, you can use the f
const { projectId: editingContextId, representationId } = useParams<EditProjectViewParams>();
----

== Contribution
=== Add the extension point to the registry

Once the component has been developed, we need to contribute it to the `DiagramPaletteToolContext.Provider`.
To do this, you need to add a `DiagramPaletteToolContribution` to the `DiagramPaletteToolContextValue` array pasted to the provider.
The `DiagramPaletteToolContribution` need two props, the _component_ and a _canHandle_ function, this function will be called each time we create a palette on the diagram.
It must return true only for the palette where the custom tool needs to be added.
To compute that, this function has two parameters the _diagramId_ and the _diagramElementId_, note that for the diagram palette _diagramId_ = _diagramElementId_.
To retrieve the node metadata, you can use the hook `useNodes` and filter all the node by the _diagramElementId_.
To add your custom tool to the application, you have to use `ExtensionRegistry#addComponent` function with `paletteToolExtensionPoint` as `ComponentExtensionPoint`.
By doing so, your component will be added to each diagram palette, most of the time you would like to declare your tool only on certain types of diagrams or nodes.
To do this, it's up to your component to only return something according to the props data.
Only return null in other cases.

== Specify a reference position
For example, to add our papaya tool, we declare the following extension point:

[source,typescript]
----
const papayaExtensionRegistry = new ExtensionRegistry();
papayaExtensionRegistry.addComponent(paletteToolExtensionPoint, {
identifier: 'papaya_customtool',
Component: PapayaOperationActivityLabelDetailToolContribution,
});
----

=== Specify a reference position

Depending on the tool purpose, the click coordinates may be necessary for the result action.
For example, when the tool creates a new element on the diagram.
Expand All @@ -49,4 +60,3 @@ For the generic tool used in sirius-component, the provider is specified in the

The basic case is to use the position of the pallet as a reference position.
These coordinates are available in the props `DiagramPaletteToolContributionComponentProps`.

Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ export type { NodeContextValue } from './renderer/node/NodeContext.types';
export { NodeTypeContribution } from './renderer/node/NodeTypeContribution';
export type { DiagramNodeType } from './renderer/node/NodeTypes.types';
export { DiagramElementPalette } from './renderer/palette/DiagramElementPalette';
export type { DiagramPaletteToolContextValue } from './renderer/palette/DiagramPalette.types';
export { DiagramPaletteToolContext } from './renderer/palette/DiagramPaletteToolContext';
export { DiagramPaletteToolContribution } from './renderer/palette/DiagramPaletteToolContribution';
export type { DiagramPaletteToolContributionComponentProps } from './renderer/palette/DiagramPaletteToolContribution.types';
export type { GQLToolVariable, GQLToolVariableType } from './renderer/palette/Palette.types';
export type { DiagramPaletteToolComponentProps } from './renderer/palette/tool/DiagramPaletteTool.types';
export { diagramPaletteToolExtensionPoint } from './renderer/palette/tool/DiagramPaletteToolExtensionPoints';
export type { DiagramPanelActionProps } from './renderer/panel/DiagramPanel.types';
export { diagramPanelActionExtensionPoint } from './renderer/panel/DiagramPanelExtensionPoints';
export { DiagramRepresentation } from './representation/DiagramRepresentation';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,25 @@ import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import { ToolProps } from './Tool.types';

const useToolStyle = makeStyles(() => ({
const useToolStyle = makeStyles((theme) => ({
toolThumbnail: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: theme.spacing(4.5),
cursor: 'pointer',
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
},
tool: {
display: 'grid',
gridTemplateRows: '1fr',
gridTemplateColumns: '20px 1fr',
display: 'flex',
alignItems: 'center',
justifyContent: 'start',
cursor: 'pointer',
},
toolLabel: {
marginLeft: theme.spacing(0.5),
},
}));

export const Tool = ({ tool, onClick, thumbnail }: ToolProps) => {
Expand All @@ -34,7 +45,7 @@ export const Tool = ({ tool, onClick, thumbnail }: ToolProps) => {
}
let labelContent: JSX.Element | null = null;
if (!thumbnail) {
labelContent = <Typography>{label}</Typography>;
labelContent = <Typography className={classes.toolLabel}>{label}</Typography>;
}

const onToolClick: React.MouseEventHandler<HTMLDivElement> = (event) => {
Expand All @@ -43,7 +54,11 @@ export const Tool = ({ tool, onClick, thumbnail }: ToolProps) => {
};

return (
<div key={id} className={classes.tool} onClick={onToolClick} data-testid={`${tool.label} - Tool`}>
<div
key={id}
className={thumbnail ? classes.toolThumbnail : classes.tool}
onClick={onToolClick}
data-testid={`${tool.label} - Tool`}>
{image}
{labelContent}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
* Obeo - initial API and implementation
*******************************************************************************/

import { DiagramPaletteToolContributionProps } from './DiagramPaletteToolContribution.types';

export type DiagramPaletteToolContextValue = React.ReactElement<DiagramPaletteToolContributionProps>[];

export interface DiagramPaletteProps {
diagramElementId: string;
targetObjectId: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@
*******************************************************************************/

import { gql, useMutation, useQuery } from '@apollo/client';
import { useDeletionConfirmationDialog, useMultiToast } from '@eclipse-sirius/sirius-components-core';
import {
useDeletionConfirmationDialog,
useMultiToast,
useComponents,
ComponentExtension,
} from '@eclipse-sirius/sirius-components-core';
import IconButton from '@material-ui/core/IconButton';
import Paper from '@material-ui/core/Paper';
import Tooltip from '@material-ui/core/Tooltip';
import { makeStyles } from '@material-ui/core/styles';
import AdjustIcon from '@material-ui/icons/Adjust';
import TonalityIcon from '@material-ui/icons/Tonality';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { useCallback, useContext, useEffect, useState } from 'react';
import { useReactFlow, useViewport } from 'reactflow';
import { DiagramContext } from '../../contexts/DiagramContext';
import { DiagramContextValue } from '../../contexts/DiagramContext.types';
Expand All @@ -31,11 +36,7 @@ import { Tool } from '../Tool';
import { useAdjustSize } from '../adjust-size/useAdjustSize';
import { useFadeDiagramElements } from '../fade/useFadeDiagramElements';
import { usePinDiagramElements } from '../pin/usePinDiagramElements';
import { DiagramPaletteToolContextValue } from './DiagramPalette.types';
import { DiagramPaletteToolContext } from './DiagramPaletteToolContext';
import { DiagramPaletteToolContributionComponentProps } from './DiagramPaletteToolContribution.types';
import {
ContextualPaletteStyleProps,
GQLCollapsingState,
GQLDeleteFromDiagramData,
GQLDeleteFromDiagramInput,
Expand Down Expand Up @@ -64,24 +65,24 @@ import {
PaletteState,
} from './Palette.types';
import { ToolSection } from './tool-section/ToolSection';
import { diagramPaletteToolExtensionPoint } from './tool/DiagramPaletteToolExtensionPoints';
import { DiagramPaletteToolComponentProps } from './tool/DiagramPaletteTool.types';

const usePaletteStyle = makeStyles((theme) => ({
palette: {
border: `1px solid ${theme.palette.divider}`,
borderRadius: '2px',
zIndex: 2,
zIndex: 5,
position: 'fixed',
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
},
paletteContent: {
display: 'grid',
gridTemplateColumns: ({ toolCount }: ContextualPaletteStyleProps) => `repeat(${Math.min(toolCount, 10)}, 36px)`,
gridTemplateRows: '28px',
gridAutoRows: '28px',
placeItems: 'center',
maxWidth: theme.spacing(45.25),
},
toolIcon: {
width: theme.spacing(4.5),
color: theme.palette.text.primary,
},
}));
Expand Down Expand Up @@ -230,9 +231,9 @@ export const Palette = ({
const { showDeletionConfirmation } = useDeletionConfirmationDialog();
const { showDialog } = useDialog();

const diagramPaletteToolComponents = useContext<DiagramPaletteToolContextValue>(DiagramPaletteToolContext)
.filter((contribution) => contribution.props.canHandle(diagramId, diagramElementId))
.map((contribution) => contribution.props.component);
const paletteToolComponents: ComponentExtension<DiagramPaletteToolComponentProps>[] = useComponents(
diagramPaletteToolExtensionPoint
);

const { data: paletteData, error: paletteError } = useQuery<GQLGetToolSectionsData, GQLGetToolSectionsVariables>(
getPaletteQuery,
Expand All @@ -258,8 +259,8 @@ export const Palette = ({
).length
: 0) +
(hideableDiagramElement ? (node ? 3 : 1) : 0) +
diagramPaletteToolComponents.length;
const classes = usePaletteStyle({ toolCount });
paletteToolComponents.length;
const classes = usePaletteStyle();

let pinUnpinTool: JSX.Element | undefined;
let adjustSizeTool: JSX.Element | undefined;
Expand Down Expand Up @@ -468,45 +469,37 @@ export const Palette = ({
className={classes.palette}
style={{ position: 'absolute', left: paletteX, top: paletteY }}
data-testid="Palette">
<div className={classes.paletteContent}>
{palette?.tools.filter(isSingleClickOnDiagramElementTool).map((tool) => (
<Tool tool={tool} onClick={handleToolClick} thumbnail key={tool.id} />
))}
{palette?.toolSections.map((toolSection) => (
<ToolSection
toolSection={toolSection}
onToolClick={handleToolClick}
key={toolSection.id}
onExpand={handleToolSectionExpand}
toolSectionExpandId={state.expandedToolSectionId}
/>
))}
{diagramPaletteToolComponents.map((component, index) => {
const props: DiagramPaletteToolContributionComponentProps = {
x,
y,
diagramElementId,
key: index.toString(),
};
return React.createElement(component, props);
})}
{hideableDiagramElement ? (
<>
<Tooltip title="Fade element">
<IconButton
className={classes.toolIcon}
size="small"
aria-label="Fade element"
onClick={invokeFadeDiagramElementTool}
data-testid="Fade-element">
<TonalityIcon fontSize="small" />
</IconButton>
</Tooltip>
{pinUnpinTool}
{adjustSizeTool}
</>
) : null}
</div>
{palette?.tools.filter(isSingleClickOnDiagramElementTool).map((tool) => (
<Tool tool={tool} onClick={handleToolClick} thumbnail key={tool.id} />
))}
{palette?.toolSections.map((toolSection) => (
<ToolSection
toolSection={toolSection}
onToolClick={handleToolClick}
key={toolSection.id}
onExpand={handleToolSectionExpand}
toolSectionExpandId={state.expandedToolSectionId}
/>
))}
{paletteToolComponents.map(({ Component: PaletteToolComponent }, index) => (
<PaletteToolComponent x={x} y={y} diagramElementId={diagramElementId} key={index} />
))}
{hideableDiagramElement ? (
<>
<Tooltip title="Fade element">
<IconButton
className={classes.toolIcon}
size="small"
aria-label="Fade element"
onClick={invokeFadeDiagramElementTool}
data-testid="Fade-element">
<TonalityIcon fontSize="small" />
</IconButton>
</Tooltip>
{pinUnpinTool}
{adjustSizeTool}
</>
) : null}
</Paper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { PalettePortalProps } from './PalettePortal.types';
//The sibling dom element .react-flow__renderer have a zIndex of 4, so we set it here to 5 to have the palette in front of the diagram.
const palettePortalStyle: React.CSSProperties = {
zIndex: 5,
position: 'absolute',
};

export const PalettePortal = ({ children }: PalettePortalProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { PaletteToolProps } from './PaletteTool.types';

const usePaletteToolStyle = makeStyles((theme) => ({
toolIcon: {
width: theme.spacing(4.5),
color: theme.palette.text.primary,
},
}));
Expand Down
Loading

0 comments on commit 1aaf6d9

Please sign in to comment.