Skip to content

Commit

Permalink
[4522] Restore contribution of custom tools to the diagram palette
Browse files Browse the repository at this point in the history
Bug: #4522
Signed-off-by: Florian ROUËNÉ <[email protected]>
  • Loading branch information
frouene authored and sbegaudeau committed Feb 14, 2025
1 parent ded4b92 commit a0dd9bd
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 62 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Now they are executed for some data if the data was coming from a studio too.
- https://github.com/eclipse-sirius/sirius-web/issues/4557[#4557] [sirius-web] Fix an issue where targetObjectURI was not set in manifest.json during the download of a project
- https://github.com/eclipse-sirius/sirius-web/issues/4547[#4547] [vs-code] Adapt the VSCode extension to the use of SemanticData#id as editingContextId
- https://github.com/eclipse-sirius/sirius-web/issues/4561[#4561] [sirius-web] Display boolean values properly in the query view
- https://github.com/eclipse-sirius/sirius-web/issues/4522[#4522] [diagram] Fix an issue where custom tools were no longer contributed to the diagram palette


=== New Features
Expand Down
55 changes: 55 additions & 0 deletions integration-tests/cypress/e2e/project/diagrams/custom-tool.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2025 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 { Explorer } from '../../../workbench/Explorer';
import { Diagram } from '../../../workbench/Diagram';
import { Papaya } from '../../../usecases/Papaya';
import { Project } from '../../../pages/Project';

describe('Custom tools', () => {
context('Given a papaya blank project', () => {
let projectId: string = '';
beforeEach(() => {
new Papaya().createPapayaBlankProject().then((createdProjectData) => {
projectId = createdProjectData.projectId;
const project = new Project();
project.visit(projectId);
const explorer = new Explorer();
explorer.expandWithDoubleClick('Papaya');
explorer.expandWithDoubleClick('Project Project');
explorer.expandWithDoubleClick('Component Component');
explorer.createRepresentation('Component Component', 'Component Diagram', 'diagram');
});
});

afterEach(() => cy.deleteProject(projectId));

it('Check diagram custom tool exist', () => {
const diagram = new Diagram();
diagram.getDiagram('diagram').should('exist');
cy.getByTestId('rf__wrapper').should('exist').rightclick(100, 100).rightclick(100, 100);
diagram.getPalette().should('exist');
cy.getByTestId('coordinates-tool').should('exist');
});

it('Check diagram element custom tool exist', () => {
const diagram = new Diagram();
diagram.getDiagram('diagram').should('exist');
cy.getByTestId('rf__wrapper').should('exist').rightclick(100, 100).rightclick(100, 100);
diagram.getPalette().should('exist');
cy.getByTestId('tool-New component').should('exist').click();
diagram.fitToScreen();
diagram.getNodes('diagram', 'Component').should('exist').rightclick();
cy.getByTestId('label-detail').should('exist');
});
});
});
34 changes: 4 additions & 30 deletions integration-tests/cypress/usecases/Papaya.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* Copyright (c) 2024, 2025 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 @@ -10,47 +10,21 @@
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
import { Project } from '../pages/Project';
import { isCreateProjectSuccessPayload } from '../support/server/createProjectCommand';
import { isCreateProjectFromTemplateSuccessPayload } from '../support/server/createProjectFromTemplateCommand';
import { Explorer } from '../workbench/Explorer';
import { Workbench } from '../workbench/Workbench';
import { CreatedProjectData } from './Papaya.types';

