@flowuent-org/diagramming-core 1.4.3 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ import React from 'react';
2
+ import { Box, Typography } from '@mui/material';
3
+ import { useTranslation } from 'react-i18next';
4
+ import {
5
+ AutomationAIReasoning,
6
+ AutomationConfigurationCard,
7
+ AutomationConfigurationCardType,
8
+ } from '../../types/automation-node-data-types';
9
+
10
+ const CONFIGURATION_CARD_ICONS: Record<
11
+ AutomationConfigurationCardType,
12
+ { icon: string; defaultColor: string }
13
+ > = {
14
+ model: { icon: '⚙️', defaultColor: '#ffffff' },
15
+ knowledgeBase: { icon: '🗄️', defaultColor: '#10b981' },
16
+ };
17
+
18
+ interface AutomationAIReasoningSectionProps {
19
+ aiReasoning?: AutomationAIReasoning;
20
+ }
21
+
22
+ export const AutomationAIReasoningSection: React.FC<
23
+ AutomationAIReasoningSectionProps
24
+ > = ({ aiReasoning }) => {
25
+ const { t } = useTranslation();
26
+ const text = aiReasoning?.text?.trim();
27
+
28
+ if (!text) {
29
+ return null;
30
+ }
31
+
32
+ return (
33
+ <Box
34
+ sx={{
35
+ backgroundColor: '#1F2937',
36
+ borderRadius: '8px',
37
+ padding: '12px',
38
+ mb: 2,
39
+ border: '1px solid #374151',
40
+ }}
41
+ >
42
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
43
+ <Box sx={{ color: '#34D399', fontSize: '16px' }}>🧠</Box>
44
+ <Typography
45
+ variant="body2"
46
+ sx={{ color: '#34D399', fontSize: '12px', fontWeight: 600 }}
47
+ >
48
+ {t('automation.formattingNode.aiReasoning')}
49
+ </Typography>
50
+ </Box>
51
+
52
+ <Box
53
+ sx={{
54
+ backgroundColor: 'transparent',
55
+ borderRadius: '4px',
56
+ padding: '8px',
57
+ border: '1px solid #4B5563',
58
+ minHeight: '40px',
59
+ display: 'flex',
60
+ alignItems: 'center',
61
+ }}
62
+ >
63
+ <Typography
64
+ variant="body2"
65
+ sx={{
66
+ color: '#9CA3AF',
67
+ fontSize: '12px',
68
+ lineHeight: 1.4,
69
+ margin: 0,
70
+ }}
71
+ >
72
+ {text}
73
+ </Typography>
74
+ </Box>
75
+ </Box>
76
+ );
77
+ };
78
+
79
+ interface AutomationConfigurationCardsSectionProps {
80
+ configurationCards?: AutomationConfigurationCard[];
81
+ }
82
+
83
+ export const AutomationConfigurationCardsSection: React.FC<
84
+ AutomationConfigurationCardsSectionProps
85
+ > = ({ configurationCards }) => {
86
+ const configuredCards = (configurationCards ?? []).filter(
87
+ (card) => card.type && card.label?.trim(),
88
+ );
89
+
90
+ if (configuredCards.length === 0) {
91
+ return null;
92
+ }
93
+
94
+ return (
95
+ <>
96
+ {configuredCards.map((card, index) => {
97
+ const iconConfig = CONFIGURATION_CARD_ICONS[card.type];
98
+
99
+ return (
100
+ <Box
101
+ key={`${card.type}-${index}`}
102
+ sx={{
103
+ backgroundColor: '#1F2937',
104
+ borderRadius: '6px',
105
+ padding: '8px 12px',
106
+ mb: 1,
107
+ display: 'flex',
108
+ alignItems: 'center',
109
+ gap: 1,
110
+ border: '1px solid #374151',
111
+ }}
112
+ >
113
+ <Box
114
+ sx={{
115
+ color: card.iconColor || iconConfig.defaultColor,
116
+ fontSize: '16px',
117
+ }}
118
+ >
119
+ {iconConfig.icon}
120
+ </Box>
121
+ <Typography
122
+ variant="body2"
123
+ sx={{ color: '#ffffff', fontSize: '11px', fontWeight: 500 }}
124
+ >
125
+ {card.label}
126
+ </Typography>
127
+ </Box>
128
+ );
129
+ })}
130
+ </>
131
+ );
132
+ };
@@ -0,0 +1,158 @@
1
+ import React from 'react';
2
+ import {
3
+ Send as SendIcon,
4
+ Email as EmailIcon,
5
+ Search as SearchIcon,
6
+ Description as DescriptionIcon,
7
+ Edit as EditIcon,
8
+ Slideshow as SlideshowIcon,
9
+ VideoCall as VideoCallIcon,
10
+ Event as EventIcon,
11
+ Link as LinkIcon,
12
+ } from '@mui/icons-material';
13
+ import { SiGmail, SiGoogledocs, SiGoogleslides, SiGooglemeet } from 'react-icons/si';
14
+
15
+ export type GoogleServiceType = 'gmail' | 'docs' | 'slides' | 'meet';
16
+
17
+ export interface GoogleOperationConfig {
18
+ icon: React.ElementType;
19
+ label: string;
20
+ color: string;
21
+ description: string;
22
+ }
23
+
24
+ export interface GoogleServiceConfig {
25
+ serviceType: GoogleServiceType;
26
+ serviceLabel: string;
27
+ brandColor: string;
28
+ iconBgColor: string;
29
+ BrandIcon: React.ComponentType<{ size?: number }>;
30
+ scopes: string[];
31
+ defaultOperation: string;
32
+ operations: Record<string, GoogleOperationConfig>;
33
+ }
34
+
35
+ export const GOOGLE_SERVICE_CONFIGS: Record<GoogleServiceType, GoogleServiceConfig> = {
36
+ gmail: {
37
+ serviceType: 'gmail',
38
+ serviceLabel: 'Gmail',
39
+ brandColor: '#EA4335',
40
+ iconBgColor: '#B31412',
41
+ BrandIcon: SiGmail,
42
+ scopes: [
43
+ 'https://www.googleapis.com/auth/gmail.send',
44
+ 'https://www.googleapis.com/auth/gmail.readonly',
45
+ ],
46
+ defaultOperation: 'send-email',
47
+ operations: {
48
+ 'send-email': {
49
+ icon: SendIcon,
50
+ label: 'Send Email',
51
+ color: '#EA4335',
52
+ description: 'Send an email via Gmail',
53
+ },
54
+ 'read-email': {
55
+ icon: EmailIcon,
56
+ label: 'Read Email',
57
+ color: '#4285F4',
58
+ description: 'Read messages from inbox',
59
+ },
60
+ 'search-emails': {
61
+ icon: SearchIcon,
62
+ label: 'Search Emails',
63
+ color: '#34A853',
64
+ description: 'Search emails by query',
65
+ },
66
+ },
67
+ },
68
+ docs: {
69
+ serviceType: 'docs',
70
+ serviceLabel: 'Google Docs',
71
+ brandColor: '#4285F4',
72
+ iconBgColor: '#1967D2',
73
+ BrandIcon: SiGoogledocs,
74
+ scopes: ['https://www.googleapis.com/auth/documents'],
75
+ defaultOperation: 'create-document',
76
+ operations: {
77
+ 'create-document': {
78
+ icon: DescriptionIcon,
79
+ label: 'Create Document',
80
+ color: '#4285F4',
81
+ description: 'Create a new Google Doc',
82
+ },
83
+ 'read-document': {
84
+ icon: DescriptionIcon,
85
+ label: 'Read Document',
86
+ color: '#34A853',
87
+ description: 'Read content from a document',
88
+ },
89
+ 'update-document': {
90
+ icon: EditIcon,
91
+ label: 'Update Document',
92
+ color: '#FBBC04',
93
+ description: 'Update document content',
94
+ },
95
+ },
96
+ },
97
+ slides: {
98
+ serviceType: 'slides',
99
+ serviceLabel: 'Google Slides',
100
+ brandColor: '#FBBC04',
101
+ iconBgColor: '#F29900',
102
+ BrandIcon: SiGoogleslides,
103
+ scopes: ['https://www.googleapis.com/auth/presentations'],
104
+ defaultOperation: 'create-presentation',
105
+ operations: {
106
+ 'create-presentation': {
107
+ icon: SlideshowIcon,
108
+ label: 'Create Presentation',
109
+ color: '#FBBC04',
110
+ description: 'Create a new Google Slides deck',
111
+ },
112
+ 'read-presentation': {
113
+ icon: SlideshowIcon,
114
+ label: 'Read Presentation',
115
+ color: '#4285F4',
116
+ description: 'Read slides from a presentation',
117
+ },
118
+ 'update-slides': {
119
+ icon: EditIcon,
120
+ label: 'Update Slides',
121
+ color: '#EA4335',
122
+ description: 'Update slide content',
123
+ },
124
+ },
125
+ },
126
+ meet: {
127
+ serviceType: 'meet',
128
+ serviceLabel: 'Google Meet',
129
+ brandColor: '#00897B',
130
+ iconBgColor: '#00796B',
131
+ BrandIcon: SiGooglemeet,
132
+ scopes: [
133
+ 'https://www.googleapis.com/auth/calendar',
134
+ 'https://www.googleapis.com/auth/calendar.events',
135
+ ],
136
+ defaultOperation: 'create-meeting',
137
+ operations: {
138
+ 'create-meeting': {
139
+ icon: VideoCallIcon,
140
+ label: 'Create Meeting',
141
+ color: '#00897B',
142
+ description: 'Create an instant Google Meet link',
143
+ },
144
+ 'schedule-meeting': {
145
+ icon: EventIcon,
146
+ label: 'Schedule Meeting',
147
+ color: '#4285F4',
148
+ description: 'Schedule a calendar event with Meet',
149
+ },
150
+ 'get-meeting-link': {
151
+ icon: LinkIcon,
152
+ label: 'Get Meeting Link',
153
+ color: '#34A853',
154
+ description: 'Retrieve an existing Meet link',
155
+ },
156
+ },
157
+ },
158
+ };
@@ -25,6 +25,20 @@ export type {
25
25
  AutomationTelegramNodeData,
26
26
  AutomationTelegramNodeProps,
27
27
  } from './AutomationTelegramNode';
