Merge branch 'feature/better_unit_tests' into feature/bpmn_user_permissions

This commit is contained in:
Dan 2022-12-15 15:01:59 -05:00
commit 6f8425a14b
10 changed files with 266 additions and 91 deletions

View File

@ -11,11 +11,12 @@ set -o errtrace -o errexit -o nounset -o pipefail
bpmn_models_absolute_dir="$1" bpmn_models_absolute_dir="$1"
git_commit_message="$2" git_commit_message="$2"
git_commit_username="$3" git_branch="$3"
git_commit_email="$4" git_commit_username="$4"
git_commit_email="$5"
if [[ -z "${2:-}" ]]; then if [[ -z "${5:-}" ]]; then
>&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message]" >&2 echo "usage: $(basename "$0") [bpmn_models_absolute_dir] [git_commit_message] [git_branch] [git_commit_username] [git_commit_email]"
exit 1 exit 1
fi fi
@ -26,11 +27,8 @@ git add .
if [ -z "$(git status --porcelain)" ]; then if [ -z "$(git status --porcelain)" ]; then
echo "No changes to commit" echo "No changes to commit"
else else
if [[ -n "$git_commit_username" ]]; then
git config --local user.name "$git_commit_username" git config --local user.name "$git_commit_username"
fi
if [[ -n "$git_commit_email" ]]; then
git config --local user.email "$git_commit_email" git config --local user.email "$git_commit_email"
fi
git commit -m "$git_commit_message" git commit -m "$git_commit_message"
git push --set-upstream origin "$git_branch"
fi fi

View File

@ -18,7 +18,19 @@ set -o errtrace -o errexit -o nounset -o pipefail
if ! docker network inspect spiffworkflow > /dev/null 2>&1; then if ! docker network inspect spiffworkflow > /dev/null 2>&1; then
docker network create spiffworkflow docker network create spiffworkflow
fi fi
docker rm keycloak 2>/dev/null || echo 'no keycloak container found, safe to start new container'
# https://stackoverflow.com/a/60579344/6090676
container_name="keycloak"
if [[ -n "$(docker ps -qa -f name=$container_name)" ]]; then
echo ":: Found container - $container_name"
if [[ -n "$(docker ps -q -f name=$container_name)" ]]; then
echo ":: Stopping running container - $container_name"
docker stop $container_name
fi
echo ":: Removing stopped container - $container_name"
docker rm $container_name
fi
docker run \ docker run \
-p 7002:8080 \ -p 7002:8080 \
-d \ -d \

View File

@ -17,5 +17,3 @@ GIT_CLONE_URL_FOR_PUBLISHING = environ.get(
) )
GIT_USERNAME = "sartography-automated-committer" GIT_USERNAME = "sartography-automated-committer"
GIT_USER_EMAIL = f"{GIT_USERNAME}@users.noreply.github.com" GIT_USER_EMAIL = f"{GIT_USERNAME}@users.noreply.github.com"
GIT_BRANCH_TO_PUBLISH_TO = "main"
GIT_BRANCH = "main"

View File

