Skip to content

Commit

Permalink
Merge branch 'AOT-Technologies:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
kiran-aot authored Dec 2, 2024
2 parents 312d571 + 026cf2b commit ed767ee
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 46 deletions.
2 changes: 2 additions & 0 deletions forms-flow-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ the system. It is built using Python :snake: .

* For docker based installation [Docker](https://docker.com) need to be installed.
* Admin access to [Keycloak](../forms-flow-idm/keycloak) server and ensure audience(camunda-rest-api) is setup in Keycloak-bpm server.
* Ensure that the `forms-flow-redis` service is running and accessible on port `6379`. For more details, refer to the [forms-flow-redis README](../forms-flow-redis/README.md).


## Solution Setup

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Meta: # pylint: disable=too-few-public-methods
deleted = fields.Boolean(data_key="deleted")
description = fields.Str(data_key="description")
prompt_new_version = fields.Bool(data_key="promptNewVersion", dump_only=True)
is_migrated = fields.Bool(data_key="isMigrated", required=False)


class FormProcessMapperListReqSchema(Schema):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,8 @@ def create_form(data, is_designer, **kwargs): # pylint:disable=too-many-locals
"formRevisionNumber": "V1",
"status": FormProcessMapperStatus.INACTIVE.value,
"anonymous": anonymous,
"task_variable": task_variable,
"is_migrated": is_migrated,
"taskVariables": task_variable,
"isMigrated": is_migrated,
}

