Merge remote-tracking branch 'origin/main' into feature/carbon_process_model_show
This commit is contained in:
commit
b58e5be583
|
@ -4,6 +4,7 @@ from dataclasses import field
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import marshmallow
|
||||
from marshmallow import INCLUDE
|
||||
from marshmallow import Schema
|
||||
|
||||
|
@ -61,6 +62,20 @@ CONTENT_TYPES = {
|
|||
}
|
||||
|
||||
|
||||
@dataclass()
|
||||
class FileReference:
|
||||
"""File Reference Information.
|
||||
|
||||
Includes items such as the process id and name for a BPMN,
|
||||
or the Decision id and Decision name for a DMN file. There may be more than
|
||||
one reference that points to a particular file.
|
||||
"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
type: str # can be 'process', 'decision', or just 'file'
|
||||
|
||||
|
||||
@dataclass(order=True)
|
||||
class File:
|
||||
"""File."""
|
||||
|
@ -70,17 +85,12 @@ class File:
|
|||
content_type: str
|
||||
name: str
|
||||
type: str
|
||||
document: dict
|
||||
last_modified: datetime
|
||||
size: int
|
||||
process_instance_id: Optional[int] = None
|
||||
irb_doc_code: Optional[str] = None
|
||||
data_store: Optional[dict] = field(default_factory=dict)
|
||||
user_uid: Optional[str] = None
|
||||
references: Optional[list[FileReference]] = None
|
||||
file_contents: Optional[bytes] = None
|
||||
process_model_id: Optional[str] = None
|
||||
process_group_id: Optional[str] = None
|
||||
archived: bool = False
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""__post_init__."""
|
||||
|
@ -100,7 +110,6 @@ class File:
|
|||
name=file_name,
|
||||
content_type=content_type,
|
||||
type=file_type.value,
|
||||
document={},
|
||||
last_modified=last_modified,
|
||||
size=file_size,
|
||||
)
|
||||
|
@ -118,32 +127,29 @@ class FileSchema(Schema):
|
|||
"id",
|
||||
"name",
|
||||
"content_type",
|
||||
"process_instance_id",
|
||||
"irb_doc_code",
|
||||
"last_modified",
|
||||
"type",
|
||||
"archived",
|
||||
"size",
|
||||
"data_store",
|
||||
"document",
|
||||
"user_uid",
|
||||
"url",
|
||||
"file_contents",
|
||||
"process_model_id",
|
||||
"references",
|
||||
"process_group_id",
|
||||
"process_model_id",
|
||||
]
|
||||
unknown = INCLUDE
|
||||
references = marshmallow.fields.List(
|
||||
marshmallow.fields.Nested("FileReferenceSchema")
|
||||
)
|
||||
|
||||
# url = Method("get_url")
|
||||
#
|
||||
# def get_url(self, obj):
|
||||
# token = 'not_available'
|
||||
# if hasattr(obj, 'id') and obj.id is not None:
|
||||
# file_url = url_for("/v1_0.crc_api_file_get_file_data_link", file_id=obj.id, _external=True)
|
||||
# if hasattr(flask.g, 'user'):
|
||||
# token = flask.g.user.encode_auth_token()
|
||||
# url = file_url + '?auth_token=' + urllib.parse.quote_plus(token)
|
||||
# return url
|
||||
# else:
|
||||
# return ""
|
||||
#
|
||||
|
||||
class FileReferenceSchema(Schema):
|
||||
"""FileSchema."""
|
||||
|
||||
class Meta:
|
||||
"""Meta."""
|
||||
|
||||
model = FileReference
|
||||
fields = ["id", "name", "type"]
|
||||
unknown = INCLUDE
|
||||
|
|
|
@ -65,6 +65,7 @@ from spiffworkflow_backend.services.error_handling_service import ErrorHandlingS
|
|||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
from spiffworkflow_backend.services.message_service import MessageService
|
||||
from spiffworkflow_backend.services.process_instance_processor import MyCustomParser
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
ProcessInstanceProcessor,
|
||||
)
|
||||
|
@ -263,6 +264,10 @@ def process_model_show(process_group_id: str, process_model_id: str) -> Any:
|
|||
process_model = get_process_model(process_model_id, process_group_id)
|
||||
files = sorted(SpecFileService.get_files(process_model))
|
||||
process_model.files = files
|
||||
for file in process_model.files:
|
||||
file.references = SpecFileService.get_references_for_file(
|
||||
file, process_model, MyCustomParser
|
||||
)
|
||||
process_model_json = ProcessModelInfoSchema().dump(process_model)
|
||||
return process_model_json
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
|
@ -14,6 +15,7 @@ from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException #
|
|||
|
||||
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
||||
from spiffworkflow_backend.models.file import File
|
||||
from spiffworkflow_backend.models.file import FileReference
|
||||
from spiffworkflow_backend.models.file import FileType
|
||||
from spiffworkflow_backend.models.message_correlation_property import (
|
||||
MessageCorrelationPropertyModel,
|
||||
|
@ -54,6 +56,41 @@ class SpecFileService(FileSystemService):
|
|||
)
|
||||
return files
|
||||
|
||||
@staticmethod
|
||||
def get_references_for_file(
|
||||
file: File, process_model_info: ProcessModelInfo, parser_class: Any
|
||||
) -> list[FileReference]:
|
||||
"""Uses spiffworkflow to parse BPMN and DMN files to determine how they can be externally referenced.
|
||||
|
||||
Returns a list of Reference objects that contain the type of reference, the id, the name.
|
||||
Ex.
|
||||
id = {str} 'Level3'
|
||||
name = {str} 'Level 3'
|
||||
type = {str} 'process'
|
||||
"""
|
||||
references: list[FileReference] = []
|
||||
file_path = SpecFileService.file_path(process_model_info, file.name)
|
||||
parser = parser_class()
|
||||
parser_type = None
|
||||
sub_parser = None
|
||||
if file.type == FileType.bpmn.value:
|
||||
parser.add_bpmn_file(file_path)
|
||||
parser_type = "process"
|
||||
sub_parsers = list(parser.process_parsers.values())
|
||||
elif file.type == FileType.dmn.value:
|
||||
parser.add_dmn_file(file_path)
|
||||
sub_parsers = list(parser.dmn_parsers.values())
|
||||
parser_type = "decision"
|
||||
else:
|
||||
return references
|
||||
for sub_parser in sub_parsers:
|
||||
references.append(
|
||||
FileReference(
|
||||
id=sub_parser.get_id(), name=sub_parser.get_name(), type=parser_type
|
||||
)
|
||||
)
|
||||
return references
|
||||
|
||||
@staticmethod
|
||||
def add_file(
|
||||
process_model_info: ProcessModelInfo, file_name: str, binary_data: bytes
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -21,7 +21,6 @@ def create_test_file(type: str, name: str) -> File:
|
|||
type=type,
|
||||
name=name,
|
||||
content_type=type,
|
||||
document={},
|
||||
last_modified=datetime.now(),
|
||||
size=1,
|
||||
)
|
||||
|
|
|
@ -5,10 +5,13 @@ import pytest
|
|||
from flask import Flask
|
||||
from flask_bpmn.api.api_error import ApiError
|
||||
from flask_bpmn.models.db import db
|
||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
from spiffworkflow_backend.models.bpmn_process_id_lookup import BpmnProcessIdLookup
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
|
||||
|
||||
class TestSpecFileService(BaseTest):
|
||||
|
@ -95,3 +98,44 @@ class TestSpecFileService(BaseTest):
|
|||
bpmn_process_id_lookups[0].bpmn_file_relative_path
|
||||
== self.call_activity_nested_relative_file_path
|
||||
)
|
||||
|
||||
def test_load_reference_information(
|
||||
self, app: Flask, with_db_and_bpmn_file_cleanup: None
|
||||
) -> None:
|
||||
"""Test_load_reference_information.
|
||||
|
||||
When getting files from the spec_file service, each file includes
|
||||
details about how the file can be referenced -- for instance
|
||||
it is possible to reference a DMN file with a Decision.id or
|
||||
a bpmn file with a process.id. These Decisions and processes
|
||||
can also have human readable display names, which should also be avaiable.
|
||||
Note that a single bpmn file can contain many processes, and
|
||||
a DMN file can (theoretically) contain many decisions. So this
|
||||
is an array.
|
||||
"""
|
||||
load_test_spec(
|
||||
"call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
)
|
||||
process_model_info = ProcessModelService().get_process_model(
|
||||
"call_activity_nested"
|
||||
)
|
||||
files = SpecFileService.get_files(process_model_info)
|
||||
|
||||
file = next(filter(lambda f: f.name == "call_activity_level_3.bpmn", files))
|
||||
ca_3 = SpecFileService.get_references_for_file(
|
||||
file, process_model_info, BpmnDmnParser
|
||||
)
|
||||
assert len(ca_3) == 1
|
||||
assert ca_3[0].name == "Level 3"
|
||||
assert ca_3[0].id == "Level3"
|
||||
assert ca_3[0].type == "process"
|
||||
|
||||
file = next(filter(lambda f: f.name == "level2c.dmn", files))
|
||||
dmn1 = SpecFileService.get_references_for_file(
|
||||
file, process_model_info, BpmnDmnParser
|
||||
)
|
||||
assert len(dmn1) == 1
|
||||
assert dmn1[0].name == "Decision 1"
|
||||
assert dmn1[0].id == "Decision_0vrtcmk"
|
||||
assert dmn1[0].type == "decision"
|
||||
|
|
|
@ -27,3 +27,6 @@ cypress/screenshots
|
|||
|
||||
# i keep accidentally committing these
|
||||
/test*.json
|
||||
|
||||
# Editors
|
||||
.idea
|
File diff suppressed because it is too large
Load Diff
|
@ -20,12 +20,13 @@
|
|||
"@types/node": "^18.6.5",
|
||||
"@types/react": "^18.0.17",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@uiw/react-md-editor": "^3.19.5",
|
||||
"autoprefixer": "10.4.8",
|
||||
"axios": "^0.27.2",
|
||||
"bootstrap": "^5.2.0",
|
||||
"bpmn-js": "^9.3.2",
|
||||
"bpmn-js-properties-panel": "^1.10.0",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#feature/more_launch_buttons_and_dropdowns",
|
||||
"craco": "^0.0.3",
|
||||
"date-fns": "^2.28.0",
|
||||
"diagram-js": "^8.5.0",
|
||||
|
|
|
@ -69,8 +69,14 @@ type OwnProps = {
|
|||
diagramXML?: string | null;
|
||||
fileName?: string;
|
||||
onLaunchScriptEditor?: (..._args: any[]) => any;
|
||||
onLaunchMarkdownEditor?: (..._args: any[]) => any;
|
||||
onLaunchBpmnEditor?: (..._args: any[]) => any;
|
||||
onLaunchJsonEditor?: (..._args: any[]) => any;
|
||||
onLaunchDmnEditor?: (..._args: any[]) => any;
|
||||
onElementClick?: (..._args: any[]) => any;
|
||||
onServiceTasksRequested?: (..._args: any[]) => any;
|
||||
onJsonFilesRequested?: (..._args: any[]) => any;
|
||||
onDmnFilesRequested?: (..._args: any[]) => any;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
|
@ -87,8 +93,14 @@ export default function ReactDiagramEditor({
|
|||
diagramXML,
|
||||
fileName,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMarkdownEditor,
|
||||
onLaunchBpmnEditor,
|
||||
onLaunchJsonEditor,
|
||||
onLaunchDmnEditor,
|
||||
onElementClick,
|
||||
onServiceTasksRequested,
|
||||
onJsonFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
url,
|
||||
}: OwnProps) {
|
||||
const [diagramXMLString, setDiagramXMLString] = useState('');
|
||||
|
@ -191,6 +203,17 @@ export default function ReactDiagramEditor({
|
|||
}
|
||||
}
|
||||
|
||||
function handleLaunchMarkdownEditor(
|
||||
element: any,
|
||||
value: string,
|
||||
eventBus: any
|
||||
) {
|
||||
if (onLaunchMarkdownEditor) {
|
||||
setPerformingXmlUpdates(true);
|
||||
onLaunchMarkdownEditor(element, value, eventBus);
|
||||
}
|
||||
}
|
||||
|
||||
function handleElementClick(event: any) {
|
||||
if (onElementClick) {
|
||||
onElementClick(event.element);
|
||||
|
@ -205,7 +228,7 @@ export default function ReactDiagramEditor({
|
|||
|
||||
setDiagramModelerState(diagramModeler);
|
||||
|
||||
diagramModeler.on('script.editor.launch', (event: any) => {
|
||||
diagramModeler.on('spiff.script.edit', (event: any) => {
|
||||
const { error, element, scriptType, script, eventBus } = event;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
|
@ -213,6 +236,35 @@ export default function ReactDiagramEditor({
|
|||
handleLaunchScriptEditor(element, script, scriptType, eventBus);
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.markdown.edit', (event: any) => {
|
||||
const { error, element, value, eventBus } = event;
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
handleLaunchMarkdownEditor(element, value, eventBus);
|
||||
});
|
||||
|
||||
/**
|
||||
* fixme: this is not in use yet, we need the ability to find bpmn files by id.
|
||||
*/
|
||||
diagramModeler.on('spiff.callactivity.edit', (event: any) => {
|
||||
if (onLaunchBpmnEditor) {
|
||||
onLaunchBpmnEditor(event.processId);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.file.edit', (event: any) => {
|
||||
if (onLaunchJsonEditor) {
|
||||
onLaunchJsonEditor(event.value);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.dmn.edit', (event: any) => {
|
||||
if (onLaunchDmnEditor) {
|
||||
onLaunchDmnEditor(event.value);
|
||||
}
|
||||
});
|
||||
|
||||
// 'element.hover',
|
||||
// 'element.out',
|
||||
// 'element.click',
|
||||
|
@ -226,12 +278,34 @@ export default function ReactDiagramEditor({
|
|||
diagramModeler.on('spiff.service_tasks.requested', (event: any) => {
|
||||
handleServiceTasksRequested(event);
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.json_files.requested', (event: any) => {
|
||||
if (onJsonFilesRequested) {
|
||||
onJsonFilesRequested(event);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.dmn_files.requested', (event: any) => {
|
||||
if (onDmnFilesRequested) {
|
||||
onDmnFilesRequested(event);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.json_files.requested', (event: any) => {
|
||||
handleServiceTasksRequested(event);
|
||||
});
|
||||
}, [
|
||||
diagramModelerState,
|
||||
diagramType,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMarkdownEditor,
|
||||
onLaunchBpmnEditor,
|
||||
onLaunchDmnEditor,
|
||||
onLaunchJsonEditor,
|
||||
onElementClick,
|
||||
onServiceTasksRequested,
|
||||
onJsonFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -17,11 +17,29 @@ export interface ProcessGroup {
|
|||
description?: string | null;
|
||||
}
|
||||
|
||||
export interface ProcessFileReference {
|
||||
id: string; // The unique id of the process or decision table.
|
||||
name: string; // The process or decision table name.
|
||||
type: string; // either "decision" or "process"
|
||||
}
|
||||
|
||||
export interface ProcessFile {
|
||||
content_type: string;
|
||||
last_modified: string;
|
||||
name: string;
|
||||
process_group_id: string;
|
||||
process_model_id: string;
|
||||
references: ProcessFileReference[];
|
||||
size: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ProcessModel {
|
||||
id: string;
|
||||
process_group_id: string;
|
||||
display_name: string;
|
||||
primary_file_name: string;
|
||||
files: ProcessFile[];
|
||||
}
|
||||
|
||||
// tuple of display value and URL
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
import { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import {
|
||||
generatePath,
|
||||
useNavigate,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Button, Modal, Stack, Content } from '@carbon/react';
|
||||
// import Container from 'react-bootstrap/Container';
|
||||
import Row from 'react-bootstrap/Row';
|
||||
import Col from 'react-bootstrap/Col';
|
||||
|
||||
import Editor from '@monaco-editor/react';
|
||||
|
||||
import MDEditor from '@uiw/react-md-editor';
|
||||
import ReactDiagramEditor from '../components/ReactDiagramEditor';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { makeid } from '../helpers';
|
||||
import { ProcessModel } from '../interfaces';
|
||||
import { ProcessFile, ProcessModel } from '../interfaces';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
|
||||
const [scriptText, setScriptText] = useState<string>('');
|
||||
const [scriptType, setScriptType] = useState<string>('');
|
||||
|
@ -27,6 +33,12 @@ export default function ProcessModelEditDiagram() {
|
|||
const [showScriptEditor, setShowScriptEditor] = useState(false);
|
||||
const handleShowScriptEditor = () => setShowScriptEditor(true);
|
||||
|
||||
const [markdownText, setMarkdownText] = useState<string | undefined>('');
|
||||
const [markdownEventBus, setMarkdownEventBus] = useState<any>(null);
|
||||
const [showMarkdownEditor, setShowMarkdownEditor] = useState(false);
|
||||
|
||||
const handleShowMarkdownEditor = () => setShowMarkdownEditor(true);
|
||||
|
||||
const editorRef = useRef(null);
|
||||
const monacoRef = useRef(null);
|
||||
|
||||
|
@ -70,8 +82,6 @@ export default function ProcessModelEditDiagram() {
|
|||
const [bpmnXmlForDiagramRendering, setBpmnXmlForDiagramRendering] =
|
||||
useState(null);
|
||||
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
|
||||
const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -85,7 +95,7 @@ export default function ProcessModelEditDiagram() {
|
|||
}, [processModelPath]);
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: any) => {
|
||||
const fileResult = (result: any) => {
|
||||
setProcessModelFile(result);
|
||||
setBpmnXmlForDiagramRendering(result.file_contents);
|
||||
};
|
||||
|
@ -93,7 +103,7 @@ export default function ProcessModelEditDiagram() {
|
|||
if (params.file_name) {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}/files/${params.file_name}`,
|
||||
successCallback: processResult,
|
||||
successCallback: fileResult,
|
||||
});
|
||||
}
|
||||
}, [processModelPath, params]);
|
||||
|
@ -246,6 +256,34 @@ export default function ProcessModelEditDiagram() {
|
|||
});
|
||||
};
|
||||
|
||||
const onJsonFilesRequested = (event: any) => {
|
||||
if (processModel) {
|
||||
const jsonFiles = processModel.files.filter((f) => f.type === 'json');
|
||||
const options = jsonFiles.map((f) => {
|
||||
return { label: f.name, value: f.name };
|
||||
});
|
||||
event.eventBus.fire('spiff.json_files.returned', { options });
|
||||
} else {
|
||||
console.log('There is no process Model.');
|
||||
}
|
||||
};
|
||||
|
||||
const onDmnFilesRequested = (event: any) => {
|
||||
if (processModel) {
|
||||
const dmnFiles = processModel.files.filter((f) => f.type === 'dmn');
|
||||
const options: any[] = [];
|
||||
dmnFiles.forEach((file) => {
|
||||
file.references.forEach((ref) => {
|
||||
options.push({ label: ref.name, value: ref.id });
|
||||
});
|
||||
});
|
||||
console.log('Options', options);
|
||||
event.eventBus.fire('spiff.dmn_files.returned', { options });
|
||||
} else {
|
||||
console.log('There is no process model.');
|
||||
}
|
||||
};
|
||||
|
||||
const getScriptUnitTestElements = (element: any) => {
|
||||
const { extensionElements } = element.businessObject;
|
||||
if (extensionElements && extensionElements.values.length > 0) {
|
||||
|
@ -292,7 +330,7 @@ export default function ProcessModelEditDiagram() {
|
|||
};
|
||||
|
||||
const handleScriptEditorClose = () => {
|
||||
scriptEventBus.fire('script.editor.update', {
|
||||
scriptEventBus.fire('spiff.script.update', {
|
||||
scriptType,
|
||||
script: scriptText,
|
||||
element: scriptElement,
|
||||
|
@ -580,6 +618,107 @@ export default function ProcessModelEditDiagram() {
|
|||
</Modal>
|
||||
);
|
||||
};
|
||||
const onLaunchMarkdownEditor = (
|
||||
element: any,
|
||||
markdown: string,
|
||||
eventBus: any
|
||||
) => {
|
||||
setMarkdownText(markdown || '');
|
||||
setMarkdownEventBus(eventBus);
|
||||
handleShowMarkdownEditor();
|
||||
};
|
||||
const handleMarkdownEditorClose = () => {
|
||||
markdownEventBus.fire('spiff.markdown.update', {
|
||||
value: markdownText,
|
||||
});
|
||||
setShowMarkdownEditor(false);
|
||||
};
|
||||
|
||||
const markdownEditor = () => {
|
||||
return (
|
||||
<Modal
|
||||
size="xl"
|
||||
show={showMarkdownEditor}
|
||||
onHide={handleMarkdownEditorClose}
|
||||
>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Edit Markdown Content</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<MDEditor value={markdownText} onChange={setMarkdownText} />
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button variant="secondary" onClick={handleMarkdownEditorClose}>
|
||||
Close
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const findFileNameForReferenceId = (
|
||||
id: string,
|
||||
type: string
|
||||
): ProcessFile | null => {
|
||||
// Given a reference id (like a process_id, or decision_id) finds the file
|
||||
// that contains that reference and returns it.
|
||||
let matchFile = null;
|
||||
if (processModel) {
|
||||
const files = processModel.files.filter((f) => f.type === type);
|
||||
files.some((file) => {
|
||||
if (file.references.some((ref) => ref.id === id)) {
|
||||
matchFile = file;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return matchFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* fixme: Not currently in use. This would only work for bpmn files within the process model. Which is right for DMN and json, but not right here. Need to merge in work on the nested process groups before tackling this.
|
||||
* @param processId
|
||||
*/
|
||||
const onLaunchBpmnEditor = (processId: string) => {
|
||||
const file = findFileNameForReferenceId(processId, 'bpmn');
|
||||
if (file) {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/files/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
}
|
||||
);
|
||||
window.open(path);
|
||||
}
|
||||
};
|
||||
const onLaunchJsonEditor = (fileName: string) => {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/form/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: fileName,
|
||||
}
|
||||
);
|
||||
window.open(path);
|
||||
};
|
||||
const onLaunchDmnEditor = (processId: string) => {
|
||||
const file = findFileNameForReferenceId(processId, 'dmn');
|
||||
if (file) {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/files/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
}
|
||||
);
|
||||
window.open(path);
|
||||
}
|
||||
};
|
||||
|
||||
const isDmn = () => {
|
||||
const fileName = params.file_name || '';
|
||||
|
@ -622,12 +761,18 @@ export default function ProcessModelEditDiagram() {
|
|||
diagramType="bpmn"
|
||||
onLaunchScriptEditor={onLaunchScriptEditor}
|
||||
onServiceTasksRequested={onServiceTasksRequested}
|
||||
onLaunchMarkdownEditor={onLaunchMarkdownEditor}
|
||||
onLaunchBpmnEditor={onLaunchBpmnEditor}
|
||||
onLaunchJsonEditor={onLaunchJsonEditor}
|
||||
onJsonFilesRequested={onJsonFilesRequested}
|
||||
onLaunchDmnEditor={onLaunchDmnEditor}
|
||||
onDmnFilesRequested={onDmnFilesRequested}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// if a file name is not given then this is a new model and the ReactDiagramEditor component will handle it
|
||||
if (bpmnXmlForDiagramRendering || !params.file_name) {
|
||||
if ((bpmnXmlForDiagramRendering || !params.file_name) && processModel) {
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb
|
||||
|
@ -642,6 +787,7 @@ export default function ProcessModelEditDiagram() {
|
|||
{appropriateEditor()}
|
||||
{newFileNameBox()}
|
||||
{scriptEditor()}
|
||||
{markdownEditor()}
|
||||
|
||||
<div id="diagram-container" />
|
||||
</>
|
||||
|
|
Loading…
Reference in New Issue