28
+ // Google Integration Nodes
29
+ export {
30
+ AutomationGmailNode,
31
+ AutomationGoogleDocsNode,
32
+ AutomationGoogleSlidesNode,
33
+ AutomationGoogleMeetNode,
34
+ AutomationGoogleServiceNode,
35
+ } from './AutomationGoogleServiceNode';
36
+ export type {
37
+ AutomationGoogleServiceNodeData,
38
+ AutomationGoogleServiceNodeProps,
39
+ } from './AutomationGoogleServiceNode';
40
+ export type { GoogleServiceType } from './googleServiceNodeConfig';
41
+ export { GOOGLE_SERVICE_CONFIGS } from './googleServiceNodeConfig';
28
42
  // Interaction Node
29
43
  export { AutomationInteractionNode } from './AutomationInteractionNode';
30
44
  export type {
@@ -0,0 +1,149 @@
1
+ // Google Identity Services OAuth helper for automation nodes
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ declare const google: any;
5
+
6
+ export interface GoogleAuthResult {
7
+ accessToken: string;
8
+ expiresAt?: number;
9
+ email?: string;
10
+ userName?: string;
11
+ userId?: string;
12
+ scopes: string[];
13
+ }
14
+
15
+ export class GoogleAuthService {
16
+ private gisLoaded = false;
17
+ private hasRequestedConsent = false;
18
+ private accessToken: string | null = null;
19
+ private expiresAt: number | undefined;
20
+ private requestedScopes = new Set<string>();
21
+
22
+ async connect(clientId: string, scopes: string[]): Promise<GoogleAuthResult> {
23
+ if (typeof window === 'undefined') {
24
+ throw new Error('Google OAuth is only available in browser environments');
25
+ }
26
+
27
+ await this.ensureGisLoaded();
28
+ const token = await this.requestAccessToken(clientId, scopes);
29
+ const userInfo = await this.fetchUserInfo(token);
30
+
31
+ return {
32
+ accessToken: token,
33
+ expiresAt: this.expiresAt,
34
+ email: userInfo.email,
35
+ userName: userInfo.name,
36
+ userId: userInfo.id,
37
+ scopes,
38
+ };
39
+ }
40
+
41
+ disconnect(): void {
42
+ if (this.accessToken && typeof google !== 'undefined') {
43
+ try {
44
+ google.accounts.oauth2.revoke(this.accessToken, () => undefined);
45
+ } catch {
46
+ // Ignore revoke failures in demo environments
47
+ }
48
+ }
49
+
50
+ this.accessToken = null;
51
+ this.expiresAt = undefined;
52
+ }
53
+
54
+ private async ensureGisLoaded(): Promise<void> {
55
+ if (this.gisLoaded) return;
56
+
57
+ await new Promise<void>((resolve, reject) => {
58
+ const existing = document.querySelector(
59
+ 'script[src="https://accounts.google.com/gsi/client"]',
60
+ );
61
+ if (existing) {
62
+ this.gisLoaded = true;
63
+ resolve();
64
+ return;
65
+ }
66
+
67
+ const script = document.createElement('script');
68
+ script.src = 'https://accounts.google.com/gsi/client';
69
+ script.async = true;
70
+ script.defer = true;
71
+ script.onload = () => {
72
+ this.gisLoaded = true;
73
+ resolve();
74
+ };
75
+ script.onerror = () => reject(new Error('Failed to load Google Identity Services'));
76
+ document.head.appendChild(script);
77
+ });
78
+ }
79
+
80
+ private async requestAccessToken(
81
+ clientId: string,
82
+ scopes: string[],
83
+ forceConsent = false,
84
+ ): Promise<string> {
85
+ await this.ensureGisLoaded();
86
+
87
+ const token = await new Promise<string>((resolve, reject) => {
88
+ try {
89
+ const tokenClient = google.accounts.oauth2.initTokenClient({
90
+ client_id: clientId,
91
+ scope: scopes.join(' '),
92
+ callback: (response: {
93
+ access_token?: string;
94
+ expires_in?: number;
95
+ error?: string;
96
+ error_description?: string;
97
+ }) => {
98
+ if (response?.access_token) {
99
+ this.hasRequestedConsent = true;
100
+ scopes.forEach((scope) => this.requestedScopes.add(scope));
101
+ if (response.expires_in) {
102
+ this.expiresAt = Date.now() + response.expires_in * 1000;
103
+ }
104
+ resolve(response.access_token);
105
+ return;
106
+ }
107
+
108
+ const err = response?.error || 'unknown_error';
109
+ const desc = response?.error_description || 'No description';
110
+ reject(new Error(`OAuth token error: ${err} - ${desc}`));
111
+ },
112
+ });
113
+
114
+ tokenClient.requestAccessToken({
115
+ prompt: forceConsent
116
+ ? 'consent'
117
+ : this.hasRequestedConsent
118
+ ? ''
119
+ : 'consent',
120
+ });
121
+ } catch (error) {
122
+ reject(error);
123
+ }
124
+ });
125
+
126
+ this.accessToken = token;
127
+ return token;
128
+ }
129
+
130
+ private async fetchUserInfo(accessToken: string): Promise<{
131
+ email?: string;
132
+ name?: string;
133
+ id?: string;
134
+ }> {
135
+ const response = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
136
+ headers: {
137
+ Authorization: `Bearer ${accessToken}`,
138
+ },
139
+ });
140
+
141
+ if (!response.ok) {
142
+ return {};
143
+ }
144
+
145
+ return response.json();
146
+ }
147
+ }
148
+
149
+ export const googleAuthService = new GoogleAuthService();
@@ -566,9 +566,6 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
566
566
  ref={setNodeRef}
