Skip to content

Commit

Permalink
Instance composer will render all required by default embedded entiti…
Browse files Browse the repository at this point in the history
…es in the canvas (Issue #6037, PR #6054)

# Description

Render all required default embedded entities on Canvas, previously we would render only one, now multiple entites of the same type are also covered

![Screenshot 2024-11-15 at 14 14 58](https://github.com/user-attachments/assets/e1798a7e-123a-484f-8e05-d5bb7f46308b)

closes #6037

# Self Check:

Strike through any lines that are not applicable (`~~line~~`) then check the box

- [ ] Attached issue to pull request
- [ ] Changelog entry
- [ ] Code is clear and sufficiently documented
- [ ] Sufficient test cases (reproduces the bug/tests the requested feature)
- [ ] Correct, in line with design
- [ ] End user documentation is included or an issue is created for end-user documentation (add ref to issue here: )
  • Loading branch information
matborowczyk authored and inmantaci committed Nov 21, 2024
1 parent 877e4a4 commit dbfe5c7
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 27 deletions.
6 changes: 6 additions & 0 deletions changelogs/unreleased/6037-multiple-default-embedded.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
description: Instance composer will render all required by default embedded entities in the canvas
issue-nr: 6037
change-type: patch
destination-branches: [master]
sections:
minor-improvement: "{{description}}"
36 changes: 35 additions & 1 deletion src/UI/Components/Diagram/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ describe("updateAttributes", () => {
});
});

describe("createComposerEntity", () => {
describe("addDefaultEntities", () => {
it("return empty array for service without embedded entities to add to the graph ", () => {
const graph = new dia.Graph({});
const embedded = addDefaultEntities(graph, parentModel);
Expand Down Expand Up @@ -279,6 +279,40 @@ describe("createComposerEntity", () => {
expect(embedded[0].getName()).toStrictEqual("child_container");
});

it("adds all default entities to the graph for service with embedded entity with lower_limit > 1 ", () => {
const dispatchEventSpy = jest.spyOn(document, "dispatchEvent");
const graph = new dia.Graph({});
const customModel = {
...containerModel,
embedded_entities: [
{ ...containerModel.embedded_entities[0], lower_limit: 2 },
],
};

const embedded = addDefaultEntities(graph, customModel);

expect(dispatchEventSpy).toHaveBeenCalledTimes(2);

//assert the arguments of the first call - calls is array of the arguments of each call
expect(
(dispatchEventSpy.mock.calls[0][0] as CustomEvent).detail,
).toMatchObject({
action: "add",
name: "child_container",
});
//assert the arguments of the second call - calls is array of the arguments of each call
expect(
(dispatchEventSpy.mock.calls[1][0] as CustomEvent).detail,
).toMatchObject({
action: "add",
name: "child_container",
});
expect(embedded.length).toBe(2);

expect(embedded[0].getName()).toStrictEqual("child_container");
expect(embedded[1].getName()).toStrictEqual("child_container");
});

it("adds default entity for service with nested embedded entities to the graph ", () => {
const dispatchEventSpy = jest.spyOn(document, "dispatchEvent");

Expand Down
81 changes: 56 additions & 25 deletions src/UI/Components/Diagram/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,44 +451,75 @@ export function addDefaultEntities(
): ServiceEntityBlock[] {
const embedded_entities = service.embedded_entities
.filter((embedded_entity) => embedded_entity.lower_limit > 0)
.map((embedded_entity) => {
.flatMap((embedded_entity) => {
const fieldCreator = new FieldCreator(new CreateModifierHandler());
const fields = fieldCreator.attributesToFields(
embedded_entity.attributes,
);
const attributes = createFormState(fields);

const embeddedEntity = createComposerEntity({
serviceModel: embedded_entity,
isCore: false,
isInEditMode: false,
attributes: createFormState(fields),
isEmbedded: true,
holderName: service.name,
});

document.dispatchEvent(
new CustomEvent("updateStencil", {
detail: {
name: embedded_entity.name,
action: EmbeddedEventEnum.ADD,
},
}),
);
if (embedded_entity.lower_limit > 1) {
const embedded_entities: ServiceEntityBlock[] = [];

embeddedEntity.addTo(graph);
const subEmbeddedEntities = addDefaultEntities(graph, embedded_entity);
for (let i = 0; i < embedded_entity.lower_limit; i++) {
embedded_entities.push(
addSingleEntity(graph, embedded_entity, attributes, service.name),
);
}

subEmbeddedEntities.forEach((entity) => {
entity.set("embeddedTo", embeddedEntity.id);
});
connectEntities(graph, embeddedEntity, subEmbeddedEntities);
return embedded_entities;
}

return embeddedEntity;
return addSingleEntity(graph, embedded_entity, attributes, service.name);
});

return embedded_entities;
}

/**
* Helper function to add single default Embedded Entity to the graph - it's created to avoid code duplication in the addDefaultEntities function
*
* @param {dia.Graph} graph - The jointJS graph to which entities should be added.
* @param {EmbeddedEntity} service - The service model or embedded entity used to generate the default entities.
* @param {InstanceAttributeModel} attributes - attributes of given instance/entity
* @param {string} holderName - name of the entity to which it is embedded/connected
* @returns {ServiceEntityBlock}
*/
const addSingleEntity = (
graph: dia.Graph,
model: EmbeddedEntity,
attributes: InstanceAttributeModel,
holderName: string,
): ServiceEntityBlock => {
const embeddedEntity = createComposerEntity({
serviceModel: model,
isCore: false,
isInEditMode: false,
attributes,
isEmbedded: true,
holderName,
});

document.dispatchEvent(
new CustomEvent("updateStencil", {
detail: {
name: model.name,
action: EmbeddedEventEnum.ADD,
},
}),
);

embeddedEntity.addTo(graph);
const subEmbeddedEntities = addDefaultEntities(graph, model);

subEmbeddedEntities.forEach((entity) => {
entity.set("embeddedTo", embeddedEntity.id);
});
connectEntities(graph, embeddedEntity, subEmbeddedEntities);

return embeddedEntity;
};

/**
* Function that iterates through service instance attributes for values and appends in jointJS entity for display
*
Expand Down
2 changes: 1 addition & 1 deletion src/UI/Components/Diagram/components/RightSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const RightSidebar: React.FC<Props> = ({ editable }) => {
const lowerLimit = entityState.min;

const isLowerLimitReached =
lowerLimit && entityState.current === lowerLimit;
lowerLimit && entityState.current <= lowerLimit;

return !isCellCore && canBeRemoved && !isLowerLimitReached;
});
Expand Down

0 comments on commit dbfe5c7

Please sign in to comment.