Skip to content

Commit

Permalink
[3763] Adapt the Selection Dialog to the TreeEvent refactoring
Browse files Browse the repository at this point in the history
Bug: #3763
Signed-off-by: Florian Barbin <[email protected]>
  • Loading branch information
florianbarbin committed Sep 12, 2024
1 parent 28e66e7 commit 36df83b
Show file tree
Hide file tree
Showing 15 changed files with 607 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.selection.configurations;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration;

/**
* The configuration of the selection dialog event processor.
*
* @author fbarbin
*/
public class SelectionDialogTreeConfiguration implements IRepresentationConfiguration {

private final String treeId;

private final List<String> expanded;

public SelectionDialogTreeConfiguration(String editingContextId, String treeId, List<String> expanded) {
this.expanded = Objects.requireNonNull(expanded);

StringBuilder idBuilder = new StringBuilder(treeId);

List<String> expandedObjectIds = expanded.stream().map(id -> URLEncoder.encode(id, StandardCharsets.UTF_8)).toList();
idBuilder.append("&expandedIds=[").append(String.join(",", expandedObjectIds)).append("]");

this.treeId = idBuilder.toString();
}

@Override
public String getId() {
return this.treeId;
}

public List<String> getExpanded() {
return this.expanded;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.selection.dto;

import java.util.List;
import java.util.UUID;

import org.eclipse.sirius.components.core.api.IInput;

/**
* The input of the selection dialog tree event subscription.
*
* @author fbarbin
*/
public record SelectionDialogTreeEventInput(UUID id, String editingContextId, String treeId, List<String> expanded) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.selection.services;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorFactory;
import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry;
import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory;
import org.eclipse.sirius.components.collaborative.selection.configurations.SelectionDialogTreeConfiguration;
import org.eclipse.sirius.components.collaborative.trees.TreeEventProcessor;
import org.eclipse.sirius.components.collaborative.trees.api.ITreeEventHandler;
import org.eclipse.sirius.components.collaborative.trees.api.ITreeService;
import org.eclipse.sirius.components.collaborative.trees.api.TreeCreationParameters;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
import org.eclipse.sirius.components.representations.GetOrCreateRandomIdProvider;
import org.eclipse.sirius.components.representations.VariableManager;
import org.eclipse.sirius.components.trees.description.TreeDescription;
import org.springframework.stereotype.Service;

import io.micrometer.core.instrument.simple.SimpleMeterRegistry;

/**
* Used to create the tree event processors in the context of a selection dialog tree.
*
* @author fbarbin
*/
@Service
public class SelectionDialogTreeEventProcessorFactory implements IRepresentationEventProcessorFactory {

private final IRepresentationDescriptionSearchService representationDescriptionSearchService;

private final ITreeService treeService;

private final List<ITreeEventHandler> treeEventHandlers;

private final ISubscriptionManagerFactory subscriptionManagerFactory;

private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry;

public SelectionDialogTreeEventProcessorFactory(IRepresentationDescriptionSearchService representationDescriptionSearchService, List<ITreeEventHandler> treeEventHandlers, ITreeService treeService, IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, ISubscriptionManagerFactory subscriptionManagerFactory) {
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
this.treeService = Objects.requireNonNull(treeService);
this.treeEventHandlers = Objects.requireNonNull(treeEventHandlers);
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory);
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry);
}

@Override
public boolean canHandle(IRepresentationConfiguration configuration) {
return configuration instanceof SelectionDialogTreeConfiguration;
}

@Override
public Optional<IRepresentationEventProcessor> createRepresentationEventProcessor(IRepresentationConfiguration configuration, IEditingContext editingContext) {
if (configuration instanceof SelectionDialogTreeConfiguration selectionDialogTreeConfiguration) {

Optional<TreeDescription> optionalTreeDescription = this.findTreeDescription(editingContext, selectionDialogTreeConfiguration);
if (optionalTreeDescription.isPresent()) {
var treeDescription = optionalTreeDescription.get();

TreeCreationParameters treeCreationParameters = TreeCreationParameters.newTreeCreationParameters(selectionDialogTreeConfiguration.getId())
.treeDescription(treeDescription)
.activeFilterIds(List.of())
.expanded(selectionDialogTreeConfiguration.getExpanded())
.editingContext(editingContext)
.build();

IRepresentationEventProcessor treeEventProcessor = new TreeEventProcessor(editingContext, this.treeService, treeCreationParameters, this.treeEventHandlers,
this.subscriptionManagerFactory.create(), new SimpleMeterRegistry(), this.representationRefreshPolicyRegistry);
return Optional.of(treeEventProcessor);
}
}
return Optional.empty();
}
private Optional<TreeDescription> findTreeDescription(IEditingContext editingContext, SelectionDialogTreeConfiguration treeConfiguration) {
VariableManager variableManager = new VariableManager();
variableManager.put(GetOrCreateRandomIdProvider.PREVIOUS_REPRESENTATION_ID, treeConfiguration.getId());
return this.representationDescriptionSearchService
.findAll(editingContext).values().stream()
.filter(TreeDescription.class::isInstance)
.map(TreeDescription.class::cast)
.filter(treeDescription -> treeDescription.getCanCreatePredicate().test(variableManager))
.findFirst();
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
extend type Subscription {
selectionDialogTreeEvent(input: SelectionDialogTreeEventInput!): TreeEventPayload!
}

input SelectionDialogTreeEventInput {
id: ID!
treeId: String!
editingContextId: ID!
expanded: [String!]!
}

type SelectionDescription implements RepresentationDescription {
id: ID!
label: String!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.sirius.components.selection.graphql.datafetchers.subscription;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.eclipse.sirius.components.annotations.spring.graphql.SubscriptionDataFetcher;
import org.eclipse.sirius.components.collaborative.selection.configurations.SelectionDialogTreeConfiguration;
import org.eclipse.sirius.components.collaborative.selection.dto.SelectionDialogTreeEventInput;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEventProcessorSubscriptionProvider;
import org.eclipse.sirius.components.graphql.api.IExceptionWrapper;
import org.eclipse.sirius.components.graphql.api.LocalContextConstants;
import org.reactivestreams.Publisher;

import graphql.execution.DataFetcherResult;
import graphql.schema.DataFetchingEnvironment;

/**
* The data fetcher used to send the refreshed tree to a selection dialog tree subscription .
*
* @author fbarbin
*/
@SubscriptionDataFetcher(type = "Subscription", field = "selectionDialogTreeEvent")
public class SubscriptionSelectionDialogTreeEventDataFetcher implements IDataFetcherWithFieldCoordinates<Publisher<DataFetcherResult<IPayload>>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IExceptionWrapper exceptionWrapper;

private final IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider;

public SubscriptionSelectionDialogTreeEventDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider) {
this.objectMapper = Objects.requireNonNull(objectMapper);
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
this.eventProcessorSubscriptionProvider = Objects.requireNonNull(eventProcessorSubscriptionProvider);
}

@Override
public Publisher<DataFetcherResult<IPayload>> get(DataFetchingEnvironment environment) throws Exception {
Object argument = environment.getArgument(INPUT_ARGUMENT);
var input = this.objectMapper.convertValue(argument, SelectionDialogTreeEventInput.class);
var selectionDialogTreeConfiguration = new SelectionDialogTreeConfiguration(input.editingContextId(), input.treeId(), input.expanded());

Map<String, Object> localContext = new HashMap<>();
localContext.put(LocalContextConstants.EDITING_CONTEXT_ID, input.editingContextId());
localContext.put(LocalContextConstants.REPRESENTATION_ID, selectionDialogTreeConfiguration.getId());

return this.exceptionWrapper.wrapFlux(() -> this.eventProcessorSubscriptionProvider.getSubscription(input.editingContextId(), selectionDialogTreeConfiguration, input), input)
.map(payload -> DataFetcherResult.<IPayload>newResult()
.data(payload)
.localContext(localContext)
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@apollo/client": "3.10.4",
"@eclipse-sirius/sirius-components-core": "*",
"@eclipse-sirius/sirius-components-diagrams": "*",
"@eclipse-sirius/sirius-components-trees": "*",
"@mui/material": "5.15.19",
"@mui/icons-material": "5.15.19",
"@xstate/react": "3.0.0",
Expand All @@ -46,6 +47,7 @@
"@apollo/client": "3.10.4",
"@eclipse-sirius/sirius-components-core": "*",
"@eclipse-sirius/sirius-components-diagrams": "*",
"@eclipse-sirius/sirius-components-trees": "*",
"@eclipse-sirius/sirius-components-tsconfig": "*",
"@mui/material": "5.15.19",
"@mui/icons-material": "5.15.19",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,32 @@
*******************************************************************************/
import { Selection, SelectionContext } from '@eclipse-sirius/sirius-components-core';
import { DiagramDialogComponentProps } from '@eclipse-sirius/sirius-components-diagrams';
import { TreeItemActionProps, TreeView } from '@eclipse-sirius/sirius-components-trees';
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import IconButton from '@mui/material/IconButton';
import { useEffect, useState } from 'react';
import { makeStyles } from 'tss-react/mui';
import { DiagramDialogComponentState } from './SelectionDialog.types';
import { DiagramDialogState } from './SelectionDialog.types';
import { SelectionDialogTreeView } from './SelectionDialogTreeView';
import { useSelectionDescription } from './useSelectionDescription';

export const SELECTION_DIALOG_TYPE: string = 'selectionDialogDescription';

const useTreeStyle = makeStyles()((theme) => ({
borderStyle: {
border: '1px solid',
borderColor: theme.palette.grey[500],
height: 300,
overflow: 'auto',
},
}));

export const SelectionDialog = ({
editingContextId,
dialogDescriptionId,
targetObjectId,
onClose,
onFinish,
}: DiagramDialogComponentProps) => {
const initialState: DiagramDialogComponentState = {
const initialState: DiagramDialogState = {
treeDescriptionId: '',
message: '',
selectedObjects: [],
};
const { classes } = useTreeStyle();
const [state, setState] = useState<DiagramDialogComponentState>(initialState);

const [state, setState] = useState<DiagramDialogState>(initialState);

const { loading, selectionDescription } = useSelectionDescription({
editingContextId,
Expand All @@ -71,25 +58,16 @@ export const SelectionDialog = ({
}));
}
}, [loading, selectionDescription]);

let content: JSX.Element | null = null;

if (state.treeDescriptionId) {
content = (
<div className={classes.borderStyle}>
<TreeView
editingContextId={editingContextId}
readOnly={true}
treeId={`selection://?treeDescriptionId=${encodeURIComponent(
state.treeDescriptionId
)}&targetObjectId=${encodeURIComponent(targetObjectId)}`}
enableMultiSelection={false}
synchronizedWithSelection={true}
activeFilterIds={[]}
textToFilter={''}
textToHighlight={''}
treeItemActionRender={(props) => <SelectionDialogTreeItemAction {...props} />}
/>
</div>
<SelectionDialogTreeView
editingContextId={editingContextId}
targetObjectId={targetObjectId}
treeDescriptionId={state.treeDescriptionId}
/>
);
}
return (
Expand Down Expand Up @@ -126,20 +104,3 @@ export const SelectionDialog = ({
</SelectionContext.Provider>
);
};

const SelectionDialogTreeItemAction = ({ onExpandAll, item, isHovered }: TreeItemActionProps) => {
if (!onExpandAll || !item || !item.hasChildren || !isHovered) {
return null;
}
return (
<IconButton
size="small"
data-testid="expand-all"
title="expand all"
onClick={() => {
onExpandAll(item);
}}>
<UnfoldMoreIcon style={{ fontSize: 12 }} />
</IconButton>
);
};
Loading

0 comments on commit 36df83b

Please sign in to comment.