567
567
  sx={{ height: '100svh', width: '100svw', position: 'relative' }}
568
568
  >
569
- {/* Redo Toolbar */}
570
-
571
-
572
569
  <ReactFlow
573
570
  panOnDrag={isPannable}
574
571
  nodesDraggable={isPannable}
@@ -1,4 +1,16 @@
1
1
  // Automation Node Data Types
2
+ export type AutomationConfigurationCardType = 'model' | 'knowledgeBase';
3
+
4
+ export interface AutomationConfigurationCard {
5
+ type: AutomationConfigurationCardType;
6
+ label: string;
7
+ iconColor?: string;
8
+ }
9
+
10
+ export interface AutomationAIReasoning {
11
+ text: string;
12
+ }
13
+
2
14
  export interface AutomationNodeFormData {
3
15
  nodeId: string;
4
16
  title: string;
@@ -26,6 +38,13 @@ export interface AutomationNodeFormData {
26
38
  value: string | number | boolean;
27
39
  }>;
28
40
  };
41
+ aiReasoning?: AutomationAIReasoning;
42
+ configurationCards?: AutomationConfigurationCard[];
43
+ schemaMatch?: {
44
+ matched: number;
45
+ partial: number;
46
+ ignored: number;
47
+ };
29
48
  // Execution result storage
30
49
  executionResult?: {
31
50
  success: boolean;
@@ -12,6 +12,10 @@ import {
12
12
  AutomationNavigationNode,
13
13
  AutomationSlackNode,
14
14
  AutomationTelegramNode,
15
+ AutomationGmailNode,
16
+ AutomationGoogleDocsNode,
17
+ AutomationGoogleSlidesNode,
18
+ AutomationGoogleMeetNode,
15
19
  AutomationInteractionNode,
16
20
  AutomationMonitoringNode,
17
21
  AutomationDecisionNode,
@@ -34,6 +38,10 @@ const nodeTypes = {
34
38
  AutomationNavigationNode,
35
39
  AutomationSlackNode,
36
40
  AutomationTelegramNode,
41
+ AutomationGmailNode,
42
+ AutomationGoogleDocsNode,
43
+ AutomationGoogleSlidesNode,
44
+ AutomationGoogleMeetNode,
37
45
  AutomationInteractionNode,
38
46
  AutomationMonitoringNode,
39
47
  AutomationDecisionNode,