diff --git a/spiffworkflow-backend/bin/recreate_db b/spiffworkflow-backend/bin/recreate_db
index 5af0209c..6a9d286a 100755
--- a/spiffworkflow-backend/bin/recreate_db
+++ b/spiffworkflow-backend/bin/recreate_db
@@ -28,8 +28,8 @@ if [[ -n "${SPIFFWORKFLOW_BACKEND_DATABASE_URI:-}" ]]; then
database_host=$(grep -oP "^[^:]+://.*@\K(.+?)[:/]" <<<"$SPIFFWORKFLOW_BACKEND_DATABASE_URI" | sed -E 's/[:\/]$//')
fi
-# this will fix branching conflicts
-# poetry run flask db merge heads -m "merging two heads"
+# uncomment this line to fix branching conflicts
+# poetry run flask db merge heads -m "merging heads"
tasks=""
if [[ "${1:-}" == "clean" ]]; then
diff --git a/spiffworkflow-backend/migrations/versions/844cee572018_.py b/spiffworkflow-backend/migrations/versions/844cee572018_.py
new file mode 100644
index 00000000..498d4202
--- /dev/null
+++ b/spiffworkflow-backend/migrations/versions/844cee572018_.py
@@ -0,0 +1,44 @@
+"""empty message
+
+Revision ID: 844cee572018
+Revises: 57df21dc569d
+Create Date: 2023-09-07 14:18:12.357989
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '844cee572018'
+down_revision = '57df21dc569d'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('user_property',
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('user_id', sa.Integer(), nullable=False),
+ sa.Column('key', sa.String(length=255), nullable=False),
+ sa.Column('value', sa.String(length=255), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('user_id', 'key', name='user_id_key_uniq')
+ )
+ with op.batch_alter_table('user_property', schema=None) as batch_op:
+ batch_op.create_index(batch_op.f('ix_user_property_key'), ['key'], unique=False)
+ batch_op.create_index(batch_op.f('ix_user_property_user_id'), ['user_id'], unique=False)
+
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('user_property', schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f('ix_user_property_user_id'))
+ batch_op.drop_index(batch_op.f('ix_user_property_key'))
+
+ op.drop_table('user_property')
+ # ### end Alembic commands ###
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
index fbf3bbcb..01fb9548 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/load_database_models.py
@@ -88,5 +88,8 @@ from spiffworkflow_backend.models.task_draft_data import (
from spiffworkflow_backend.models.configuration import (
ConfigurationModel,
) # noqa: F401
+from spiffworkflow_backend.models.user_property import (
+ UserPropertyModel,
+) # noqa: F401
add_listeners()
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/user_property.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/user_property.py
new file mode 100644
index 00000000..74313f4e
--- /dev/null
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/user_property.py
@@ -0,0 +1,20 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+from sqlalchemy import ForeignKey
+
+from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
+from spiffworkflow_backend.models.db import db
+from spiffworkflow_backend.models.user import UserModel
+
+
+@dataclass
+class UserPropertyModel(SpiffworkflowBaseDBModel):
+ __tablename__ = "user_property"
+ __table_args__ = (db.UniqueConstraint("user_id", "key", name="user_id_key_uniq"),)
+
+ id: int = db.Column(db.Integer, primary_key=True)
+ user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False, index=True) # type: ignore
+ key: str = db.Column(db.String(255), nullable=False, index=True)
+ value: str | None = db.Column(db.String(255))
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/extensions_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/extensions_controller.py
index 076dad07..749d59a9 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/extensions_controller.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/extensions_controller.py
@@ -21,6 +21,7 @@ from spiffworkflow_backend.services.process_instance_processor import CustomBpmn
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
from spiffworkflow_backend.services.process_instance_queue_service import ProcessInstanceIsAlreadyLockedError
from spiffworkflow_backend.services.process_instance_queue_service import ProcessInstanceIsNotEnqueuedError
+from spiffworkflow_backend.services.process_instance_service import ProcessInstanceService
from spiffworkflow_backend.services.process_model_service import ProcessModelService
from spiffworkflow_backend.services.spec_file_service import SpecFileService
from spiffworkflow_backend.services.workflow_execution_service import WorkflowExecutionServiceError
@@ -121,17 +122,25 @@ def _run_extension(
status_code=400,
)
- ui_schema_page_definition = None
- if body and "ui_schema_page_definition" in body:
- ui_schema_page_definition = body["ui_schema_page_definition"]
+ ui_schema_action = None
+ persistence_level = "none"
+ if body and "ui_schema_action" in body:
+ ui_schema_action = body["ui_schema_action"]
+ persistence_level = ui_schema_action.get("persistence_level", "none")
- process_instance = ProcessInstanceModel(
- status=ProcessInstanceStatus.not_started.value,
- process_initiator_id=g.user.id,
- process_model_identifier=process_model.id,
- process_model_display_name=process_model.display_name,
- persistence_level="none",
- )
+ process_instance = None
+ if persistence_level == "none":
+ process_instance = ProcessInstanceModel(
+ status=ProcessInstanceStatus.not_started.value,
+ process_initiator_id=g.user.id,
+ process_model_identifier=process_model.id,
+ process_model_display_name=process_model.display_name,
+ persistence_level=persistence_level,
+ )
+ else:
+ process_instance = ProcessInstanceService.create_process_instance_from_process_model_identifier(
+ process_model_identifier, g.user
+ )
processor = None
try:
@@ -170,10 +179,10 @@ def _run_extension(
task_data = processor.get_data()
result: dict[str, Any] = {"task_data": task_data}
- if ui_schema_page_definition:
- if "results_markdown_filename" in ui_schema_page_definition:
+ if ui_schema_action:
+ if "results_markdown_filename" in ui_schema_action:
file_contents = SpecFileService.get_data(
- process_model, ui_schema_page_definition["results_markdown_filename"]
+ process_model, ui_schema_action["results_markdown_filename"]
).decode("utf-8")
form_contents = JinjaService.render_jinja_template(file_contents, task_data=task_data)
result["rendered_results_markdown"] = form_contents
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user_properties.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user_properties.py
new file mode 100644
index 00000000..46266703
--- /dev/null
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/get_user_properties.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+from flask import g
+from spiffworkflow_backend.models.script_attributes_context import ScriptAttributesContext
+from spiffworkflow_backend.models.user_property import UserPropertyModel
+from spiffworkflow_backend.scripts.script import Script
+
+
+class GetUserProperties(Script):
+ @staticmethod
+ def requires_privileged_permissions() -> bool:
+ """We have deemed this function safe to run without elevated permissions."""
+ return False
+
+ def get_description(self) -> str:
+ return """Gets the user properties for current user."""
+
+ def run(self, script_attributes_context: ScriptAttributesContext, *_args: Any, **kwargs: Any) -> Any:
+ user_properties = UserPropertyModel.query.filter_by(user_id=g.user.id).all()
+ dict_to_return = {}
+ for up in user_properties:
+ dict_to_return[up.key] = up.value
+ return dict_to_return
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py
index f33b8e4e..777f3ef0 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/script.py
@@ -31,6 +31,10 @@ class ProcessModelIdentifierMissingError(Exception):
pass
+class InvalidArgsGivenToScriptError(Exception):
+ pass
+
+
class Script:
"""Provides an abstract class that defines how scripts should work, this must be extended in all Script Tasks."""
diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/scripts/set_user_properties.py b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/set_user_properties.py
new file mode 100644
index 00000000..b6ed4bba
--- /dev/null
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/scripts/set_user_properties.py
@@ -0,0 +1,36 @@
+from typing import Any
+
+from flask import g
+from spiffworkflow_backend.models.db import db
+from spiffworkflow_backend.models.script_attributes_context import ScriptAttributesContext
+from spiffworkflow_backend.models.user_property import UserPropertyModel
+from spiffworkflow_backend.scripts.script import InvalidArgsGivenToScriptError
+from spiffworkflow_backend.scripts.script import Script
+
+
+class SetUserProperties(Script):
+ @staticmethod
+ def requires_privileged_permissions() -> bool:
+ """We have deemed this function safe to run without elevated permissions."""
+ return False
+
+ def get_description(self) -> str:
+ return """Sets given user properties on current user."""
+
+ def run(self, script_attributes_context: ScriptAttributesContext, *args: Any, **kwargs: Any) -> Any:
+ properties = args[0]
+ if not isinstance(properties, dict):
+ raise InvalidArgsGivenToScriptError(
+ f"Args to set_user_properties must be a dict. '{properties}' is invalid."
+ )
+ # consider using engine-specific insert or update metaphor in future: https://stackoverflow.com/a/68431412/6090676
+ for property_key, property_value in properties.items():
+ user_property = UserPropertyModel.query.filter_by(user_id=g.user.id, key=property_key).first()
+ if user_property is None:
+ user_property = UserPropertyModel(
+ user_id=g.user.id,
+ key=property_key,
+ )
+ user_property.value = property_value
+ db.session.add(user_property)
+ db.session.commit()
diff --git a/spiffworkflow-frontend/src/App.tsx b/spiffworkflow-frontend/src/App.tsx
index 4fee5ec5..92f140fe 100644
--- a/spiffworkflow-frontend/src/App.tsx
+++ b/spiffworkflow-frontend/src/App.tsx
@@ -48,11 +48,7 @@ export default function App() {
} />
} />
}
- />
- }
/>
diff --git a/spiffworkflow-frontend/src/components/NavigationBar.tsx b/spiffworkflow-frontend/src/components/NavigationBar.tsx
index 23d7a3e8..4fc02da9 100644
--- a/spiffworkflow-frontend/src/components/NavigationBar.tsx
+++ b/spiffworkflow-frontend/src/components/NavigationBar.tsx
@@ -24,13 +24,11 @@ import { Can } from '@casl/react';
import logo from '../logo.svg';
import UserService from '../services/UserService';
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
+import { PermissionsToCheck, ProcessModel, ProcessFile } from '../interfaces';
import {
- PermissionsToCheck,
- ProcessModel,
- ProcessFile,
ExtensionUiSchema,
- UiSchemaNavItem,
-} from '../interfaces';
+ UiSchemaUxElement,
+} from '../extension_ui_schema_interfaces';
import { usePermissionFetcher } from '../hooks/PermissionService';
import HttpService, { UnauthenticatedError } from '../services/HttpService';
import { DOCUMENTATION_URL, SPIFF_ENVIRONMENT } from '../config';
@@ -49,7 +47,7 @@ export default function NavigationBar() {
const location = useLocation();
const [activeKey, setActiveKey] = useState('');
const [extensionNavigationItems, setExtensionNavigationItems] = useState<
- UiSchemaNavItem[] | null
+ UiSchemaUxElement[] | null
>(null);
const { targetUris } = useUriListForPermissions();
@@ -109,7 +107,7 @@ export default function NavigationBar() {
}
const processExtensionResult = (processModels: ProcessModel[]) => {
- const eni: UiSchemaNavItem[] = processModels
+ const eni: UiSchemaUxElement[] = processModels
.map((processModel: ProcessModel) => {
const extensionUiSchemaFile = processModel.files.find(
(file: ProcessFile) => file.name === 'extension_uischema.json'
@@ -119,8 +117,8 @@ export default function NavigationBar() {
const extensionUiSchema: ExtensionUiSchema = JSON.parse(
extensionUiSchemaFile.file_contents
);
- if (extensionUiSchema.navigation_items) {
- return extensionUiSchema.navigation_items;
+ if (extensionUiSchema.ux_elements) {
+ return extensionUiSchema.ux_elements;
}
} catch (jsonParseError: any) {
console.error(
@@ -128,7 +126,7 @@ export default function NavigationBar() {
);
}
}
- return [] as UiSchemaNavItem[];
+ return [] as UiSchemaUxElement[];
})
.flat();
if (eni) {
@@ -157,6 +155,27 @@ export default function NavigationBar() {
const userEmail = UserService.getUserEmail();
const username = UserService.getPreferredUsername();
+ const extensionNavigationElementsForDisplayLocation = (
+ displayLocation: string,
+ elementCallback: Function
+ ) => {
+ if (!extensionNavigationItems) {
+ return null;
+ }
+
+ return extensionNavigationItems.map((uxElement: UiSchemaUxElement) => {
+ if (uxElement.display_location === displayLocation) {
+ return elementCallback(uxElement);
+ }
+ return null;
+ });
+ };
+
+ const extensionUserProfileElement = (uxElement: UiSchemaUxElement) => {
+ const navItemPage = `/extensions${uxElement.page}`;
+ return {uxElement.label};
+ };
+
const profileToggletip = (
@@ -177,6 +196,10 @@ export default function NavigationBar() {
Documentation
+ {extensionNavigationElementsForDisplayLocation(
+ 'user_profile_item',
+ extensionUserProfileElement
+ )}
{!UserService.authenticationDisabled() ? (
<>
@@ -258,27 +281,21 @@ export default function NavigationBar() {
);
};
- const extensionNavigationElements = () => {
- if (!extensionNavigationItems) {
- return null;
+ const extensionHeaderMenuItemElement = (uxElement: UiSchemaUxElement) => {
+ const navItemPage = `/extensions${uxElement.page}`;
+ const regexp = new RegExp(`^${navItemPage}$`);
+ if (regexp.test(location.pathname)) {
+ setActiveKey(navItemPage);
}
-
- return extensionNavigationItems.map((navItem: UiSchemaNavItem) => {
- const navItemRoute = `/extensions${navItem.route}`;
- const regexp = new RegExp(`^${navItemRoute}`);
- if (regexp.test(location.pathname)) {
- setActiveKey(navItemRoute);
- }
- return (
-
- {navItem.label}
-
- );
- });
+ return (
+
+ {uxElement.label}
+
+ );
};
const headerMenuItems = () => {
@@ -328,7 +345,10 @@ export default function NavigationBar() {
{configurationElement()}
- {extensionNavigationElements()}
+ {extensionNavigationElementsForDisplayLocation(
+ 'header_menu_item',
+ extensionHeaderMenuItemElement
+ )}
>
);
};
diff --git a/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts b/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts
new file mode 100644
index 00000000..e68cb45c
--- /dev/null
+++ b/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts
@@ -0,0 +1,49 @@
+export enum UiSchemaDisplayLocation {
+ header_menu_item = 'header_menu_item',
+ user_profile_item = 'user_profile_item',
+}
+
+export enum UiSchemaPersistenceLevel {
+ full = 'full',
+ none = 'none',
+}
+
+export interface UiSchemaUxElement {
+ label: string;
+ page: string;
+ display_location: UiSchemaDisplayLocation;
+}
+
+export interface UiSchemaAction {
+ api_path: string;
+
+ persistence_level?: UiSchemaPersistenceLevel;
+ navigate_to_on_form_submit?: string;
+ results_markdown_filename?: string;
+}
+
+export interface UiSchemaPageDefinition {
+ header: string;
+ api: string;
+
+ on_load?: UiSchemaAction;
+ on_form_submit?: UiSchemaAction;
+ form_schema_filename?: any;
+ form_ui_schema_filename?: any;
+ markdown_instruction_filename?: string;
+ navigate_to_on_form_submit?: string;
+}
+
+export interface UiSchemaPage {
+ [key: string]: UiSchemaPageDefinition;
+}
+
+export interface ExtensionUiSchema {
+ ux_elements?: UiSchemaUxElement[];
+ pages: UiSchemaPage;
+}
+
+export interface ExtensionPostBody {
+ extension_input: any;
+ ui_schema_action?: UiSchemaAction;
+}
diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts
index 30c6bfd3..b4ae0a14 100644
--- a/spiffworkflow-frontend/src/interfaces.ts
+++ b/spiffworkflow-frontend/src/interfaces.ts
@@ -435,29 +435,3 @@ export interface DataStore {
name: string;
type: string;
}
-
-export interface UiSchemaNavItem {
- label: string;
- route: string;
-}
-export interface UiSchemaPageDefinition {
- header: string;
- api: string;
-
- form_schema_filename?: any;
- form_ui_schema_filename?: any;
- markdown_instruction_filename?: string;
- navigate_to_on_form_submit?: string;
-}
-export interface UiSchemaRoute {
- [key: string]: UiSchemaPageDefinition;
-}
-export interface ExtensionUiSchema {
- navigation_items?: UiSchemaNavItem[];
- routes: UiSchemaRoute;
-}
-
-export interface ExtensionPostBody {
- extension_input: any;
- ui_schema_page_definition?: UiSchemaPageDefinition;
-}
diff --git a/spiffworkflow-frontend/src/routes/Extension.tsx b/spiffworkflow-frontend/src/routes/Extension.tsx
index bf779560..be9dca51 100644
--- a/spiffworkflow-frontend/src/routes/Extension.tsx
+++ b/spiffworkflow-frontend/src/routes/Extension.tsx
@@ -1,20 +1,19 @@
-import { useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import MDEditor from '@uiw/react-md-editor';
import { useParams } from 'react-router-dom';
import { Editor } from '@monaco-editor/react';
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
-import {
- ExtensionPostBody,
- ExtensionUiSchema,
- ProcessFile,
- ProcessModel,
- UiSchemaPageDefinition,
-} from '../interfaces';
+import { ProcessFile, ProcessModel } from '../interfaces';
import HttpService from '../services/HttpService';
import useAPIError from '../hooks/UseApiError';
import { recursivelyChangeNullAndUndefined } from '../helpers';
import CustomForm from '../components/CustomForm';
import { BACKEND_BASE_URL } from '../config';
+import {
+ ExtensionPostBody,
+ ExtensionUiSchema,
+ UiSchemaPageDefinition,
+} from '../extension_ui_schema_interfaces';
import ErrorDisplay from '../components/ErrorDisplay';
// eslint-disable-next-line sonarjs/cognitive-complexity
@@ -26,7 +25,12 @@ export default function Extension() {
const [formData, setFormData] = useState(null);
const [formButtonsDisabled, setFormButtonsDisabled] = useState(false);
const [processedTaskData, setProcessedTaskData] = useState(null);
- const [markdownToRender, setMarkdownToRender] = useState(null);
+ const [markdownToRenderOnSubmit, setMarkdownToRenderOnSubmit] = useState<
+ string | null
+ >(null);
+ const [markdownToRenderOnLoad, setMarkdownToRenderOnLoad] = useState<
+ string | null
+ >(null);
const [filesByName] = useState<{
[key: string]: ProcessFile;
}>({});
@@ -35,18 +39,15 @@ export default function Extension() {
const { addError, removeError } = useAPIError();
- useEffect(() => {
- const processExtensionResult = (pm: ProcessModel) => {
- setProcessModel(pm);
- let extensionUiSchemaFile: ProcessFile | null = null;
- pm.files.forEach((file: ProcessFile) => {
- filesByName[file.name] = file;
- if (file.name === 'extension_uischema.json') {
- extensionUiSchemaFile = file;
+ const setConfigsIfDesiredSchemaFile = useCallback(
+ (extensionUiSchemaFile: ProcessFile | null, pm: ProcessModel) => {
+ const processLoadResult = (result: any) => {
+ setFormData(result.task_data);
+ if (result.rendered_results_markdown) {
+ setMarkdownToRenderOnLoad(result.rendered_results_markdown);
}
- });
+ };
- // typescript is really confused by extensionUiSchemaFile so force it since we are properly checking
if (
extensionUiSchemaFile &&
(extensionUiSchemaFile as ProcessFile).file_contents
@@ -55,24 +56,61 @@ export default function Extension() {
(extensionUiSchemaFile as any).file_contents
);
- let routeIdentifier = `/${params.process_model}`;
- if (params.extension_route) {
- routeIdentifier = `${routeIdentifier}/${params.extension_route}`;
+ const pageIdentifier = `/${params.page_identifier}`;
+ if (
+ extensionUiSchema.pages &&
+ Object.keys(extensionUiSchema.pages).includes(pageIdentifier)
+ ) {
+ const pageDefinition = extensionUiSchema.pages[pageIdentifier];
+ setUiSchemaPageDefinition(pageDefinition);
+ setProcessModel(pm);
+
+ const postBody: ExtensionPostBody = { extension_input: {} };
+ postBody.ui_schema_action = pageDefinition.on_load;
+ if (pageDefinition.on_load) {
+ HttpService.makeCallToBackend({
+ path: `${targetUris.extensionListPath}/${pageDefinition.on_load.api_path}`,
+ successCallback: processLoadResult,
+ httpMethod: 'POST',
+ postBody,
+ });
+ }
}
- setUiSchemaPageDefinition(extensionUiSchema.routes[routeIdentifier]);
}
+ },
+ [targetUris.extensionListPath, params]
+ );
+
+ useEffect(() => {
+ const processExtensionResult = (processModels: ProcessModel[]) => {
+ processModels.forEach((pm: ProcessModel) => {
+ let extensionUiSchemaFile: ProcessFile | null = null;
+ pm.files.forEach((file: ProcessFile) => {
+ filesByName[file.name] = file;
+ if (file.name === 'extension_uischema.json') {
+ extensionUiSchemaFile = file;
+ }
+ });
+ setConfigsIfDesiredSchemaFile(extensionUiSchemaFile, pm);
+ });
};
HttpService.makeCallToBackend({
- path: targetUris.extensionPath,
+ path: targetUris.extensionListPath,
successCallback: processExtensionResult,
});
- }, [targetUris.extensionPath, params, filesByName]);
+ }, [
+ filesByName,
+ params,
+ setConfigsIfDesiredSchemaFile,
+ targetUris.extensionListPath,
+ targetUris.extensionPath,
+ ]);
const processSubmitResult = (result: any) => {
setProcessedTaskData(result.task_data);
if (result.rendered_results_markdown) {
- setMarkdownToRender(result.rendered_results_markdown);
+ setMarkdownToRenderOnSubmit(result.rendered_results_markdown);
}
setFormButtonsDisabled(false);
};
@@ -111,15 +149,15 @@ export default function Extension() {
if (!isValid) {
return;
}
- const url = `${BACKEND_BASE_URL}/extensions-get-data/${params.process_model}/${optionString}`;
+ const url = `${BACKEND_BASE_URL}/extensions-get-data/${params.page_identifier}/${optionString}`;
window.location.href = url;
setFormButtonsDisabled(false);
} else {
const postBody: ExtensionPostBody = { extension_input: dataToSubmit };
let apiPath = targetUris.extensionPath;
- if (uiSchemaPageDefinition && uiSchemaPageDefinition.api) {
- apiPath = `${targetUris.extensionListPath}/${uiSchemaPageDefinition.api}`;
- postBody.ui_schema_page_definition = uiSchemaPageDefinition;
+ if (uiSchemaPageDefinition && uiSchemaPageDefinition.on_form_submit) {
+ apiPath = `${targetUris.extensionListPath}/${uiSchemaPageDefinition.on_form_submit.api_path}`;
+ postBody.ui_schema_action = uiSchemaPageDefinition.on_form_submit;
}
// NOTE: rjsf sets blanks values to undefined and JSON.stringify removes keys with undefined values
@@ -141,22 +179,30 @@ export default function Extension() {
if (uiSchemaPageDefinition) {
const componentsToDisplay = [{uiSchemaPageDefinition.header}
];
+ const markdownContentsToRender = [];
if (uiSchemaPageDefinition.markdown_instruction_filename) {
const markdownFile =
filesByName[uiSchemaPageDefinition.markdown_instruction_filename];
if (markdownFile.file_contents) {
- componentsToDisplay.push(
-
-
-
- );
+ markdownContentsToRender.push(markdownFile.file_contents);
}
}
+ if (markdownToRenderOnLoad) {
+ markdownContentsToRender.push(markdownToRenderOnLoad);
+ }
+
+ if (markdownContentsToRender.length > 0) {
+ componentsToDisplay.push(
+
+
+
+ );
+ }
if (uiSchemaPageDefinition.form_schema_filename) {
const formSchemaFile =
@@ -180,13 +226,13 @@ export default function Extension() {
}
}
if (processedTaskData) {
- if (markdownToRender) {
+ if (markdownToRenderOnSubmit) {
componentsToDisplay.push(
);