diff --git a/components/process-flow/NotificationNodeConfiguration.vue b/components/process-flow/NotificationNodeConfiguration.vue new file mode 100644 index 0000000..f599f24 --- /dev/null +++ b/components/process-flow/NotificationNodeConfiguration.vue @@ -0,0 +1,795 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/NotificationNodeConfigurationModal.vue b/components/process-flow/NotificationNodeConfigurationModal.vue new file mode 100644 index 0000000..a069b2c --- /dev/null +++ b/components/process-flow/NotificationNodeConfigurationModal.vue @@ -0,0 +1,113 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/ProcessBuilderComponents.vue b/components/process-flow/ProcessBuilderComponents.vue index 7ff7f53..dcd7a65 100644 --- a/components/process-flow/ProcessBuilderComponents.vue +++ b/components/process-flow/ProcessBuilderComponents.vue @@ -119,22 +119,6 @@ const availableComponents = [ } } }, - { - type: 'business-rule', - name: 'Business Rule', - category: 'Core', - icon: 'material-symbols:rule', - description: 'Apply business rules to process data', - defaultProps: { - label: 'Business Rule', - data: { - description: 'Applies business rules to process data', - conditions: [], - actions: [], - priority: 'medium' - } - } - }, { type: 'gateway', name: 'Decision Point', @@ -149,6 +133,69 @@ const availableComponents = [ defaultPath: 'Default' } } + }, + { + type: 'notification', + name: 'Notification', + category: 'Core', + icon: 'material-symbols:notifications-outline', + description: 'Send notifications to users', + defaultProps: { + label: 'Notification', + data: { + description: 'Send notification to users', + notificationType: 'info', + recipientType: 'user', + recipientUser: '', + recipientRole: '', + recipientVariable: '', + recipientEmail: '', + subject: '', + message: '', + priority: 'medium', + deliveryOptions: { + inApp: true, + email: false, + sms: false + }, + expiration: { + enabled: false, + value: 24, + unit: 'hours' + } + } + } + }, + // Advanced components + { + type: 'script', + name: 'Script Task', + category: 'Advanced', + icon: 'material-symbols:code', + description: 'Execute custom code', + defaultProps: { + label: 'Script', + data: { + description: 'Script execution', + language: 'JavaScript', + script: '' + } + } + }, + { + type: 'business-rule', + name: 'Business Rule', + category: 'Advanced', + icon: 'material-symbols:rule', + description: 'Apply business rules to data', + defaultProps: { + label: 'Business Rule', + data: { + description: 'Apply business rules', + ruleGroups: [], + priority: 'medium' + } + } } ]; diff --git a/components/process-flow/ProcessFlowNodes.js b/components/process-flow/ProcessFlowNodes.js index ee3ee1c..03f1f2a 100644 --- a/components/process-flow/ProcessFlowNodes.js +++ b/components/process-flow/ProcessFlowNodes.js @@ -484,6 +484,87 @@ export const BusinessRuleNode = markRaw({ } }); +// Notification node +export const NotificationNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + computed: { + nodeLabel() { + // Get label from either prop or data, with fallback + return this.label || (this.data && this.data.label) || 'Notification'; + }, + notificationType() { + return this.data?.notificationType || 'info'; + }, + notificationTypeIcon() { + const types = { + info: 'material-symbols:info-outline', + success: 'material-symbols:check-circle-outline', + warning: 'material-symbols:warning-outline', + error: 'material-symbols:error-outline' + }; + return types[this.notificationType] || types.info; + }, + notificationTypeColor() { + const colors = { + info: 'text-blue-500', + success: 'text-green-500', + warning: 'text-yellow-500', + error: 'text-red-500' + }; + return colors[this.notificationType] || colors.info; + }, + recipientType() { + return this.data?.recipientType || 'user'; + }, + recipientLabel() { + const types = { + user: 'User', + role: 'Role', + variable: 'Variable', + email: 'Email' + }; + return types[this.recipientType] || 'User'; + }, + isConfigured() { + // Check if notification has required fields + return !!(this.data?.subject && this.data?.message); + } + }, + render() { + return h(CustomNode, { + id: this.id, + type: 'notification', + label: this.nodeLabel, + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: `material-icons ${this.notificationTypeColor}` }, 'notifications'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Send notification'), + h('div', { class: 'node-rule-detail flex items-center justify-between text-xs mt-1' }, [ + h('span', { class: 'node-rule-detail-label' }, 'Type:'), + h('span', { + class: `node-rule-detail-value ml-1 font-medium ${this.notificationTypeColor}` + }, this.notificationType.charAt(0).toUpperCase() + this.notificationType.slice(1)) + ]), + h('div', { class: 'node-rule-detail flex items-center justify-between text-xs mt-1' }, [ + h('span', { class: 'node-rule-detail-label' }, 'Recipient:'), + h('span', { + class: 'node-rule-detail-value ml-1 font-medium text-blue-600' + }, this.recipientLabel) + ]), + h('div', { class: 'node-rule-detail flex items-center justify-between text-xs mt-1' }, [ + h('span', { class: 'node-rule-detail-label' }, 'Status:'), + h('span', { + class: this.isConfigured ? 'node-rule-detail-value ml-1 font-medium text-green-600' : 'node-rule-detail-value ml-1 font-medium text-red-600' + }, this.isConfigured ? 'Configured' : 'Not configured') + ]) + ]) + }); + } +}); + // Export the node types object to use with Vue Flow export const nodeTypes = markRaw({ task: TaskNode, @@ -493,7 +574,8 @@ export const nodeTypes = markRaw({ form: FormNode, script: ScriptNode, 'business-rule': BusinessRuleNode, - api: ApiCallNode + api: ApiCallNode, + notification: NotificationNode }); // Default CSS for the nodes to be imported where needed diff --git a/components/process-flow/notification/NotificationLogs.vue b/components/process-flow/notification/NotificationLogs.vue new file mode 100644 index 0000000..7c6f693 --- /dev/null +++ b/components/process-flow/notification/NotificationLogs.vue @@ -0,0 +1,509 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/notification/NotificationManager.vue b/components/process-flow/notification/NotificationManager.vue new file mode 100644 index 0000000..bb006f6 --- /dev/null +++ b/components/process-flow/notification/NotificationManager.vue @@ -0,0 +1,746 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/notification/NotificationQueue.vue b/components/process-flow/notification/NotificationQueue.vue new file mode 100644 index 0000000..0b2d06f --- /dev/null +++ b/components/process-flow/notification/NotificationQueue.vue @@ -0,0 +1,527 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/notification/NotificationTemplates.vue b/components/process-flow/notification/NotificationTemplates.vue new file mode 100644 index 0000000..b8df5d4 --- /dev/null +++ b/components/process-flow/notification/NotificationTemplates.vue @@ -0,0 +1,579 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/notification/NotificationTriggers.vue b/components/process-flow/notification/NotificationTriggers.vue new file mode 100644 index 0000000..6e4d863 --- /dev/null +++ b/components/process-flow/notification/NotificationTriggers.vue @@ -0,0 +1,620 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/notification/UserPreferences.vue b/components/process-flow/notification/UserPreferences.vue new file mode 100644 index 0000000..39af777 --- /dev/null +++ b/components/process-flow/notification/UserPreferences.vue @@ -0,0 +1,315 @@ + + + + + \ No newline at end of file diff --git a/pages/notifications/index.vue b/pages/notifications/index.vue new file mode 100644 index 0000000..110a65d --- /dev/null +++ b/pages/notifications/index.vue @@ -0,0 +1,75 @@ + + + + + \ No newline at end of file diff --git a/pages/process-builder/index.vue b/pages/process-builder/index.vue index d836a0d..5abbd07 100644 --- a/pages/process-builder/index.vue +++ b/pages/process-builder/index.vue @@ -17,6 +17,7 @@ import FormNodeConfigurationModal from '~/components/process-flow/FormNodeConfig import TaskNodeConfiguration from '~/components/process-flow/TaskNodeConfiguration.vue'; import BusinessRuleNodeConfiguration from '~/components/process-flow/BusinessRuleNodeConfiguration.vue'; import BusinessRuleNodeConfigurationModal from '~/components/process-flow/BusinessRuleNodeConfigurationModal.vue'; +import NotificationNodeConfigurationModal from '~/components/process-flow/NotificationNodeConfigurationModal.vue'; // Define page meta definePageMeta({ @@ -64,6 +65,7 @@ const showFormConfigModal = ref(false); const showApiConfigModal = ref(false); const showGatewayConfigModal = ref(false); const showBusinessRuleConfigModal = ref(false); +const showNotificationConfigModal = ref(false); // Component definitions const components = [ @@ -717,6 +719,14 @@ const handleDefaultPathUpdate = (path) => { updateNodeInStore(); } }; + +// Handle notification node update +const handleNotificationNodeUpdate = (updatedData) => { + if (selectedNodeData.value) { + selectedNodeData.value.data = { ...updatedData }; + updateNodeInStore(); + } +}; @@ -1020,6 +1046,13 @@ const handleDefaultPathUpdate = (path) => { border-left: 4px solid #9333ea; /* Purple border to match our icon color */ } +:deep(.node-notification) { + min-width: 160px; + background: white; + border: 1px solid #ddd; + border-left: 4px solid #3b82f6; /* Blue border to match our icon color */ +} + :deep(.node-details) { margin-top: 8px; font-size: 0.75rem;