From 81f2f6191bddfa07edff6eea24bd814143786179 Mon Sep 17 00:00:00 2001 From: Ayoub Ait Lachgar <44379029+theaubmov@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:15:25 +0100 Subject: [PATCH] Feature/message editor improved UI (#1754) * retrieval_expressions should be a string and not an array in this context w/ burnettk * Improve message editor ui * Check if CorrelationProperties arent synced * Merge Imporoved UI for messages * some linting fixes * more linting * some updates for linting and updated bpmn-js-spiffworkflow w/ burnettk * removed unused console.log w/ burnettk * fix language w/ burnettk --------- Co-authored-by: jasquat --- .../services/message_definition_service.py | 7 +- .../examples/process_group.json | 53 ++-- .../integration/test_messages.py | 8 +- spiffworkflow-frontend/package-lock.json | 6 +- .../src/components/CustomForm.tsx | 9 +- .../src/components/Notification.tsx | 3 + .../src/components/messages/MessageEditor.tsx | 252 +++++++++++------- .../src/components/messages/MessageHelper.tsx | 60 ++++- spiffworkflow-frontend/src/index.css | 111 ++++++-- spiffworkflow-frontend/src/interfaces.ts | 2 +- .../src/rjsf/carbon_theme/index.css | 12 +- .../src/routes/ProcessModelEditDiagram.tsx | 21 +- 12 files changed, 371 insertions(+), 173 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/message_definition_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/message_definition_service.py index a9c21e27..dffbd6a9 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/message_definition_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/message_definition_service.py @@ -24,14 +24,13 @@ class MessageDefinitionService: models: list[MessageCorrelationPropertyModel] = [] for identifier, definition in correlation_property_group.items(): - retrieval_expressions = definition.get("retrieval_expressions") + retrieval_expression = definition.get("retrieval_expression") - if not retrieval_expressions: + if not retrieval_expression: current_app.logger.debug(f"Malformed correlation property: '{identifier}' in file @ '{location}'") continue - for retrieval_expression in retrieval_expressions: - models.append(MessageCorrelationPropertyModel(identifier=identifier, retrieval_expression=retrieval_expression)) + models.append(MessageCorrelationPropertyModel(identifier=identifier, retrieval_expression=retrieval_expression)) return models diff --git a/spiffworkflow-backend/tests/process_models_example_dir/examples/process_group.json b/spiffworkflow-backend/tests/process_models_example_dir/examples/process_group.json index 8ca186b9..b813d7da 100644 --- a/spiffworkflow-backend/tests/process_models_example_dir/examples/process_group.json +++ b/spiffworkflow-backend/tests/process_models_example_dir/examples/process_group.json @@ -5,32 +5,31 @@ "display_order": 40, "parent_groups": null, - - "messages": { - "table_seated": { - "correlation_properties": { - "table_number": { - "retrieval_expressions": ["table_number"] - }, - "franchise_id": { - "retrieval_expressions": ["franchise_id"] - } - }, - "schema": {} - }, - "order_ready": { - "correlation_properties": { - "table_number": { - "retrieval_expressions": ["table_number"] - }, - "franchise_id": { - "retrieval_expressions": ["franchise_id"] - } - }, - "schema": {} - }, - "end_of_day_receipts": { - "schema": {} - } + "messages": { + "table_seated": { + "correlation_properties": { + "table_number": { + "retrieval_expression": "table_number" + }, + "franchise_id": { + "retrieval_expression": "franchise_id" + } + }, + "schema": {} + }, + "order_ready": { + "correlation_properties": { + "table_number": { + "retrieval_expression": "table_number" + }, + "franchise_id": { + "retrieval_expression": "franchise_id" + } + }, + "schema": {} + }, + "end_of_day_receipts": { + "schema": {} } + } } diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_messages.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_messages.py index 4deb3743..343c8d4a 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_messages.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_messages.py @@ -126,10 +126,10 @@ class TestMessages(BaseTest): "table_seated": { "correlation_properties": { "table_number": { - "retrieval_expressions": ["table_number"], + "retrieval_expression": "table_number", }, "franchise_id": { - "retrieval_expressions": ["franchise_id"], + "retrieval_expression": "franchise_id", }, }, "schema": {}, @@ -137,10 +137,10 @@ class TestMessages(BaseTest): "order_ready": { "correlation_properties": { "table_number": { - "retrieval_expressions": ["table_number"], + "retrieval_expression": "table_number", }, "franchise_id": { - "retrieval_expressions": ["franchise_id"], + "retrieval_expression": "franchise_id", }, }, "schema": {}, diff --git a/spiffworkflow-frontend/package-lock.json b/spiffworkflow-frontend/package-lock.json index b9fec0e6..a04034f8 100644 --- a/spiffworkflow-frontend/package-lock.json +++ b/spiffworkflow-frontend/package-lock.json @@ -7669,7 +7669,7 @@ }, "node_modules/bpmn-js-spiffworkflow": { "version": "0.0.8", - "resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#7f7707838acc30d03fae907bb72f5bec101882b5", + "resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#fd7a9489d86bd9a8bd0f8c84eeba37c234443951", "license": "LGPL", "dependencies": { "inherits": "^2.0.4", @@ -31216,7 +31216,11 @@ } }, "bpmn-js-spiffworkflow": { +<<<<<<< HEAD + "version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#fd7a9489d86bd9a8bd0f8c84eeba37c234443951", +======= "version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#7f7707838acc30d03fae907bb72f5bec101882b5", +>>>>>>> origin/main "from": "bpmn-js-spiffworkflow@github:sartography/bpmn-js-spiffworkflow#main", "requires": { "inherits": "^2.0.4", diff --git a/spiffworkflow-frontend/src/components/CustomForm.tsx b/spiffworkflow-frontend/src/components/CustomForm.tsx index d86d4548..946b20ff 100644 --- a/spiffworkflow-frontend/src/components/CustomForm.tsx +++ b/spiffworkflow-frontend/src/components/CustomForm.tsx @@ -33,6 +33,7 @@ type OwnProps = { restrictedWidth?: boolean; submitButtonText?: string; reactJsonSchemaForm?: string; + hideSubmitButton?: boolean; }; export default function CustomForm({ @@ -50,6 +51,7 @@ export default function CustomForm({ restrictedWidth = false, submitButtonText, reactJsonSchemaForm = 'carbon', + hideSubmitButton = false, }: OwnProps) { // set in uiSchema using the "ui:widget" key for a property const rjsfWidgets = { @@ -500,7 +502,12 @@ export default function CustomForm({ let childrenToUse = children; if (submitButtonText) { childrenToUse = ( - ); diff --git a/spiffworkflow-frontend/src/components/Notification.tsx b/spiffworkflow-frontend/src/components/Notification.tsx index b005e66b..1bdd2598 100644 --- a/spiffworkflow-frontend/src/components/Notification.tsx +++ b/spiffworkflow-frontend/src/components/Notification.tsx @@ -4,6 +4,7 @@ import { Checkmark, Error, // @ts-ignore + WarningAlt, } from '@carbon/icons-react'; // @ts-ignore import { Button } from '@carbon/react'; @@ -38,6 +39,8 @@ export function Notification({ let iconComponent = ; if (type === 'error') { iconComponent = ; + } else if (type === 'warning') { + iconComponent = ; } if (timeout && onClose) { diff --git a/spiffworkflow-frontend/src/components/messages/MessageEditor.tsx b/spiffworkflow-frontend/src/components/messages/MessageEditor.tsx index 6f62a31d..3eb9e378 100644 --- a/spiffworkflow-frontend/src/components/messages/MessageEditor.tsx +++ b/spiffworkflow-frontend/src/components/messages/MessageEditor.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import CustomForm from '../CustomForm'; import { ProcessGroup, @@ -12,6 +12,7 @@ import { } from '../../helpers'; import HttpService from '../../services/HttpService'; import { + areCorrelationPropertiesInSync, convertCorrelationPropertiesToRJSF, mergeCorrelationProperties, } from './MessageHelper'; @@ -19,6 +20,7 @@ import { Notification } from '../Notification'; type OwnProps = { modifiedProcessGroupIdentifier: string; + elementId: string; messageId: string; messageEvent: any; correlationProperties: any; @@ -29,12 +31,123 @@ export function MessageEditor({ messageId, messageEvent, correlationProperties, + elementId, }: OwnProps) { const [processGroup, setProcessGroup] = useState(null); const [currentFormData, setCurrentFormData] = useState(null); const [displaySaveMessageMessage, setDisplaySaveMessageMessage] = useState(false); const [currentMessageId, setCurrentMessageId] = useState(null); + const [isSynced, setSynced] = useState(true); + + const updateCorrelationPropertiesOnProcessGroup = useCallback( + (currentMessagesForId: MessageDefinition, formData: any) => { + const newCorrelationProperties: CorrelationProperties = { + ...currentMessagesForId.correlation_properties, + }; + (formData.correlation_properties || []).forEach((formProp: any) => { + if (!(formProp.id in newCorrelationProperties)) { + newCorrelationProperties[formProp.id] = { + retrieval_expression: formProp.retrievalExpression, + }; + } + }); + + Object.keys(currentMessagesForId.correlation_properties || []).forEach( + (propId: string) => { + const foundProp = (formData.correlation_properties || []).find( + (formProp: any) => { + return propId === formProp.id; + }, + ); + if (!foundProp) { + delete newCorrelationProperties[propId]; + } + }, + ); + return newCorrelationProperties; + }, + [], + ); + + const handleProcessGroupUpdateResponse = useCallback( + ( + response: ProcessGroup, + messageIdentifier: string, + updatedMessagesForId: MessageDefinition, + ) => { + setProcessGroup(response); + setDisplaySaveMessageMessage(true); + messageEvent.eventBus.fire('spiff.add_message.returned', { + name: messageIdentifier, + correlation_properties: updatedMessagesForId.correlation_properties, + elementId, + }); + setSynced(true); + }, + [elementId, messageEvent.eventBus], + ); + + const updateProcessGroupWithMessages = useCallback( + (formObject: RJSFFormObject) => { + const { formData } = formObject; + + if (!processGroup) { + return; + } + + // keep track of new and old message ids so we can handle renaming a message + const newMessageId = formData.messageId; + const oldMessageId = currentMessageId || newMessageId; + + const processGroupForUpdate = { ...processGroup }; + if (!processGroupForUpdate.messages) { + processGroupForUpdate.messages = {}; + } + const currentMessagesForId: MessageDefinition = + (processGroupForUpdate.messages || {})[oldMessageId] || {}; + const updatedMessagesForId = { ...currentMessagesForId }; + + const newCorrelationProperties = + updateCorrelationPropertiesOnProcessGroup( + currentMessagesForId, + formData, + ); + + updatedMessagesForId.correlation_properties = newCorrelationProperties; + + try { + updatedMessagesForId.schema = JSON.parse(formData.schema || '{}'); + } catch (e) { + // TODO: display error in a tag like we normally do + // eslint-disable-next-line no-alert + alert(`Invalid schema: ${e}`); + return; + } + + processGroupForUpdate.messages[newMessageId] = updatedMessagesForId; + setCurrentMessageId(newMessageId); + const path = `/process-groups/${modifiedProcessGroupIdentifier}`; + HttpService.makeCallToBackend({ + path, + successCallback: (response: ProcessGroup) => + handleProcessGroupUpdateResponse( + response, + newMessageId, + updatedMessagesForId, + ), + httpMethod: 'PUT', + postBody: processGroupForUpdate, + }); + }, + [ + currentMessageId, + handleProcessGroupUpdateResponse, + modifiedProcessGroupIdentifier, + processGroup, + updateCorrelationPropertiesOnProcessGroup, + ], + ); useEffect(() => { const setInitialFormData = (newProcessGroup: ProcessGroup) => { @@ -46,7 +159,6 @@ export function MessageEditor({ correlationProperties, newCorrelationProperties, ); - const jsonSchema = (newProcessGroup.messages || {})[messageId]?.schema || {}; const newFormData = { @@ -60,6 +172,12 @@ export function MessageEditor({ setCurrentFormData(newFormData); }; const processResult = (result: ProcessGroup) => { + const newIsSynced = areCorrelationPropertiesInSync( + result, + messageId, + correlationProperties, + ); + setSynced(newIsSynced); setProcessGroup(result); setCurrentMessageId(messageId); setPageTitle([result.display_name]); @@ -71,108 +189,21 @@ export function MessageEditor({ }); }, [modifiedProcessGroupIdentifier, correlationProperties, messageId]); - const handleProcessGroupUpdateResponse = ( - response: ProcessGroup, - messageIdentifier: string, - updatedMessagesForId: MessageDefinition, - ) => { - setProcessGroup(response); - setDisplaySaveMessageMessage(true); - messageEvent.eventBus.fire('spiff.add_message.returned', { - name: messageIdentifier, - correlation_properties: updatedMessagesForId.correlation_properties, - }); - }; - - const updateCorrelationPropertiesOnProcessGroup = ( - currentMessagesForId: MessageDefinition, - formData: any, - ) => { - const newCorrelationProperties: CorrelationProperties = { - ...currentMessagesForId.correlation_properties, + // Setup event listeners on message.save + useEffect(() => { + const handleSaveEvent = (_event: any) => { + updateProcessGroupWithMessages({ + formData: currentFormData, + }); }; - (formData.correlation_properties || []).forEach((formProp: any) => { - if (!(formProp.id in newCorrelationProperties)) { - newCorrelationProperties[formProp.id] = { - retrieval_expressions: [], - }; - } - if ( - !newCorrelationProperties[formProp.id].retrieval_expressions.includes( - formProp.retrievalExpression, - ) - ) { - newCorrelationProperties[formProp.id].retrieval_expressions.push( - formProp.retrievalExpression, - ); - } - }); - Object.keys(currentMessagesForId.correlation_properties || []).forEach( - (propId: string) => { - const foundProp = (formData.correlation_properties || []).find( - (formProp: any) => { - return propId === formProp.id; - }, - ); - if (!foundProp) { - delete newCorrelationProperties[propId]; - } - }, - ); - return newCorrelationProperties; - }; + messageEvent.eventBus.on('spiff.message.save', handleSaveEvent); - const updateProcessGroupWithMessages = (formObject: RJSFFormObject) => { - const { formData } = formObject; - - if (!processGroup) { - return; - } - - // keep track of new and old message ids so we can handle renaming a message - const newMessageId = formData.messageId; - const oldMessageId = currentMessageId || newMessageId; - - const processGroupForUpdate = { ...processGroup }; - if (!processGroupForUpdate.messages) { - processGroupForUpdate.messages = {}; - } - const currentMessagesForId: MessageDefinition = - (processGroupForUpdate.messages || {})[oldMessageId] || {}; - const updatedMessagesForId = { ...currentMessagesForId }; - - const newCorrelationProperties = updateCorrelationPropertiesOnProcessGroup( - currentMessagesForId, - formData, - ); - - updatedMessagesForId.correlation_properties = newCorrelationProperties; - - try { - updatedMessagesForId.schema = JSON.parse(formData.schema || '{}'); - } catch (e) { - // TODO: display error in a tag like we normally do - // eslint-disable-next-line no-alert - alert(`Invalid schema: ${e}`); - return; - } - - processGroupForUpdate.messages[newMessageId] = updatedMessagesForId; - setCurrentMessageId(newMessageId); - const path = `/process-groups/${modifiedProcessGroupIdentifier}`; - HttpService.makeCallToBackend({ - path, - successCallback: (response: ProcessGroup) => - handleProcessGroupUpdateResponse( - response, - newMessageId, - updatedMessagesForId, - ), - httpMethod: 'PUT', - postBody: processGroupForUpdate, - }); - }; + // Cleanup event listener on unmount + return () => { + messageEvent.eventBus.off('spiff.message.save', handleSaveEvent); + }; + }, [currentFormData, messageEvent.eventBus, updateProcessGroupWithMessages]); const schema = { type: 'object', @@ -226,6 +257,7 @@ export function MessageEditor({ }, }, }; + const uischema = { schema: { 'ui:widget': 'textarea', @@ -265,6 +297,20 @@ export function MessageEditor({ Message has been saved ) : null} + {!isSynced && !displaySaveMessageMessage ? ( + setDisplaySaveMessageMessage(false)} + > + There is a difference between the message properties in this process + model and the shared message data stored with the process group. + Updating the message properties by saving is recommended to ensure + data consistency + + ) : null} ); } + return null; } diff --git a/spiffworkflow-frontend/src/components/messages/MessageHelper.tsx b/spiffworkflow-frontend/src/components/messages/MessageHelper.tsx index 0bba2534..21acd6f0 100644 --- a/spiffworkflow-frontend/src/components/messages/MessageHelper.tsx +++ b/spiffworkflow-frontend/src/components/messages/MessageHelper.tsx @@ -23,11 +23,9 @@ export const convertCorrelationPropertiesToRJSF = ( const returnArray: any = []; Object.keys(correlationPropertiesToUse).forEach((propIdentifier: string) => { const property = correlationPropertiesToUse[propIdentifier]; - return property.retrieval_expressions.forEach((retExp: string) => { - returnArray.push({ - id: propIdentifier, - retrievalExpression: retExp, - }); + returnArray.push({ + id: propIdentifier, + retrievalExpression: property.retrieval_expression, }); }); return returnArray; @@ -53,3 +51,55 @@ export const mergeCorrelationProperties = ( return mergedProperties; }; + +export const areCorrelationPropertiesInSync = ( + processGroup: ProcessGroup, + messageId: string, + messageProperties: any[], +) => { + if (!messageId) { + // About Message Creation + return true; + } + + const message = processGroup.messages + ? processGroup.messages[messageId] + : undefined; + + if (!message) { + return false; + } + + const localPropertyIds = messageProperties.map((property) => property.id); + const processGroupPropertyIds = Object.keys(message.correlation_properties); + + // Check if all local properties exist in the process group data + // TODO: fix the lint + // eslint-disable-next-line + for (const property of messageProperties) { + const correlationProperty = message.correlation_properties[property.id]; + + if (!correlationProperty) { + return false; + } + + const localRetrievalExpression = Array.isArray(property.retrievalExpression) + ? property.retrievalExpression[0] + : property.retrievalExpression; + + if (correlationProperty.retrieval_expression !== localRetrievalExpression) { + return false; + } + } + + // Checking if all process group properties exist in the local xml + // TODO: fix the lint + // eslint-disable-next-line + for (const propertyId of processGroupPropertyIds) { + if (!localPropertyIds.includes(propertyId)) { + return false; + } + } + + return true; +}; diff --git a/spiffworkflow-frontend/src/index.css b/spiffworkflow-frontend/src/index.css index 5b534bfd..52407ae8 100644 --- a/spiffworkflow-frontend/src/index.css +++ b/spiffworkflow-frontend/src/index.css @@ -25,6 +25,7 @@ a.cds--header__menu-item { background-color: #161616; cursor: default; } + .cds--header__action.unclickable-text:focus { border: none; box-shadow: none; @@ -81,6 +82,7 @@ h3 { background-blend-mode: multiply; border: 1px solid #393939; } + .cds--btn.button-white-background:hover { background: lightgrey; } @@ -88,12 +90,15 @@ h3 { .spiff-breadcrumb .MuiBreadcrumbs-li a:hover { color: #525252; } + .spiff-breadcrumb .MuiBreadcrumbs-li a:visited { color: #525252; } + .spiff-breadcrumb .MuiBreadcrumbs-li a:visited:hover { color: #525252; } + .spiff-breadcrumb .MuiBreadcrumbs-li a { color: #525252; } @@ -101,12 +106,15 @@ h3 { .cds--btn--ghost { color: black; } + .cds--btn--ghost:visited { color: black; } + .cds--btn--ghost:hover { color: black; } + .cds--btn--ghost:visited:hover { color: black; } @@ -116,15 +124,18 @@ h3 { color: #0062fe; padding-left: 0; } + .cds--btn--ghost.button-link:visited { color: #0062fe; padding-left: 0; } + .cds--btn--ghost.button-link:hover { color: #0062fe; background-color: white; padding-left: 0; } + .cds--btn--ghost.button-link:visited:hover { color: #0062fe; background-color: white; @@ -136,10 +147,12 @@ h3 { color: black; border-color: black; } + .cds--btn--tertiary:visited { color: black; border-color: black; } + /* make the colors a little lighter black on hover * so they match our normal scheme better */ @@ -148,11 +161,13 @@ h3 { border-color: #161616; background-color: #f4f4f4; } + .cds--btn--tertiary:hover { color: #161616; border-color: #161616; background-color: #f4f4f4; } + .cds--btn--tertiary:visited:hover { color: #161616; border-color: #161616; @@ -164,21 +179,25 @@ h3 { border-color: #efefef; background-color: #efefef; } + .cds--btn--secondary:visited { color: #161616; border-color: #efefef; background-color: #efefef; } + .cds--btn--secondary:focus { color: #161616; border-color: #efefef; background-color: #efefef; } + .cds--btn--secondary:hover { color: #161616; border-color: #dddddd; background-color: #dddddd; } + .cds--btn--secondary:visited:hover { color: #161616; border-color: #dddddd; @@ -190,27 +209,58 @@ h3 { border-color: #393939; background-color: #393939; } + .cds--modal-footer .cds--btn--secondary:visited { color: #ffffff; border-color: #393939; background-color: #393939; } + .cds--modal-footer .cds--btn--secondary:focus { color: #ffffff; border-color: #393939; background-color: #393939; } + .cds--modal-footer .cds--btn--secondary:hover { color: #ffffff; border-color: #474747; background-color: #474747; } + .cds--modal-footer .cds--btn--secondary:visited:hover { color: #ffffff; border-color: #474747; background-color: #474747; } +/* position the close button at the top-right corner of the modal header */ +.cds--modal-close { + position: absolute; + top: 1rem; + right: 1rem; + border: none; + background: transparent; + cursor: pointer; + padding: 0; +} + +.cds--modal-close__icon { + fill: #161616; +} + +.cds--modal-footer .cds--btn--secondary { + color: #161616; + border-color: #e0e0e0; + background-color: #e0e0e0; +} + +.cds--modal-footer .cds--btn--secondary:hover { + border-color: #c6c6c6; + background-color: #c6c6c6; + color: #161616; +} + .cds--header__global .cds--btn--primary.button-link { color: #f4f4f4; background-color: #393939; @@ -220,12 +270,15 @@ h3 { .cds--header__global .cds--btn--primary { background-color: #161616; } + .cds--btn--primary { background-color: #393939; } + .cds--btn--primary:hover { background-color: #474747; } + code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; @@ -242,20 +295,22 @@ code { margin-bottom: 2rem; } -.active-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { +.active-task-highlight:not(.djs-connection) .djs-visual> :nth-child(1) { fill: yellow !important; opacity: 0.6; } -.completed-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { +.completed-task-highlight:not(.djs-connection) .djs-visual> :nth-child(1) { fill: grey !important; opacity: 0.4; } -.cancelled-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { + +.cancelled-task-highlight:not(.djs-connection) .djs-visual> :nth-child(1) { fill: blue !important; opacity: 0.2; } -.errored-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { + +.errored-task-highlight:not(.djs-connection) .djs-visual> :nth-child(1) { fill: red !important; opacity: 0.2; } @@ -340,6 +395,7 @@ dl dd { margin-top: 8px; margin-right: 12px; } + #user-profile-toggletip .cds--popover-content::before { content: none; } @@ -363,9 +419,7 @@ dl dd { content: none; } -#user-profile-toggletip - .cds--popover--tab-tip.cds--popover--open - .cds--popover--tab-tip__button { +#user-profile-toggletip .cds--popover--tab-tip.cds--popover--open .cds--popover--tab-tip__button { background-color: #161616; } @@ -423,16 +477,19 @@ dl dd { font-size: 12pt; border-collapse: collapse; } + .markdown table thead th, .markdown table tfoot th { color: #777; background: rgba(0, 0, 0, 0.1); } + .markdown table th, .markdown table td { padding: 0.5rem; border: 1px solid lightgrey; } + /* Zebra Table Style */ .markdown tbody tr:nth-of-type(odd) { background: rgba(0, 0, 0, 0.05); @@ -444,7 +501,7 @@ dl dd { /* Json Web Form CSS Fix - Bootstrap now requries that each li have a "list-inline-item." Also have a PR in on this with the react-jsonschema-form repo. This is just a patch fix to allow date inputs to layout a little more cleanly */ -.list-inline > li { +.list-inline>li { display: inline-block; padding-right: 5px; padding-left: 5px; @@ -589,9 +646,11 @@ th.table-header-right-align .cds--table-header-label { .cds--btn--ghost:not([disabled]).red-icon svg { fill: red; } + .cds--btn--ghost:not([disabled]).green-icon svg { fill: #198038; } + .cds--btn--ghost:not([disabled]) svg.red-icon { fill: red; } @@ -613,13 +672,14 @@ svg.notification-icon { width: 100%; height: 2rem; } -.filter-tag > span { + +.filter-tag>span { display: flex; flex-direction: row; width: 100%; } -.filter-tag > span > span { +.filter-tag>span>span { margin-right: 0.5px; } @@ -668,6 +728,7 @@ svg.notification-icon { .modal-within-table-cell .cds--modal-container { text-align: left; } + .modal-within-table-cell .cds--modal-container button { padding-left: 15px; } @@ -844,8 +905,9 @@ div.json-schema { } fieldset legend.header { - margin-bottom: 32px; + margin-bottom: 16px; } + fieldset fieldset fieldset legend.header { margin-bottom: 16px; } @@ -876,6 +938,7 @@ blockquote, hr { max-width: 640px; } + li.cds--accordion__item { max-width: 100%; } @@ -893,14 +956,11 @@ div.markdown-collapsed { max-height: 200px; overflow: hidden; - --mask: linear-gradient( - to bottom, + --mask: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 95%, - rgba(0, 0, 0, 0) 0 - ) - 100% 50% / 100% 100% repeat-x; + rgba(0, 0, 0, 0) 0) 100% 50% / 100% 100% repeat-x; font: 2em/1.6em Arial; -webkit-mask: var(--mask); @@ -920,6 +980,7 @@ div.markdown-collapsed { .cds--accordion { --cds-layout-density-padding-inline-local: 0px; } + .megacondensed-button .cds--btn { --cds-layout-density-padding-inline-local: 0px; } @@ -945,6 +1006,7 @@ div.onboarding { .completed-task-modal .cds--modal-container { background-color: #ffffff; } + .completed-task-modal .cds--text-input:disabled, .completed-task-modal .cds--text-area:disabled, .completed-task-modal .cds--date-picker__input:disabled, @@ -953,6 +1015,7 @@ div.onboarding { --cds-text-disabled: rgba(22, 22, 22, 0.5); background-color: var(--cds-field); } + .completed-task-modal .cds--form__helper-text--disabled { --cds-text-disabled: rgba(22, 22, 22, 0.5); } @@ -963,6 +1026,7 @@ div.onboarding { overflow: hidden; white-space: nowrap; } + .process-model-file-table-filename { overflow: hidden; text-overflow: ellipsis; @@ -997,15 +1061,20 @@ div.onboarding { } .shortcut-description { - width: 50%; /* Adjust width as needed */ - float: left; /* Floats the description to the left */ + width: 50%; + /* Adjust width as needed */ + float: left; + /* Floats the description to the left */ margin-top: 10px; } .shortcut-key-group { - width: 50%; /* Adjust width as needed */ - float: right; /* Floats the keys to the right */ - text-align: right; /* Aligns text to the right within the container */ + width: 50%; + /* Adjust width as needed */ + float: right; + /* Floats the keys to the right */ + text-align: right; + /* Aligns text to the right within the container */ } div.retrievalExpressionsForm { diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index b13c7115..af29366e 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -213,7 +213,7 @@ export interface ProcessInstance { } export interface CorrelationProperty { - retrieval_expressions: string[]; + retrieval_expression: string; } export interface CorrelationProperties { diff --git a/spiffworkflow-frontend/src/rjsf/carbon_theme/index.css b/spiffworkflow-frontend/src/rjsf/carbon_theme/index.css index a66672c4..0716f939 100644 --- a/spiffworkflow-frontend/src/rjsf/carbon_theme/index.css +++ b/spiffworkflow-frontend/src/rjsf/carbon_theme/index.css @@ -31,6 +31,7 @@ .rjsf .rjsf-field .rjsf-field { margin-bottom: 2rem; } + /* only the outter rjsf-field gets the margin from the rule above but not its contents like the array-item so mention it explicitly */ .rjsf .array-item .rjsf-field .rjsf-field { margin-bottom: 2rem; @@ -49,6 +50,7 @@ padding-bottom: 8px; font-size: 14px; } + /* position the remove button to align with the file description */ .rjsf .file-info span div { position: relative; @@ -72,8 +74,10 @@ padding-top: 1rem; padding-bottom: 1rem; margin-bottom: 1rem; - background: rgba(0, 0, 0, 0.1); - border-radius: 0.5rem; + /* background: rgba(0, 0, 0, 0.1); + border-radius: 0.5rem; */ + background: rgb(109 107 107 / 10%); + border-radius: 0.30rem; } .rjsf .array-item legend { @@ -123,10 +127,12 @@ .rjsf .array-field-container { display: flex; } + .rjsf .array-field-contents { flex: 8; margin-left: calc(3%); } + .rjsf .array-field-actions { flex: 1; display: flex; @@ -137,4 +143,4 @@ .rjsf .radio-button-group { padding-top: 0.5rem; -} +} \ No newline at end of file diff --git a/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx b/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx index edb9e7c8..8d8f6faa 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx @@ -46,6 +46,7 @@ import { } from '../helpers'; import { CarbonComboBoxProcessSelection, + CorrelationProperties, ProcessFile, ProcessModel, ProcessReference, @@ -83,7 +84,9 @@ export default function ProcessModelEditDiagram() { const [showMarkdownEditor, setShowMarkdownEditor] = useState(false); const [showMessageEditor, setShowMessageEditor] = useState(false); const [messageId, setMessageId] = useState(''); - const [correlationProperties, setCorrelationProperties] = useState([]); + const [elementId, setElementId] = useState(''); + const [correlationProperties, setCorrelationProperties] = + useState(null); const [showProcessSearch, setShowProcessSearch] = useState(false); const [processSearchEventBus, setProcessSearchEventBus] = useState(null); const [processSearchElement, setProcessSearchElement] = useState(null); @@ -1062,6 +1065,7 @@ export default function ProcessModelEditDiagram() { const onLaunchMessageEditor = (event: any) => { setMessageEvent(event); setMessageId(event.value.messageId); + setElementId(event.value.elementId); setCorrelationProperties(event.value.correlation_properties); handleShowMessageEditor(); }; @@ -1070,6 +1074,11 @@ export default function ProcessModelEditDiagram() { onMessagesRequested(messageEvent); }; + const handleMessageEditorSave = (_event: any) => { + // setShowMessageEditor(false); + messageEvent.eventBus.fire('spiff.message.save'); + }; + const messageEditor = () => { // do not render this component until we actually want to display it if (!showMessageEditor) { @@ -1078,12 +1087,15 @@ export default function ProcessModelEditDiagram() { return (