export class Papaya {
static readonly PAPAYA_NATURE = 'siriusComponents://nature?kind=papaya';

public createPapayaStudioProject(): Cypress.Chainable<CreatedProjectData> {
return cy.createProjectFromTemplate('papaya-studio-template').then((res) => {
public createPapayaBlankProject(): Cypress.Chainable<CreatedProjectData> {
return cy.createProjectFromTemplate('papaya-empty').then((res) => {
const payload = res.body.data.createProjectFromTemplate;
if (isCreateProjectFromTemplateSuccessPayload(payload)) {
const projectId = payload.project.id;
const data: CreatedProjectData = { projectId };
return cy.wrap(data);
} else {
throw new Error(`The project papaya studio has not been created`);
}
});
}

public createPapayaInstanceProject(name: string): Cypress.Chainable<CreatedProjectData> {
return cy.createProject(name, [Papaya.PAPAYA_NATURE]).then((res) => {
const payload = res.body.data.createProject;
if (isCreateProjectSuccessPayload(payload)) {
const projectId = payload.project.id;

new Project().visit(projectId);

const workbench = new Workbench();
workbench.performAction('Others...');

const explorer = new Explorer();
explorer.createRootObject('Others...', 'papaya_core', 'Root');

const data: CreatedProjectData = { projectId };
return cy.wrap(data);
} else {
throw new Error(`The project "${name}" has not been created`);
throw new Error(`The project papaya blank has not been created`);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023, 2024 Obeo.
* Copyright (c) 2023, 2025 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 @@ -15,7 +15,7 @@ import { Edge, Node } from '@xyflow/react';
import { EdgeData, NodeData } from '../../DiagramRenderer.types';

export interface DiagramPaletteToolContributionProps {
canHandle: (element: Node<NodeData> | Edge<EdgeData>) => boolean;
canHandle: (element: Node<NodeData> | Edge<EdgeData> | null) => boolean;
component: React.ComponentType<DiagramPaletteToolContributionComponentProps>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const AdjustSizeTool = ({ diagramElementId }: AdjustSizeToolProps) => {
aria-label="Adjust element"
onClick={() => adjustSize(diagramElementId)}
data-testid="adjust-element">
<AdjustIcon fontSize="small" />
<AdjustIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const FadeElementTool = ({ diagramElementId, isFaded }: FadeElementToolPr
aria-label="Unfade element"
onClick={() => fadeDiagramElements([diagramElementId], false)}
data-testid="Fade-element">
<TonalityIcon fontSize="small" />
<TonalityIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand All @@ -52,7 +52,7 @@ export const FadeElementTool = ({ diagramElementId, isFaded }: FadeElementToolPr
aria-label="Fade element"
onClick={() => fadeDiagramElements([diagramElementId], true)}
data-testid="Fade-element">
<TonalityIcon fontSize="small" />
<TonalityIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { PaletteQuickAccessToolBarProps } from './PaletteQuickAccessToolBar.type
import { PinUnPinTool } from './PinUnPinTool';
import { ResetEditedEdgePathTool } from './ResetEditedEdgePathTool';
import { Tool } from './Tool';

const isPinnable = (diagramElement: Node<NodeData> | Edge<EdgeData>): diagramElement is Node<NodeData> => {
return !!diagramElement.data && 'pinned' in diagramElement.data;
};
Expand Down Expand Up @@ -94,25 +95,25 @@ export const PaletteQuickAccessToolBar = ({
quickAccessToolComponents.push(
<AdjustSizeTool diagramElementId={diagramElementId} key={'tool_adjustSizeTool'}></AdjustSizeTool>
);
}

const paletteToolData: DataExtension<DiagramPaletteToolContributionProps[]> = useData(
diagramPaletteToolExtensionPoint
);
const paletteToolData: DataExtension<DiagramPaletteToolContributionProps[]> = useData(
diagramPaletteToolExtensionPoint
);

paletteToolData.data
.filter((data) => data.canHandle(diagramElement))
.map((data) => data.component)
.forEach((PaletteToolComponent, index) =>
quickAccessToolComponents.push(
<PaletteToolComponent
x={x}
y={y}
diagramElementId={diagramElementId}
key={'paletteToolComponents_' + index.toString()}
/>
)
);
}
paletteToolData.data
.filter((data) => data.canHandle(diagramElement ?? null))
.map((data) => data.component)
.forEach((PaletteToolComponent, index) =>
quickAccessToolComponents.push(
<PaletteToolComponent
x={x}
y={y}
diagramElementId={diagramElementId}
key={'paletteToolComponents_' + index.toString()}
/>
)
);

if (quickAccessToolComponents.length > 0) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const PinUnPinTool = ({ diagramElementId, isPined }: PinUnPinToolProps) =
aria-label="Unpin element"
onClick={() => pinDiagramElements([diagramElementId], false)}
data-testid="Unpin-element">
<UnpinIcon fontSize="small" />
<UnpinIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand All @@ -53,7 +53,7 @@ export const PinUnPinTool = ({ diagramElementId, isPined }: PinUnPinToolProps) =
aria-label="Pin element"
onClick={() => pinDiagramElements([diagramElementId], true)}
data-testid="Pin-element">
<PinIcon fontSize="small" />
<PinIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const ResetEditedEdgePathTool = ({ diagramElementId }: ResetEditedEdgePat
aria-label="Reset path"
onClick={() => removeEdgeLayoutData(diagramElementId)}
data-testid="Reset-path">
<DirectionsOffIcon fontSize="small" />
<DirectionsOffIcon sx={{ fontSize: 16 }} />
</IconButton>
</Tooltip>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Typography from '@mui/material/Typography';
import { Edge, Node, ReactFlowProps } from '@xyflow/react';
import { PapayaDiagramInformationPanel } from './diagrams/PapayaDiagramInformationPanel';
import { PapayaDiagramLegendPanel } from './diagrams/PapayaDiagramLegendPanel';
import { PapayaComponentDiagramToolContribution } from './tools/PapayaComponentDiagramToolContribution';
import { PapayaComponentLabelDetailToolContribution } from './tools/PapayaComponentLabelDetailToolContribution';

const papayaExtensionRegistry = new ExtensionRegistry();
Expand Down Expand Up @@ -82,13 +83,17 @@ const papayaDiagramPanelExtension: DataExtension<Array<ReactFlowPropsCustomizer>
papayaExtensionRegistry.putData(diagramRendererReactFlowPropsCustomizerExtensionPoint, papayaDiagramPanelExtension);
const diagramPaletteToolContributions: DiagramPaletteToolContributionProps[] = [
{
canHandle: (diagamElement: Node<NodeData> | Edge<EdgeData>) => {
return diagamElement.data
? diagamElement.data.targetObjectKind.startsWith('siriusComponents://semantic?domain=papaya&entity=Component')
canHandle: (diagramElement: Node<NodeData> | Edge<EdgeData> | null) => {
return diagramElement?.data
? diagramElement.data.targetObjectKind.startsWith('siriusComponents://semantic?domain=papaya&entity=Component')
: false;
},
component: PapayaComponentLabelDetailToolContribution,
},
{
canHandle: (diagramElement: Node<NodeData> | Edge<EdgeData> | null) => diagramElement === null,
component: PapayaComponentDiagramToolContribution,
},
];
papayaExtensionRegistry.putData<DiagramPaletteToolContributionProps[]>(diagramPaletteToolExtensionPoint, {
identifier: `papaya_${diagramPaletteToolExtensionPoint.identifier}`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*******************************************************************************
* Copyright (c) 2025 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 { useCurrentProject } from '@eclipse-sirius/sirius-web-application';
import RadarIcon from '@mui/icons-material/Radar';
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import IconButton from '@mui/material/IconButton';
import { Theme } from '@mui/material/styles';
import { Fragment, useState } from 'react';
import { makeStyles } from 'tss-react/mui';

const useToolStyle = makeStyles()((theme: Theme) => ({
tool: {
minWidth: theme.spacing(3),
minHeight: theme.spacing(3),
color: theme.palette.text.primary,
padding: 0,
},
}));

type Modal = 'dialog';
export const PapayaComponentDiagramToolContribution = ({ x, y }) => {
const { project } = useCurrentProject();
const [modal, setModal] = useState<Modal | null>(null);
const { classes } = useToolStyle();

const onClose = () => {
setModal(null);
};

let modalElement: JSX.Element | null = null;
if (modal === 'dialog') {
modalElement = (
<>
<Dialog open={true} onClose={onClose} fullWidth>
<DialogContent>
<DialogContentText>
x: {x}, y:{y}
</DialogContentText>
</DialogContent>
</Dialog>
</>
);
}

if (project.natures.filter((nature) => nature.name === 'siriusComponents://nature?kind=papaya').length > 0) {
return (
<Fragment key="coordinates-modal-contribution">
<IconButton
className={classes.tool}
size="small"
color="inherit"
aria-label="Coordinates"
title="Coordinates"
onClick={() => setModal('dialog')}
data-testid="coordinates-tool">
<RadarIcon sx={{ fontSize: 16 }} />
</IconButton>
{modalElement}
</Fragment>
);
}
return null;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023, 2024 Obeo.
* Copyright (c) 2023, 2025 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 @@ -16,13 +16,17 @@ import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import IconButton from '@mui/material/IconButton';
import { Theme } from '@mui/material/styles';
import { Node, useNodes } from '@xyflow/react';
import { Fragment, useState } from 'react';
import { makeStyles } from 'tss-react/mui';

const useToolStyle = makeStyles()(() => ({
const useToolStyle = makeStyles()((theme: Theme) => ({
tool: {
width: '36px',
minWidth: theme.spacing(3),
minHeight: theme.spacing(3),
color: theme.palette.text.primary,
padding: 0,
},
}));

Expand Down Expand Up @@ -66,7 +70,7 @@ export const PapayaComponentLabelDetailToolContribution = ({ diagramElementId }:
title="Label detail"
onClick={() => setModal('dialog')}
data-testid="label-detail">
<Slideshow />
<Slideshow sx={{ fontSize: 16 }} />
</IconButton>
{modalElement}
</Fragment>
Expand Down

0 comments on commit a0dd9bd

Please sign in to comment.