Enhance Process Templates with New Data-Driven Workflows and URL Parameter Capture

- Added a new category for 'Data-Driven Workflows' in the ProcessTemplatesModal component.
- Introduced multiple new templates for data-driven workflows, including 'URL Data Capture & Form Pre-fill', 'Dynamic Survey with Conditional Logic', 'Order Processing with Status Updates', and 'Customer Feedback Analysis'.
- Enhanced VariableManager to support capturing variable values from URL parameters, including new form fields for URL parameter configuration.
- Updated workflow page to capture URL parameters for variables configured to do so, improving the integration of external data into workflows.
- Adjusted processBuilder store to include new properties for URL parameter handling in variable definitions.
This commit is contained in:
Md Afiq Iskandar 2025-07-31 16:34:52 +08:00
parent 47c296fcc0
commit dfea8e7f47
4 changed files with 956 additions and 9 deletions

View File

@ -256,7 +256,8 @@ const categories = [
{ id: 'onboarding', name: 'Onboarding' },
{ id: 'support', name: 'Support & Service' },
{ id: 'business', name: 'Business Operations' },
{ id: 'automation', name: 'Automation' }
{ id: 'automation', name: 'Automation' },
{ id: 'data-driven', name: 'Data-Driven Workflows' }
];
// Active category
@ -1207,6 +1208,832 @@ const templates = [
{ id: 'e40', source: 'form-10', target: 'notification-11', sourceHandle: 'form-10-bottom', targetHandle: 'notification-11-top', type: 'smoothstep' },
{ id: 'e41', source: 'notification-11', target: 'end-6', sourceHandle: 'notification-11-bottom', targetHandle: 'end-6-top', type: 'smoothstep' }
]
},
{
id: 'url-data-capture',
name: 'URL Data Capture & Form Pre-fill',
description: 'Capture user ID from URL parameters, fetch user data via API, and pre-fill a form for editing.',
category: 'data-driven',
complexity: 'Simple',
nodeCount: 4,
edgeCount: 3,
variables: [
{
name: 'userId',
type: 'string',
scope: 'global',
description: 'User ID captured from URL parameter',
defaultValue: '',
captureFromUrl: true,
urlParameterName: 'id'
},
{
name: 'userData',
type: 'object',
scope: 'global',
description: 'User data retrieved from API',
defaultValue: {}
},
{
name: 'formSubmissionResult',
type: 'object',
scope: 'global',
description: 'Result of form submission',
defaultValue: {}
}
],
nodes: [
{
id: 'start-url-1',
type: 'start',
position: { x: 100, y: 100 },
data: {
label: 'Start',
description: 'Begin URL data capture process',
backgroundColor: '#dcfce7',
borderColor: '#10b981',
textColor: '#065f46',
shape: 'circle'
}
},
{
id: 'api-fetch-user',
type: 'api',
position: { x: 300, y: 100 },
data: {
label: 'Fetch User Data',
description: 'Retrieve user information from API',
apiMethod: 'GET',
apiUrl: '/api/users/{userId}',
headers: [
{ key: 'Content-Type', value: 'application/json' },
{ key: 'Authorization', value: 'Bearer YOUR_API_TOKEN' }
],
outputVariable: 'userData',
errorVariable: 'apiError',
continueOnError: false,
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'form-edit-user',
type: 'form',
position: { x: 500, y: 100 },
data: {
label: 'Edit User Information',
description: 'Form pre-filled with user data for editing',
formId: null,
formName: 'User Information Form',
inputMappings: [
{ processVariable: 'userData.name', formField: 'fullName' },
{ processVariable: 'userData.email', formField: 'email' },
{ processVariable: 'userData.phone', formField: 'phoneNumber' }
],
outputMappings: [
{ formField: 'fullName', processVariable: 'updatedName' },
{ formField: 'email', processVariable: 'updatedEmail' },
{ formField: 'phoneNumber', processVariable: 'updatedPhone' }
],
backgroundColor: '#faf5ff',
borderColor: '#9333ea',
textColor: '#6b21a8',
shape: 'rectangle'
}
},
{
id: 'end-url-1',
type: 'end',
position: { x: 700, y: 100 },
data: {
label: 'End',
description: 'Process completed',
backgroundColor: '#fee2e2',
borderColor: '#dc2626',
textColor: '#991b1b',
shape: 'circle'
}
}
],
edges: [
{ id: 'e-url-1', source: 'start-url-1', target: 'api-fetch-user', sourceHandle: 'start-url-1-bottom', targetHandle: 'api-fetch-user-top', type: 'smoothstep' },
{ id: 'e-url-2', source: 'api-fetch-user', target: 'form-edit-user', sourceHandle: 'api-fetch-user-bottom', targetHandle: 'form-edit-user-top', type: 'smoothstep' },
{ id: 'e-url-3', source: 'form-edit-user', target: 'end-url-1', sourceHandle: 'form-edit-user-bottom', targetHandle: 'end-url-1-top', type: 'smoothstep' }
]
},
{
id: 'dynamic-survey',
name: 'Dynamic Survey with Conditional Logic',
description: 'Multi-step survey with conditional questions based on URL parameters and previous answers.',
category: 'data-driven',
complexity: 'Medium',
nodeCount: 6,
edgeCount: 7,
variables: [
{
name: 'surveyType',
type: 'string',
scope: 'global',
description: 'Type of survey from URL parameter',
defaultValue: 'general',
captureFromUrl: true,
urlParameterName: 'type'
},
{
name: 'userRole',
type: 'string',
scope: 'global',
description: 'User role from URL parameter',
defaultValue: 'user',
captureFromUrl: true,
urlParameterName: 'role'
},
{
name: 'basicInfo',
type: 'object',
scope: 'global',
description: 'Basic information from first form',
defaultValue: {}
},
{
name: 'isManager',
type: 'boolean',
scope: 'global',
description: 'Whether user is in management role',
defaultValue: false
},
{
name: 'surveyResults',
type: 'object',
scope: 'global',
description: 'Complete survey results',
defaultValue: {}
}
],
nodes: [
{
id: 'start-survey',
type: 'start',
position: { x: 100, y: 200 },
data: {
label: 'Start Survey',
description: 'Begin dynamic survey process',
backgroundColor: '#dcfce7',
borderColor: '#10b981',
textColor: '#065f46',
shape: 'circle'
}
},
{
id: 'form-basic-info',
type: 'form',
position: { x: 300, y: 200 },
data: {
label: 'Basic Information',
description: 'Collect basic user information',
formId: null,
formName: 'Basic Information Form',
outputMappings: [
{ formField: 'name', processVariable: 'basicInfo.name' },
{ formField: 'department', processVariable: 'basicInfo.department' },
{ formField: 'experience', processVariable: 'basicInfo.experience' }
],
backgroundColor: '#faf5ff',
borderColor: '#9333ea',
textColor: '#6b21a8',
shape: 'rectangle'
}
},
{
id: 'business-rule-role-check',
type: 'business-rule',
position: { x: 500, y: 200 },
data: {
label: 'Check User Role',
description: 'Determine if user is manager based on role parameter',
ruleGroups: [
{
name: 'Manager Check',
conditions: [
{
variable: 'userRole',
operator: 'eq',
value: 'manager',
minValue: null,
maxValue: null
}
],
actions: [
{
type: 'set_variable',
variable: 'isManager',
value: 'true'
}
]
}
],
backgroundColor: '#fdf4ff',
borderColor: '#a855f7',
textColor: '#7c3aed',
shape: 'rectangle'
}
},
{
id: 'gateway-manager-check',
type: 'gateway',
position: { x: 700, y: 200 },
data: {
label: 'Is Manager?',
description: 'Route based on manager status',
conditions: [
{
variable: 'isManager',
operator: 'eq',
value: 'true',
output: 'Manager Path'
}
],
defaultPath: 'Employee Path',
backgroundColor: '#fff7ed',
borderColor: '#f97316',
textColor: '#c2410c',
shape: 'diamond'
}
},
{
id: 'form-manager-questions',
type: 'form',
position: { x: 900, y: 150 },
data: {
label: 'Manager Questions',
description: 'Additional questions for managers',
formId: null,
formName: 'Manager Survey Form',
outputMappings: [
{ formField: 'teamSize', processVariable: 'surveyResults.teamSize' },
{ formField: 'managementStyle', processVariable: 'surveyResults.managementStyle' },
{ formField: 'budgetResponsibility', processVariable: 'surveyResults.budgetResponsibility' }
],
backgroundColor: '#faf5ff',
borderColor: '#9333ea',
textColor: '#6b21a8',
shape: 'rectangle'
}
},
{
id: 'form-employee-questions',
type: 'form',
position: { x: 900, y: 250 },
data: {
label: 'Employee Questions',
description: 'Questions for regular employees',
formId: null,
formName: 'Employee Survey Form',
outputMappings: [
{ formField: 'jobSatisfaction', processVariable: 'surveyResults.satisfaction' },
{ formField: 'workloadRating', processVariable: 'surveyResults.workload' },
{ formField: 'careerGoals', processVariable: 'surveyResults.goals' }
],
backgroundColor: '#faf5ff',
borderColor: '#9333ea',
textColor: '#6b21a8',
shape: 'rectangle'
}
},
{
id: 'end-survey',
type: 'end',
position: { x: 1100, y: 200 },
data: {
label: 'Survey Complete',
description: 'Survey completed successfully',
backgroundColor: '#fee2e2',
borderColor: '#dc2626',
textColor: '#991b1b',
shape: 'circle'
}
}
],
edges: [
{ id: 'e-survey-1', source: 'start-survey', target: 'form-basic-info', sourceHandle: 'start-survey-bottom', targetHandle: 'form-basic-info-top', type: 'smoothstep' },
{ id: 'e-survey-2', source: 'form-basic-info', target: 'business-rule-role-check', sourceHandle: 'form-basic-info-bottom', targetHandle: 'business-rule-role-check-top', type: 'smoothstep' },
{ id: 'e-survey-3', source: 'business-rule-role-check', target: 'gateway-manager-check', sourceHandle: 'business-rule-role-check-bottom', targetHandle: 'gateway-manager-check-top', type: 'smoothstep' },
{ id: 'e-survey-4', source: 'gateway-manager-check', target: 'form-manager-questions', sourceHandle: 'gateway-manager-check-right', targetHandle: 'form-manager-questions-left', type: 'smoothstep', label: 'Manager Path' },
{ id: 'e-survey-5', source: 'gateway-manager-check', target: 'form-employee-questions', sourceHandle: 'gateway-manager-check-bottom', targetHandle: 'form-employee-questions-left', type: 'smoothstep', label: 'Employee Path' },
{ id: 'e-survey-6', source: 'form-manager-questions', target: 'end-survey', sourceHandle: 'form-manager-questions-bottom', targetHandle: 'end-survey-top', type: 'smoothstep' },
{ id: 'e-survey-7', source: 'form-employee-questions', target: 'end-survey', sourceHandle: 'form-employee-questions-bottom', targetHandle: 'end-survey-left', type: 'smoothstep' }
]
},
{
id: 'order-processing',
name: 'Order Processing with Status Updates',
description: 'Process orders with automatic status updates and notifications based on order ID from URL.',
category: 'business',
complexity: 'Medium',
nodeCount: 7,
edgeCount: 8,
variables: [
{
name: 'orderId',
type: 'string',
scope: 'global',
description: 'Order ID from URL parameter',
defaultValue: '',
captureFromUrl: true,
urlParameterName: 'orderId'
},
{
name: 'priority',
type: 'string',
scope: 'global',
description: 'Order priority from URL parameter',
defaultValue: 'normal',
captureFromUrl: true,
urlParameterName: 'priority'
},
{
name: 'orderData',
type: 'object',
scope: 'global',
description: 'Order details from API',
defaultValue: {}
},
{
name: 'isHighPriority',
type: 'boolean',
scope: 'global',
description: 'Whether order is high priority',
defaultValue: false
},
{
name: 'processingResult',
type: 'object',
scope: 'global',
description: 'Result of order processing',
defaultValue: {}
}
],
nodes: [
{
id: 'start-order',
type: 'start',
position: { x: 100, y: 300 },
data: {
label: 'Start Processing',
description: 'Begin order processing',
backgroundColor: '#dcfce7',
borderColor: '#10b981',
textColor: '#065f46',
shape: 'circle'
}
},
{
id: 'api-get-order',
type: 'api',
position: { x: 300, y: 300 },
data: {
label: 'Fetch Order',
description: 'Get order details from system',
apiMethod: 'GET',
apiUrl: '/api/orders/{orderId}',
headers: [
{ key: 'Content-Type', value: 'application/json' },
{ key: 'Authorization', value: 'Bearer YOUR_API_TOKEN' }
],
outputVariable: 'orderData',
errorVariable: 'orderError',
continueOnError: false,
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'business-rule-priority',
type: 'business-rule',
position: { x: 500, y: 300 },
data: {
label: 'Check Priority',
description: 'Determine processing priority',
ruleGroups: [
{
name: 'High Priority Check',
conditions: [
{
variable: 'priority',
operator: 'eq',
value: 'high',
minValue: null,
maxValue: null
}
],
actions: [
{
type: 'set_variable',
variable: 'isHighPriority',
value: 'true'
}
]
}
],
backgroundColor: '#fdf4ff',
borderColor: '#a855f7',
textColor: '#7c3aed',
shape: 'rectangle'
}
},
{
id: 'gateway-priority-check',
type: 'gateway',
position: { x: 700, y: 300 },
data: {
label: 'High Priority?',
description: 'Route based on priority',
conditions: [
{
variable: 'isHighPriority',
operator: 'eq',
value: 'true',
output: 'Express Processing'
}
],
defaultPath: 'Standard Processing',
backgroundColor: '#fff7ed',
borderColor: '#f97316',
textColor: '#c2410c',
shape: 'diamond'
}
},
{
id: 'api-express-process',
type: 'api',
position: { x: 900, y: 250 },
data: {
label: 'Express Processing',
description: 'Process high priority order',
apiMethod: 'POST',
apiUrl: '/api/orders/{orderId}/process-express',
requestBody: '{"orderId": "{orderId}", "priority": "high"}',
headers: [
{ key: 'Content-Type', value: 'application/json' }
],
outputVariable: 'processingResult',
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'api-standard-process',
type: 'api',
position: { x: 900, y: 350 },
data: {
label: 'Standard Processing',
description: 'Process regular order',
apiMethod: 'POST',
apiUrl: '/api/orders/{orderId}/process-standard',
requestBody: '{"orderId": "{orderId}", "priority": "normal"}',
headers: [
{ key: 'Content-Type', value: 'application/json' }
],
outputVariable: 'processingResult',
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'notification-complete',
type: 'notification',
position: { x: 1100, y: 300 },
data: {
label: 'Notify Completion',
description: 'Send processing complete notification',
notificationType: 'success',
recipientType: 'email',
recipientEmail: '{orderData.customerEmail}',
subject: 'Order Processing Complete',
message: 'Your order {orderId} has been processed successfully.',
priority: 'medium',
backgroundColor: '#f0f9ff',
borderColor: '#0ea5e9',
textColor: '#0284c7',
shape: 'rectangle'
}
},
{
id: 'end-order',
type: 'end',
position: { x: 1300, y: 300 },
data: {
label: 'Complete',
description: 'Order processing complete',
backgroundColor: '#fee2e2',
borderColor: '#dc2626',
textColor: '#991b1b',
shape: 'circle'
}
}
],
edges: [
{ id: 'e-order-1', source: 'start-order', target: 'api-get-order', sourceHandle: 'start-order-bottom', targetHandle: 'api-get-order-top', type: 'smoothstep' },
{ id: 'e-order-2', source: 'api-get-order', target: 'business-rule-priority', sourceHandle: 'api-get-order-bottom', targetHandle: 'business-rule-priority-top', type: 'smoothstep' },
{ id: 'e-order-3', source: 'business-rule-priority', target: 'gateway-priority-check', sourceHandle: 'business-rule-priority-bottom', targetHandle: 'gateway-priority-check-top', type: 'smoothstep' },
{ id: 'e-order-4', source: 'gateway-priority-check', target: 'api-express-process', sourceHandle: 'gateway-priority-check-right', targetHandle: 'api-express-process-left', type: 'smoothstep', label: 'Express Processing' },
{ id: 'e-order-5', source: 'gateway-priority-check', target: 'api-standard-process', sourceHandle: 'gateway-priority-check-bottom', targetHandle: 'api-standard-process-left', type: 'smoothstep', label: 'Standard Processing' },
{ id: 'e-order-6', source: 'api-express-process', target: 'notification-complete', sourceHandle: 'api-express-process-bottom', targetHandle: 'notification-complete-top', type: 'smoothstep' },
{ id: 'e-order-7', source: 'api-standard-process', target: 'notification-complete', sourceHandle: 'api-standard-process-bottom', targetHandle: 'notification-complete-left', type: 'smoothstep' },
{ id: 'e-order-8', source: 'notification-complete', target: 'end-order', sourceHandle: 'notification-complete-bottom', targetHandle: 'end-order-top', type: 'smoothstep' }
]
},
{
id: 'customer-feedback-analysis',
name: 'Customer Feedback Analysis',
description: 'Automated feedback collection and analysis with sentiment detection and response routing.',
category: 'automation',
complexity: 'Complex',
nodeCount: 8,
edgeCount: 10,
variables: [
{
name: 'customerId',
type: 'string',
scope: 'global',
description: 'Customer ID from URL parameter',
defaultValue: '',
captureFromUrl: true,
urlParameterName: 'customer'
},
{
name: 'feedbackType',
type: 'string',
scope: 'global',
description: 'Type of feedback from URL parameter',
defaultValue: 'general',
captureFromUrl: true,
urlParameterName: 'type'
},
{
name: 'customerData',
type: 'object',
scope: 'global',
description: 'Customer information from API',
defaultValue: {}
},
{
name: 'feedbackData',
type: 'object',
scope: 'global',
description: 'Feedback form submission data',
defaultValue: {}
},
{
name: 'sentimentAnalysis',
type: 'object',
scope: 'global',
description: 'AI sentiment analysis results',
defaultValue: {}
},
{
name: 'isNegativeFeedback',
type: 'boolean',
scope: 'global',
description: 'Whether feedback is negative',
defaultValue: false
},
{
name: 'escalationRequired',
type: 'boolean',
scope: 'global',
description: 'Whether escalation is needed',
defaultValue: false
}
],
nodes: [
{
id: 'start-feedback',
type: 'start',
position: { x: 100, y: 400 },
data: {
label: 'Start Feedback',
description: 'Begin feedback collection process',
backgroundColor: '#dcfce7',
borderColor: '#10b981',
textColor: '#065f46',
shape: 'circle'
}
},
{
id: 'api-get-customer',
type: 'api',
position: { x: 300, y: 400 },
data: {
label: 'Get Customer Info',
description: 'Fetch customer details',
apiMethod: 'GET',
apiUrl: '/api/customers/{customerId}',
headers: [
{ key: 'Content-Type', value: 'application/json' },
{ key: 'Authorization', value: 'Bearer YOUR_API_TOKEN' }
],
outputVariable: 'customerData',
errorVariable: 'customerError',
continueOnError: false,
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'form-feedback',
type: 'form',
position: { x: 500, y: 400 },
data: {
label: 'Feedback Form',
description: 'Collect customer feedback',
formId: null,
formName: 'Customer Feedback Form',
inputMappings: [
{ processVariable: 'customerData.name', formField: 'customerName' },
{ processVariable: 'customerData.email', formField: 'customerEmail' },
{ processVariable: 'feedbackType', formField: 'feedbackCategory' }
],
outputMappings: [
{ formField: 'rating', processVariable: 'feedbackData.rating' },
{ formField: 'comments', processVariable: 'feedbackData.comments' },
{ formField: 'improvementSuggestions', processVariable: 'feedbackData.suggestions' }
],
backgroundColor: '#faf5ff',
borderColor: '#9333ea',
textColor: '#6b21a8',
shape: 'rectangle'
}
},
{
id: 'api-sentiment-analysis',
type: 'api',
position: { x: 700, y: 400 },
data: {
label: 'Analyze Sentiment',
description: 'AI-powered sentiment analysis',
apiMethod: 'POST',
apiUrl: '/api/ai/sentiment-analysis',
requestBody: '{"text": "{feedbackData.comments}", "context": "customer_feedback"}',
headers: [
{ key: 'Content-Type', value: 'application/json' },
{ key: 'X-API-Key', value: 'YOUR_AI_API_KEY' }
],
outputVariable: 'sentimentAnalysis',
backgroundColor: '#eff6ff',
borderColor: '#3b82f6',
textColor: '#1e40af',
shape: 'rectangle'
}
},
{
id: 'business-rule-sentiment',
type: 'business-rule',
position: { x: 900, y: 400 },
data: {
label: 'Evaluate Sentiment',
description: 'Determine if feedback requires escalation',
ruleGroups: [
{
name: 'Negative Sentiment',
conditions: [
{
variable: 'sentimentAnalysis.sentiment',
operator: 'eq',
value: 'negative',
minValue: null,
maxValue: null
}
],
actions: [
{
type: 'set_variable',
variable: 'isNegativeFeedback',
value: 'true'
}
]
},
{
name: 'Low Rating',
conditions: [
{
variable: 'feedbackData.rating',
operator: 'lte',
value: '2',
minValue: null,
maxValue: null
}
],
actions: [
{
type: 'set_variable',
variable: 'escalationRequired',
value: 'true'
}
]
}
],
backgroundColor: '#fdf4ff',
borderColor: '#a855f7',
textColor: '#7c3aed',
shape: 'rectangle'
}
},
{
id: 'gateway-escalation',
type: 'gateway',
position: { x: 1100, y: 400 },
data: {
label: 'Needs Escalation?',
description: 'Check if escalation is required',
conditions: [
{
variable: 'escalationRequired',
operator: 'eq',
value: 'true',
output: 'Escalate'
}
],
defaultPath: 'Standard Response',
backgroundColor: '#fff7ed',
borderColor: '#f97316',
textColor: '#c2410c',
shape: 'diamond'
}
},
{
id: 'notification-escalate',
type: 'notification',
position: { x: 1300, y: 350 },
data: {
label: 'Escalate to Manager',
description: 'Notify manager of negative feedback',
notificationType: 'warning',
recipientType: 'role',
recipientRole: 'customer_success_manager',
subject: 'Urgent: Negative Customer Feedback',
message: 'Customer {customerData.name} has provided negative feedback requiring immediate attention.',
priority: 'high',
backgroundColor: '#f0f9ff',
borderColor: '#0ea5e9',
textColor: '#0284c7',
shape: 'rectangle'
}
},
{
id: 'notification-standard',
type: 'notification',
position: { x: 1300, y: 450 },
data: {
label: 'Thank Customer',
description: 'Send standard thank you message',
notificationType: 'success',
recipientType: 'variable',
recipientVariable: 'customerData.email',
subject: 'Thank you for your feedback',
message: 'Thank you for taking the time to provide feedback. We appreciate your input.',
priority: 'medium',
backgroundColor: '#f0f9ff',
borderColor: '#0ea5e9',
textColor: '#0284c7',
shape: 'rectangle'
}
},
{
id: 'end-feedback',
type: 'end',
position: { x: 1500, y: 400 },
data: {
label: 'Complete',
description: 'Feedback processing complete',
backgroundColor: '#fee2e2',
borderColor: '#dc2626',
textColor: '#991b1b',
shape: 'circle'
}
}
],
edges: [
{ id: 'e-feedback-1', source: 'start-feedback', target: 'api-get-customer', sourceHandle: 'start-feedback-bottom', targetHandle: 'api-get-customer-top', type: 'smoothstep' },
{ id: 'e-feedback-2', source: 'api-get-customer', target: 'form-feedback', sourceHandle: 'api-get-customer-bottom', targetHandle: 'form-feedback-top', type: 'smoothstep' },
{ id: 'e-feedback-3', source: 'form-feedback', target: 'api-sentiment-analysis', sourceHandle: 'form-feedback-bottom', targetHandle: 'api-sentiment-analysis-top', type: 'smoothstep' },
{ id: 'e-feedback-4', source: 'api-sentiment-analysis', target: 'business-rule-sentiment', sourceHandle: 'api-sentiment-analysis-bottom', targetHandle: 'business-rule-sentiment-top', type: 'smoothstep' },
{ id: 'e-feedback-5', source: 'business-rule-sentiment', target: 'gateway-escalation', sourceHandle: 'business-rule-sentiment-bottom', targetHandle: 'gateway-escalation-top', type: 'smoothstep' },
{ id: 'e-feedback-6', source: 'gateway-escalation', target: 'notification-escalate', sourceHandle: 'gateway-escalation-right', targetHandle: 'notification-escalate-left', type: 'smoothstep', label: 'Escalate' },
{ id: 'e-feedback-7', source: 'gateway-escalation', target: 'notification-standard', sourceHandle: 'gateway-escalation-bottom', targetHandle: 'notification-standard-left', type: 'smoothstep', label: 'Standard Response' },
{ id: 'e-feedback-8', source: 'notification-escalate', target: 'end-feedback', sourceHandle: 'notification-escalate-bottom', targetHandle: 'end-feedback-top', type: 'smoothstep' },
{ id: 'e-feedback-9', source: 'notification-standard', target: 'end-feedback', sourceHandle: 'notification-standard-bottom', targetHandle: 'end-feedback-left', type: 'smoothstep' }
]
}
];
@ -1246,7 +2073,8 @@ const getTemplateIcon = (template) => {
'onboarding': 'material-symbols:person-add-outline',
'support': 'material-symbols:support-agent',
'business': 'material-symbols:business-center-outline',
'automation': 'material-symbols:precision-manufacturing-outline'
'automation': 'material-symbols:precision-manufacturing-outline',
'data-driven': 'material-symbols:data-usage'
};
return icons[template.category] || 'material-symbols:account-tree';

View File

@ -479,6 +479,28 @@
help="A clear description helps others understand the purpose of this variable"
/>
<FormKit
name="captureFromUrl"
v-model="variableForm.captureFromUrl"
type="checkbox"
label="Capture from URL Parameters"
help="Enable this to automatically capture the variable value from URL query parameters during workflow execution"
/>
<FormKit
v-if="variableForm.captureFromUrl"
name="urlParameterName"
v-model="variableForm.urlParameterName"
type="text"
label="URL Parameter Name"
placeholder="Enter the URL parameter name (e.g. 'userId' for ?userId=123)"
validation="required"
:validation-messages="{
required: 'URL parameter name is required when capture from URL is enabled',
}"
help="The name of the URL query parameter to capture (without the ? or &)"
/>
<div class="flex justify-end space-x-2 pt-4 border-t border-gray-200">
<RsButton type="button" @click="closeModal" variant="tertiary">
Cancel
@ -512,7 +534,9 @@ const variableForm = ref({
type: "string",
scope: "global",
description: "",
defaultValue: ""
defaultValue: "",
captureFromUrl: false,
urlParameterName: ""
});
// Variable type options with descriptions
@ -1498,7 +1522,9 @@ const resetForm = () => {
type: "string",
scope: "global",
description: "",
defaultValue: ""
defaultValue: "",
captureFromUrl: false,
urlParameterName: ""
};
editingVariable.value = null;
};
@ -1532,7 +1558,9 @@ const saveVariable = async (formData) => {
type: formData.type,
scope: "global",
description: formData.description,
value: processedDefaultValue
value: processedDefaultValue,
captureFromUrl: formData.captureFromUrl || false,
urlParameterName: formData.urlParameterName || ""
};
if (editingVariable.value) {

View File

@ -83,6 +83,84 @@ watch(isProcessComplete, (newValue) => {
}
});
// Capture URL parameters for variables that are configured to do so
const captureUrlParameters = () => {
try {
console.log('[Workflow] Capturing URL parameters...');
// Get current URL parameters
const urlParams = new URLSearchParams(window.location.search);
console.log('[Workflow] Available URL parameters:', Object.fromEntries(urlParams.entries()));
// Check if we have process variables defined
const variableSource = process.value?.variables || process.value?.processVariables;
if (!variableSource) {
console.log('[Workflow] No process variables defined, skipping URL parameter capture');
return;
}
// Iterate through process variables to find ones configured for URL capture
Object.entries(variableSource).forEach(([variableName, variableConfig]) => {
if (variableConfig && variableConfig.captureFromUrl && variableConfig.urlParameterName) {
const paramName = variableConfig.urlParameterName;
const paramValue = urlParams.get(paramName);
if (paramValue !== null) {
// Convert the parameter value based on the variable type
let convertedValue = paramValue;
switch (variableConfig.type) {
case 'number':
case 'int':
case 'decimal':
convertedValue = Number(paramValue);
if (isNaN(convertedValue)) {
console.warn(`[Workflow] Could not convert URL parameter "${paramName}" value "${paramValue}" to number for variable "${variableName}"`);
convertedValue = variableConfig.value || 0; // Use default value
}
break;
case 'boolean':
convertedValue = paramValue.toLowerCase() === 'true' || paramValue === '1';
break;
case 'object':
try {
convertedValue = JSON.parse(paramValue);
} catch (e) {
console.warn(`[Workflow] Could not parse URL parameter "${paramName}" value "${paramValue}" as JSON for variable "${variableName}"`);
convertedValue = variableConfig.value || {}; // Use default value
}
break;
case 'date':
case 'datetime':
const dateValue = new Date(paramValue);
if (isNaN(dateValue.getTime())) {
console.warn(`[Workflow] Could not parse URL parameter "${paramName}" value "${paramValue}" as date for variable "${variableName}"`);
convertedValue = variableConfig.value || null; // Use default value
} else {
convertedValue = variableConfig.type === 'date' ? dateValue.toISOString().split('T')[0] : dateValue.toISOString();
}
break;
case 'string':
default:
convertedValue = String(paramValue);
break;
}
// Set the variable value
processVariables.value[variableName] = convertedValue;
console.log(`[Workflow] Captured URL parameter "${paramName}" = "${paramValue}" -> variable "${variableName}" = `, convertedValue);
} else {
console.log(`[Workflow] URL parameter "${paramName}" not found for variable "${variableName}"`);
}
}
});
console.log('[Workflow] Final process variables after URL capture:', processVariables.value);
} catch (err) {
console.error('[Workflow] Error capturing URL parameters:', err);
}
};
// Load process data
const loadProcess = async () => {
try {
@ -94,7 +172,6 @@ const loadProcess = async () => {
if (response.success) {
process.value = response.process; // includes processDefinition
console.log('[Workflow] Process loaded:', process.value.processName, process.value.processDefinition);
// Check if process is published
const status = process.value.processStatus || process.value.status || 'draft';
@ -103,8 +180,20 @@ const loadProcess = async () => {
return;
}
// Initialize process variables from DB (process.processVariables)
processVariables.value = process.value.processVariables ? { ...process.value.processVariables } : {};
// Initialize process variables from DB - extract values from variable definitions
processVariables.value = {};
// Try both possible property names for variables
const variableSource = process.value.variables || process.value.processVariables;
if (variableSource) {
Object.entries(variableSource).forEach(([name, variableDefinition]) => {
// Set the actual value, defaulting to the variable's default value or empty string
processVariables.value[name] = variableDefinition.value || variableDefinition.defaultValue || '';
});
}
// Capture URL parameters for variables configured to do so
captureUrlParameters();
// Start the process execution (case instance)
await startProcessExecution();

View File

@ -1159,7 +1159,9 @@ export const useProcessBuilderStore = defineStore('processBuilder', {
type: variable.type || 'string',
scope: variable.scope || 'global',
value: variable.value,
description: variable.description || ''
description: variable.description || '',
captureFromUrl: variable.captureFromUrl || false,
urlParameterName: variable.urlParameterName || ''
};
this.unsavedChanges = true;