@ -15,6 +15,7 @@ SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME = environ.get(
SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get( SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get(
"SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug" "SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug"
) )
GIT_COMMIT_ON_SAVE = False
# NOTE: set this here since nox shoves tests and src code to # NOTE: set this here since nox shoves tests and src code to
# different places and this allows us to know exactly where we are at the start # different places and this allows us to know exactly where we are at the start

View File

@ -1,5 +1,6 @@
"""APIs for dealing with process groups, process models, and process instances.""" """APIs for dealing with process groups, process models, and process instances."""
import json import json
import os
import random import random
import re import re
import string import string
@ -75,6 +76,7 @@ from spiffworkflow_backend.models.user_group_assignment import UserGroupAssignme
from spiffworkflow_backend.routes.user import verify_token from spiffworkflow_backend.routes.user import verify_token
from spiffworkflow_backend.services.authorization_service import AuthorizationService from spiffworkflow_backend.services.authorization_service import AuthorizationService
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
from spiffworkflow_backend.services.file_system_service import FileSystemService
from spiffworkflow_backend.services.git_service import GitService from spiffworkflow_backend.services.git_service import GitService
from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.message_service import MessageService
from spiffworkflow_backend.services.process_instance_processor import ( from spiffworkflow_backend.services.process_instance_processor import (
@ -168,6 +170,9 @@ def process_group_add(body: dict) -> flask.wrappers.Response:
"""Add_process_group.""" """Add_process_group."""
process_group = ProcessGroup(**body) process_group = ProcessGroup(**body)
ProcessModelService.add_process_group(process_group) ProcessModelService.add_process_group(process_group)
commit_and_push_to_git(
f"User: {g.user.username} added process group {process_group.id}"
)
return make_response(jsonify(process_group), 201) return make_response(jsonify(process_group), 201)
@ -175,6 +180,9 @@ def process_group_delete(modified_process_group_id: str) -> flask.wrappers.Respo
"""Process_group_delete.""" """Process_group_delete."""
process_group_id = un_modify_modified_process_model_id(modified_process_group_id) process_group_id = un_modify_modified_process_model_id(modified_process_group_id)
ProcessModelService().process_group_delete(process_group_id) ProcessModelService().process_group_delete(process_group_id)
commit_and_push_to_git(
f"User: {g.user.username} deleted process group {process_group_id}"
)
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
@ -192,6 +200,9 @@ def process_group_update(
process_group_id = un_modify_modified_process_model_id(modified_process_group_id) process_group_id = un_modify_modified_process_model_id(modified_process_group_id)
process_group = ProcessGroup(id=process_group_id, **body_filtered) process_group = ProcessGroup(id=process_group_id, **body_filtered)
ProcessModelService.update_process_group(process_group) ProcessModelService.update_process_group(process_group)
commit_and_push_to_git(
f"User: {g.user.username} updated process group {process_group_id}"
)
return make_response(jsonify(process_group), 200) return make_response(jsonify(process_group), 200)
@ -256,7 +267,10 @@ def process_group_move(
new_process_group = ProcessModelService().process_group_move( new_process_group = ProcessModelService().process_group_move(
original_process_group_id, new_location original_process_group_id, new_location
) )
return make_response(jsonify(new_process_group), 201) commit_and_push_to_git(
f"User: {g.user.username} moved process group {original_process_group_id} to {new_process_group.id}"
)
return make_response(jsonify(new_process_group), 200)
def process_model_create( def process_model_create(
@ -304,6 +318,9 @@ def process_model_create(
) )
ProcessModelService.add_process_model(process_model_info) ProcessModelService.add_process_model(process_model_info)
commit_and_push_to_git(
f"User: {g.user.username} created process model {process_model_info.id}"
)
return Response( return Response(
json.dumps(ProcessModelInfoSchema().dump(process_model_info)), json.dumps(ProcessModelInfoSchema().dump(process_model_info)),
status=201, status=201,
@ -317,6 +334,9 @@ def process_model_delete(
"""Process_model_delete.""" """Process_model_delete."""
process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model_identifier = modified_process_model_identifier.replace(":", "/")
ProcessModelService().process_model_delete(process_model_identifier) ProcessModelService().process_model_delete(process_model_identifier)
commit_and_push_to_git(
f"User: {g.user.username} deleted process model {process_model_identifier}"
)
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
@ -340,6 +360,9 @@ def process_model_update(
process_model = get_process_model(process_model_identifier) process_model = get_process_model(process_model_identifier)
ProcessModelService.update_process_model(process_model, body_filtered) ProcessModelService.update_process_model(process_model, body_filtered)
commit_and_push_to_git(
f"User: {g.user.username} updated process model {process_model_identifier}"
)
return ProcessModelInfoSchema().dump(process_model) return ProcessModelInfoSchema().dump(process_model)
@ -371,7 +394,10 @@ def process_model_move(
new_process_model = ProcessModelService().process_model_move( new_process_model = ProcessModelService().process_model_move(
original_process_model_id, new_location original_process_model_id, new_location
) )
return make_response(jsonify(new_process_model), 201) commit_and_push_to_git(
f"User: {g.user.username} moved process model {original_process_model_id} to {new_process_model.id}"
)
return make_response(jsonify(new_process_model), 200)
def process_model_publish( def process_model_publish(
@ -467,14 +493,9 @@ def process_model_file_update(
) )
SpecFileService.update_file(process_model, file_name, request_file_contents) SpecFileService.update_file(process_model, file_name, request_file_contents)
commit_and_push_to_git(
if current_app.config["GIT_COMMIT_ON_SAVE"]: f"User: {g.user.username} clicked save for {process_model_identifier}/{file_name}"
git_output = GitService.commit(
message=f"User: {g.user.username} clicked save for {process_model_identifier}/{file_name}"
) )
current_app.logger.info(f"git output: {git_output}")
else:
current_app.logger.info("Git commit on save is disabled")
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
@ -496,6 +517,9 @@ def process_model_file_delete(
) )
) from exception ) from exception
commit_and_push_to_git(
f"User: {g.user.username} deleted process model file {process_model_identifier}/{file_name}"
)
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
@ -517,6 +541,9 @@ def add_file(modified_process_model_identifier: str) -> flask.wrappers.Response:
file_contents = SpecFileService.get_data(process_model, file.name) file_contents = SpecFileService.get_data(process_model, file.name)
file.file_contents = file_contents file.file_contents = file_contents
file.process_model_id = process_model.id file.process_model_id = process_model.id
commit_and_push_to_git(
f"User: {g.user.username} added process model file {process_model_identifier}/{file.name}"
)
return Response( return Response(
json.dumps(FileSchema().dump(file)), status=201, mimetype="application/json" json.dumps(FileSchema().dump(file)), status=201, mimetype="application/json"
) )
@ -1484,7 +1511,25 @@ def task_show(process_instance_id: int, task_id: str) -> flask.wrappers.Response
task.data = spiff_task.data task.data = spiff_task.data
task.process_model_display_name = process_model.display_name task.process_model_display_name = process_model.display_name
task.process_model_identifier = process_model.id task.process_model_identifier = process_model.id
process_model_with_form = process_model process_model_with_form = process_model
refs = SpecFileService.get_references_for_process(process_model_with_form)
all_processes = [i.identifier for i in refs]
if task.process_identifier not in all_processes:
bpmn_file_full_path = (
ProcessInstanceProcessor.bpmn_file_full_path_from_bpmn_process_identifier(
task.process_identifier
)
)
relative_path = os.path.relpath(
bpmn_file_full_path, start=FileSystemService.root_path()
)
process_model_relative_path = os.path.dirname(relative_path)
process_model_with_form = (
ProcessModelService.get_process_model_from_relative_path(
process_model_relative_path
)
)
if task.type == "User Task": if task.type == "User Task":
if not form_schema_file_name: if not form_schema_file_name:
@ -1657,7 +1702,7 @@ def script_unit_test_create(
extension_elements = None extension_elements = None
extension_elements_array = script_task_element.xpath( extension_elements_array = script_task_element.xpath(
"//bpmn:extensionElements", ".//bpmn:extensionElements",
namespaces={"bpmn": "http://www.omg.org/spec/BPMN/20100524/MODEL"}, namespaces={"bpmn": "http://www.omg.org/spec/BPMN/20100524/MODEL"},
) )
if len(extension_elements_array) == 0: if len(extension_elements_array) == 0:
@ -2038,3 +2083,12 @@ def update_task_data(
status=200, status=200,
mimetype="application/json", mimetype="application/json",
) )
def commit_and_push_to_git(message: str) -> None:
"""Commit_and_push_to_git."""
if current_app.config["GIT_COMMIT_ON_SAVE"]:
git_output = GitService.commit(message=message)
current_app.logger.info(f"git output: {git_output}")
else:
current_app.logger.info("Git commit on save is disabled")

View File

@ -68,8 +68,17 @@ class GitService:
return cls.run_shell_command_to_get_stdout(shell_command) return cls.run_shell_command_to_get_stdout(shell_command)
@classmethod @classmethod
def commit(cls, message: str, repo_path: Optional[str] = None) -> str: def commit(
cls,
message: str,
repo_path: Optional[str] = None,
branch_name: Optional[str] = None,
) -> str:
"""Commit.""" """Commit."""
cls.check_for_basic_configs()
branch_name_to_use = branch_name
if branch_name_to_use is None:
branch_name_to_use = current_app.config["GIT_BRANCH"]
repo_path_to_use = repo_path repo_path_to_use = repo_path
if repo_path is None: if repo_path is None:
repo_path_to_use = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"] repo_path_to_use = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"]
@ -88,14 +97,25 @@ class GitService:
shell_command_path, shell_command_path,
repo_path_to_use, repo_path_to_use,
message, message,
branch_name_to_use,
git_username, git_username,
git_email, git_email,
] ]
return cls.run_shell_command_to_get_stdout(shell_command) return cls.run_shell_command_to_get_stdout(shell_command)
@classmethod @classmethod
def check_for_configs(cls) -> None: def check_for_basic_configs(cls) -> None:
"""Check_for_basic_configs."""
if current_app.config["GIT_BRANCH"] is None:
raise MissingGitConfigsError(
"Missing config for GIT_BRANCH. "
"This is required for publishing process models"
)
@classmethod
def check_for_publish_configs(cls) -> None:
"""Check_for_configs.""" """Check_for_configs."""
cls.check_for_basic_configs()
if current_app.config["GIT_BRANCH_TO_PUBLISH_TO"] is None: if current_app.config["GIT_BRANCH_TO_PUBLISH_TO"] is None:
raise MissingGitConfigsError( raise MissingGitConfigsError(
"Missing config for GIT_BRANCH_TO_PUBLISH_TO. " "Missing config for GIT_BRANCH_TO_PUBLISH_TO. "
@ -148,7 +168,7 @@ class GitService:
@classmethod @classmethod
def handle_web_hook(cls, webhook: dict) -> bool: def handle_web_hook(cls, webhook: dict) -> bool:
"""Handle_web_hook.""" """Handle_web_hook."""
cls.check_for_configs() cls.check_for_publish_configs()
if "repository" not in webhook or "clone_url" not in webhook["repository"]: if "repository" not in webhook or "clone_url" not in webhook["repository"]:
raise InvalidGitWebhookBodyError( raise InvalidGitWebhookBodyError(
@ -184,7 +204,7 @@ class GitService:
@classmethod @classmethod
def publish(cls, process_model_id: str, branch_to_update: str) -> str: def publish(cls, process_model_id: str, branch_to_update: str) -> str:
"""Publish.""" """Publish."""
cls.check_for_configs() cls.check_for_publish_configs()
source_process_model_root = FileSystemService.root_path() source_process_model_root = FileSystemService.root_path()
source_process_model_path = os.path.join( source_process_model_path = os.path.join(
source_process_model_root, process_model_id source_process_model_root, process_model_id
@ -233,10 +253,7 @@ class GitService:
f"Request to publish changes to {process_model_id}, " f"Request to publish changes to {process_model_id}, "
f"from {g.user.username} on {current_app.config['ENV_IDENTIFIER']}" f"from {g.user.username} on {current_app.config['ENV_IDENTIFIER']}"
) )
cls.commit(commit_message, destination_process_root) cls.commit(commit_message, destination_process_root, branch_to_pull_request)
cls.run_shell_command(
["git", "push", "--set-upstream", "origin", branch_to_pull_request]
)
# build url for github page to open PR # build url for github page to open PR
git_remote = cls.run_shell_command_to_get_stdout( git_remote = cls.run_shell_command_to_get_stdout(

View File

@ -843,8 +843,8 @@ export default function ProcessInstanceListTable({
return null; return null;
}} }}
shouldFilterItem={shouldFilterReportColumn} shouldFilterItem={shouldFilterReportColumn}
placeholder="Choose a report column" placeholder="Choose a column to show"
titleText="Report Column" titleText="Column"
/> />
); );
} }
@ -893,7 +893,7 @@ export default function ProcessInstanceListTable({
kind="ghost" kind="ghost"
size="sm" size="sm"
className={`button-tag-icon ${tagTypeClass}`} className={`button-tag-icon ${tagTypeClass}`}
title={`Edit ${reportColumnForEditing.accessor}`} title={`Edit ${reportColumnForEditing.accessor} column`}
onClick={() => { onClick={() => {
setReportColumnToOperateOn(reportColumnForEditing); setReportColumnToOperateOn(reportColumnForEditing);
setShowReportColumnForm(true); setShowReportColumnForm(true);
@ -921,7 +921,7 @@ export default function ProcessInstanceListTable({
<Button <Button
data-qa="add-column-button" data-qa="add-column-button"
renderIcon={AddAlt} renderIcon={AddAlt}
iconDescription="Filter Options" iconDescription="Column options"
className="with-tiny-top-margin" className="with-tiny-top-margin"
kind="ghost" kind="ghost"
hasIconOnly hasIconOnly

View File

@ -52,6 +52,8 @@ import TouchModule from 'diagram-js/lib/navigation/touch';
// @ts-expect-error TS(7016) FIXME // @ts-expect-error TS(7016) FIXME
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
import { useNavigate } from 'react-router-dom';
import { Can } from '@casl/react'; import { Can } from '@casl/react';
import HttpService from '../services/HttpService'; import HttpService from '../services/HttpService';
@ -119,6 +121,7 @@ export default function ReactDiagramEditor({
[targetUris.processModelFileShowPath]: ['POST', 'GET', 'PUT', 'DELETE'], [targetUris.processModelFileShowPath]: ['POST', 'GET', 'PUT', 'DELETE'],
}; };
const { ability } = usePermissionFetcher(permissionRequestData); const { ability } = usePermissionFetcher(permissionRequestData);
const navigate = useNavigate();
useEffect(() => { useEffect(() => {
if (diagramModelerState) { if (diagramModelerState) {
@ -542,6 +545,8 @@ export default function ReactDiagramEditor({
}); });
}; };
const canViewXml = fileName !== undefined;
const userActionOptions = () => { const userActionOptions = () => {
if (diagramType !== 'readonly') { if (diagramType !== 'readonly') {
return ( return (
@ -580,6 +585,23 @@ export default function ReactDiagramEditor({
> >
<Button onClick={downloadXmlFile}>Download</Button> <Button onClick={downloadXmlFile}>Download</Button>
</Can> </Can>
<Can
I="GET"
a={targetUris.processModelFileShowPath}
ability={ability}
>
{canViewXml && (
<Button
onClick={() => {
navigate(
`/admin/process-models/${processModelId}/form/${fileName}`
);
}}
>
View XML
</Button>
)}
</Can>
</> </>
); );
} }

View File

@ -6,11 +6,11 @@ import {
useSearchParams, useSearchParams,
} from 'react-router-dom'; } from 'react-router-dom';
// @ts-ignore // @ts-ignore
import { Button, Modal, Stack, Content } from '@carbon/react'; import { Button, Modal, Content, Tabs, TabList, Tab, TabPanels, TabPanel } from '@carbon/react';
import Row from 'react-bootstrap/Row'; import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col'; import Col from 'react-bootstrap/Col';
import Editor from '@monaco-editor/react'; import Editor, { DiffEditor } from '@monaco-editor/react';
import MDEditor from '@uiw/react-md-editor'; import MDEditor from '@uiw/react-md-editor';
import ReactDiagramEditor from '../components/ReactDiagramEditor'; import ReactDiagramEditor from '../components/ReactDiagramEditor';
@ -397,6 +397,13 @@ export default function ProcessModelEditDiagram() {
}; };
}; };
const jsonEditorOptions = () => {
return Object.assign(generalEditorOptions(), {
minimap: { enabled: false },
folding: true
});
}
const setPreviousScriptUnitTest = () => { const setPreviousScriptUnitTest = () => {
resetUnitTextResult(); resetUnitTextResult();
const newScriptIndex = currentScriptUnitTestIndex - 1; const newScriptIndex = currentScriptUnitTestIndex - 1;
@ -491,11 +498,32 @@ export default function ProcessModelEditDiagram() {
} }
let errorContextElement = null; let errorContextElement = null;
if (scriptUnitTestResult.context) { if (scriptUnitTestResult.context) {
errorStringElement = (
<span>Unexpected result. Please see the comparison below.</span>
);
let outputJson = '{}';
if (currentScriptUnitTest) {
outputJson = JSON.stringify(
JSON.parse(currentScriptUnitTest.expectedOutputJson.value),
null,
' '
);
}
const contextJson = JSON.stringify(
scriptUnitTestResult.context,
null,
' '
);
errorContextElement = ( errorContextElement = (
<span> <DiffEditor
Received unexpected output:{' '} height={200}
{JSON.stringify(scriptUnitTestResult.context)} width="auto"
</span> originalLanguage="json"
modifiedLanguage="json"
options={Object.assign(jsonEditorOptions(), {})}
original={outputJson}
modified={contextJson}
/>
); );
} }
return ( return (
@ -539,19 +567,29 @@ export default function ProcessModelEditDiagram() {
</Col> </Col>
); );
} }
const inputJson = JSON.stringify(
JSON.parse(currentScriptUnitTest.inputJson.value),
null,
' '
);
const outputJson = JSON.stringify(
JSON.parse(currentScriptUnitTest.expectedOutputJson.value),
null,
' '
);
return ( return (
<main> <main>
<Content> <Content>
<Row> <Row>
<Col xs={8}> <Col xs={8}>
<Button variant="link" disabled style={{ fontSize: '1.5em' }}> <Button variant="link" disabled>
Unit Test: {currentScriptUnitTest.id} Unit Test: {currentScriptUnitTest.id}
</Button> </Button>
</Col> </Col>
<Col xs={1}> <Col xs={1}>
<Button <Button
data-qa="unit-test-previous-button" data-qa="unit-test-previous-button"
style={{ fontSize: '1.5em' }}
onClick={setPreviousScriptUnitTest} onClick={setPreviousScriptUnitTest}
variant="link" variant="link"
disabled={previousButtonDisable} disabled={previousButtonDisable}
@ -582,61 +620,45 @@ export default function ProcessModelEditDiagram() {
</Col> </Col>
<Col xs={1}>{scriptUnitTestResultBoolElement}</Col> <Col xs={1}>{scriptUnitTestResultBoolElement}</Col>
</Row> </Row>
</Content> <Row>
<Stack orientation="horizontal" gap={3}> <Col>{unitTestFailureElement()}</Col>
{unitTestFailureElement()} </Row>
</Stack> <Row>
<Stack orientation="horizontal" gap={3}> <Col>
<Stack>
<div>Input Json:</div> <div>Input Json:</div>
<div> <div>
<Editor <Editor
height={200} height={500}
width="auto"
defaultLanguage="json" defaultLanguage="json"
options={Object.assign(generalEditorOptions(), { options={Object.assign(jsonEditorOptions(), {})}
minimap: { enabled: false }, value={inputJson}
})}
value={currentScriptUnitTest.inputJson.value}
onChange={handleEditorScriptTestUnitInputChange} onChange={handleEditorScriptTestUnitInputChange}
/> />
</div> </div>
</Stack> </Col>
<Stack> <Col>
<div>Expected Output Json:</div> <div>Expected Output Json:</div>
<div> <div>
<Editor <Editor
height={200} height={500}
width="auto"
defaultLanguage="json" defaultLanguage="json"
options={Object.assign(generalEditorOptions(), { options={Object.assign(jsonEditorOptions(), {})}
minimap: { enabled: false }, value={outputJson}
})}
value={currentScriptUnitTest.expectedOutputJson.value}
onChange={handleEditorScriptTestUnitOutputChange} onChange={handleEditorScriptTestUnitOutputChange}
/> />
</div> </div>
</Stack> </Col>
</Stack> </Row>
</Content>
</main> </main>
); );
} }
return null; return null;
}; };
const scriptEditor = () => { const scriptEditor = () => {
let scriptName = '';
if (scriptElement) {
scriptName = (scriptElement as any).di.bpmnElement.name;
}
return ( return (
<Modal
open={showScriptEditor}
modalHeading={`Editing Script: ${scriptName}`}
primaryButtonText="Close"
onRequestSubmit={handleScriptEditorClose}
size="lg"
onRequestClose={handleScriptEditorClose}
>
<Editor <Editor
height={500} height={500}
width="auto" width="auto"
@ -646,7 +668,32 @@ export default function ProcessModelEditDiagram() {
onChange={handleEditorScriptChange} onChange={handleEditorScriptChange}
onMount={handleEditorDidMount} onMount={handleEditorDidMount}
/> />
{scriptUnitTestEditorElement()} );
};
const scriptEditorAndTests = () => {
let scriptName = '';
if (scriptElement) {
scriptName = (scriptElement as any).di.bpmnElement.name;
}
return (
<Modal
open={showScriptEditor}
modalHeading={`Editing Script: ${scriptName}`}
primaryButtonText="Close"
onRequestSubmit={handleScriptEditorClose}
size="lg"
onRequestClose={handleScriptEditorClose}
>
<Tabs>
<TabList aria-label="List of tabs" activation="manual">
<Tab>Script Editor</Tab>
<Tab>Unit Tests</Tab>
</TabList>
<TabPanels>
<TabPanel>{scriptEditor()}</TabPanel>
<TabPanel>{scriptUnitTestEditorElement()}</TabPanel>
</TabPanels>
</Tabs>
</Modal> </Modal>
); );
}; };
@ -858,7 +905,7 @@ export default function ProcessModelEditDiagram() {
</h1> </h1>
{appropriateEditor()} {appropriateEditor()}
{newFileNameBox()} {newFileNameBox()}
{scriptEditor()} {scriptEditorAndTests()}
{markdownEditor()} {markdownEditor()}
{processModelSelector()} {processModelSelector()}
<div id="diagram-container" /> <div id="diagram-container" />

View File

@ -36,7 +36,20 @@ export default function ReactFormEditor() {
return searchParams.get('file_ext') ?? 'json'; return searchParams.get('file_ext') ?? 'json';
})(); })();
const editorDefaultLanguage = fileExtension === 'md' ? 'markdown' : 'json'; const hasDiagram = fileExtension === 'bpmn' || fileExtension === 'dmn';
const editorDefaultLanguage = (() => {
if (fileExtension === 'json') {
return 'json';
}
if (hasDiagram) {
return 'xml';
}
if (fileExtension === 'md') {
return 'markdown';
}
return 'text';
})();
const modifiedProcessModelId = modifyProcessIdentifierForPathParam( const modifiedProcessModelId = modifyProcessIdentifierForPathParam(
`${params.process_model_id}` `${params.process_model_id}`
@ -193,6 +206,19 @@ export default function ReactFormEditor() {
buttonLabel="Delete" buttonLabel="Delete"
/> />
) : null} ) : null}
{hasDiagram ? (
<Button
onClick={() =>
navigate(
`/admin/process-models/${modifiedProcessModelId}/files/${params.file_name}`
)
}
variant="danger"
data-qa="view-diagram-button"
>
View Diagram
</Button>
) : null}
<Editor <Editor
height={600} height={600}
width="auto" width="auto"