mapper = FormProcessMapperService.mapper_create(mapper_data)
Expand All @@ -431,6 +431,7 @@ def create_form(data, is_designer, **kwargs): # pylint:disable=too-many-locals
"resourceId": parent_form_id,
"resourceDetails": {},
"roles": [],
"userName": user.user_name,
},
"designer": {
"resourceId": parent_form_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ def import_form(
"titleChanged": title_changed,
"anonymousChanged": anonymous_changed,
"description": mapper.description if form_only else description,
"is_migrated": mapper.is_migrated,
"isMigrated": mapper.is_migrated,
}
FormProcessMapperService.mapper_create(mapper_data)
FormProcessMapperService.mark_unpublished(mapper.id)
Expand Down
2 changes: 2 additions & 0 deletions forms-flow-documents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ template should be valid jinja template.

* For docker based installation [Docker](https://docker.com) need to be installed.
* Admin access to [Keycloak](../forms-flow-idm/keycloak) server and ensure audience(camunda-rest-api) is setup in Keycloak-bpm server.
* Ensure that the `forms-flow-redis` service is running and accessible on port `6379`. For more details, refer to the [forms-flow-redis README](../forms-flow-redis/README.md).


## Solution Setup

Expand Down
33 changes: 33 additions & 0 deletions forms-flow-redis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# formsflow.ai Redis

This repository contains a Docker Compose configuration to set up a lightweight Redis service using the official Redis Alpine image.


## Table of Content

1. [Prerequisites](#prerequisites)
2. [Running the Application](#running-the-application)

## Prerequisites

* For docker based installation [Docker](https://docker.com) need to be installed.

### Running the Application

* forms-flow-redis service uses port 6379, make sure the port is available.
* `cd {Your Directory}/forms-flow-ai/forms-flow-redis`

* Run `docker-compose up -d` to start.

#### To Stop the Application

* Run `docker-compose stop` to stop.

### Important Note

The forms-flow-redis service must be up and running before installing and starting the following services:

- forms-flow-api
- forms-flow-documents-api

Ensure that Redis is functional and accessible on port 6379 before proceeding with the installation of these dependent services. Failure to start forms-flow-redis first may result in errors during the initialization or runtime of the dependent applications.
3 changes: 3 additions & 0 deletions forms-flow-web/src/components/Form/EditForm/FlowEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ const FlowEdit = forwardRef(({ isPublished = false, CategoryType, setWorkflowIsC
}
//if xml is same as existing process data, no need to update
const isEqual = await compareXML(processData?.processData, xml);

if (isEqual && !isReverted) {
showToast && toast.success(t("Process updated successfully"));
disableWorkflowChange();
return;
}

Expand Down Expand Up @@ -264,6 +266,7 @@ const FlowEdit = forwardRef(({ isPublished = false, CategoryType, setWorkflowIsC
form={formData}
showTaskVarModal={showTaskVarModal}
onClose={CloseTaskVarModal}
isPublished={isPublished}
/>
)}
</>
Expand Down
2 changes: 0 additions & 2 deletions forms-flow-web/src/components/Form/constants/FormTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ function FormTable() {
</tr>
);
})}
<tr>
{formData.length ? (
<TableFooter
limit={limit}
Expand All @@ -209,7 +208,6 @@ function FormTable() {
) : (
<td colSpan={3}></td>
)}
</tr>
</tbody>
) : !searchFormLoading ? (
<NoDataFound />
Expand Down
115 changes: 85 additions & 30 deletions forms-flow-web/src/components/Modals/TaskVariableModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { Form } from "@aot-technologies/formio-react";
import PropTypes from "prop-types";
import { useDispatch ,useSelector } from "react-redux";
import utils from "@aot-technologies/formiojs/lib/utils";
import {
saveFormProcessMapperPut,
} from "../../apiManager/services/processServices";
Expand All @@ -27,7 +28,7 @@ const PillList = React.memo(({ alternativeLabels, onRemove }) => {
<CustomPill
key={key}
label={altVariable || labelOfComponent}
icon={<CloseIcon color="#253DF4" data-testid="pill-remove-icon" />}
icon={(key !== "applicationId" && key !== "applicationStatus") && <CloseIcon color="#253DF4" data-testid="pill-remove-icon" />}
bg="#E7E9FE"
onClick={() => onRemove(key)}
secondaryLabel={key}
Expand Down Expand Up @@ -57,30 +58,66 @@ const FormComponent = React.memo(
const detailsRef = useRef(null); // Ref for the details container
const { t } = useTranslation();


const ignoredTypes = new Set([
"button",
"columns",
"panel",
"well",
"container",
"htmlelement",
"tabs",
]);
const ignoredKeys = new Set([
"hidden",
]);
const handleClick = useCallback(
(e) => {

const formioComponent = e.target.closest(".formio-component");
const highlightedElement = document.querySelector(".formio-hilighted");

if (highlightedElement) {
highlightedElement.classList.remove("formio-hilighted");
}

if (formioComponent) {
setShowElement(true);
formioComponent.classList.add("formio-hilighted");

let classes = Array.from(formioComponent.classList);
classes = classes.filter((cls) =>
let classes = Array.from(formioComponent.classList).filter((cls) =>
cls.startsWith("formio-component-")
);
const typeClass = classes[classes.length - 2];
const keyClass = classes[classes.length - 1];

const typeClass = classes[classes.length - 2];
//if key and type are same , then there will be only one class for both
const componentType = typeClass ? typeClass.split("-").pop() : keyClass.split("-").pop();

// Check if the component type is in the ignored list
if (ignoredTypes.has(componentType)) {
setShowElement(false);
setSelectedComponent({
key: null,
type: "",
label: "",
altVariable: "",
});
return;
}


const componentKey = keyClass?.split("-").pop();
// Check if the component key is in the ignored list
if (ignoredKeys.has(componentKey)) {
setShowElement(false);
setSelectedComponent({
key: null,
type: "",
label: "",
altVariable: "",
});
return;
}

const labelElement = formioComponent.querySelector("label");
let label = "";

if (labelElement) {
label = Array.from(labelElement.childNodes)
.filter(
Expand All @@ -93,10 +130,12 @@ const FormComponent = React.memo(
.map((node) => node.textContent.trim())
.join(" ");
}

const componentKey = keyClass?.split("-").pop();
const componentType = typeClass?.split("-").pop();
// const currentComponent = utils.getComponent(form.components,componentKey);

// Highlight the selected component
formioComponent.classList.add("formio-hilighted");
setShowElement(true);

// Update the selected component state
setSelectedComponent({
key: componentKey,
type: componentType,
Expand Down Expand Up @@ -166,7 +205,7 @@ const FormComponent = React.memo(
options={{
viewAsHtml: true,
readOnly: true,
}}
}}
formReady={(e) => {
formRef.current = e;
}}
Expand Down Expand Up @@ -231,7 +270,7 @@ FormComponent.propTypes = {
setSelectedComponent: PropTypes.func.isRequired,
};
const TaskVariableModal = React.memo(
({ showTaskVarModal, onClose, form }) => {
({ showTaskVarModal, isPublished = false ,onClose, form }) => {
const { t } = useTranslation();
const dispatch = useDispatch();
const formProcessList = useSelector(
Expand All @@ -241,18 +280,32 @@ const TaskVariableModal = React.memo(
const [alternativeLabels, setAlternativeLabels] = useState({});

useEffect(() => {
if (formProcessList?.taskVariables?.length > 0) {
const updatedLabels = {};
formProcessList.taskVariables.forEach(({ key, label, type }) => {
updatedLabels[key] = {
key,
altVariable: label, // Use label from taskVariables as altVariable
labelOfComponent: label, // Set the same label for labelOfComponent
type:type
};
});
setAlternativeLabels(updatedLabels);
}
//filtering applicationId and applicationStatus components from form
const filteredComponents = Object.values(utils.flattenComponents(form.components)).filter(
({ key }) => key === "applicationStatus" || key === "applicationId"
);

const updatedLabels = {};
// Add filtered components to updatedLabels
filteredComponents.forEach(({ key, label, type }) => {
updatedLabels[key] = {
key,
altVariable: label,
labelOfComponent: label,
type: type,
};
});

// Add taskVariables to updatedLabels
formProcessList?.taskVariables?.forEach(({ key, label, type }) => {
updatedLabels[key] = {
key,
altVariable: label, // Use label from taskVariables as altVariable
labelOfComponent: label, // Set the same label for labelOfComponent
type: type,
};
});
setAlternativeLabels(updatedLabels);
}, [formProcessList]);
const [selectedComponent, setSelectedComponent] = useState({
key: null,
Expand Down Expand Up @@ -340,6 +393,7 @@ const TaskVariableModal = React.memo(
variant="primary"
size="md"
className=""
disabled={isPublished}
label={t("Save")}
ariaLabel="save task variable btn"
dataTestid="save-task-variable-btn"
Expand All @@ -364,6 +418,7 @@ const TaskVariableModal = React.memo(
TaskVariableModal.propTypes = {
showTaskVarModal: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
form: PropTypes.object.isRequired
form: PropTypes.object.isRequired,
isPublished: PropTypes.bool.isRequired,
};
export default TaskVariableModal;
4 changes: 3 additions & 1 deletion forms-flow-web/src/components/Modeler/ProcessCreateEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,10 @@ const ProcessCreateEdit = ({ type }) => {
if (!isValid) return;

const isEqual = await checkIfEqual(isCreate, xml);
if (!isReverted && !isCreateMode && isEqual)
if (!isReverted && !isCreateMode && isEqual){
disableWorkflowChange();
return handleAlreadyUpToDate(isPublishing);
}

setSavingFlow(true);

Expand Down
23 changes: 13 additions & 10 deletions forms-flow-web/src/helper/processHelper.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { extractDataFromDiagram } from "../components/Modeler/helpers/helper";
import BpmnModdle from "bpmn-moddle";
import DmnModdle from "dmn-moddle";
import isEqual from "lodash/isEqual";
import { toast } from "react-toastify";
import {
ERROR_LINTING_CLASSNAME,
WARNING_LINTING_CLASSNAME,
} from "../components/Modeler/constants/bpmnModelerConstants";
const bpmnModdle = new BpmnModdle();
const dmnModdle = new DmnModdle();

export const parseBpmn = async (xmlString) => {
const { rootElement: definitionsA } = await bpmnModdle.fromXML(xmlString);
return definitionsA;


const normalizeXML = (xmlString) => {
const parser = new DOMParser();
const serializer = new XMLSerializer();
// Parse the XML string to a DOM object
const xmlDoc = parser.parseFromString(xmlString, "application/xml");
// Serialize the DOM back to a string (minimized formatting differences)
return serializer.serializeToString(xmlDoc);
};

export const compareXML = async (xmlString1, xmlString2) => {
try {
// Parse both BPMN XMLs to their JSON structure
const bpmn1 = await parseBpmn(xmlString1);
const bpmn2 = await parseBpmn(xmlString2);
const bpmn1 = normalizeXML(xmlString1);
const bpmn2 = normalizeXML(xmlString2);
// Compare the JSON structures
return isEqual(bpmn1, bpmn2);
return bpmn1 == bpmn2;
} catch (error) {
console.error("Error while comparing BPMN:", error);
}
Expand Down Expand Up @@ -63,7 +66,7 @@ export const validateProcess = (xml, lintErrors, translation = (i) => i) => {
export const createXMLFromModeler = async (modeler) => {
try {
// Convert diagram to xml
let { xml } = await modeler.saveXML();
let { xml } = await modeler.saveXML({ format: true });
// Set isExecutable to true
xml = xml.replaceAll('isExecutable="false"', 'isExecutable="true"');
return xml;
Expand Down

0 comments on commit ed767ee

Please sign in to comment.