flowengine-mcp-app 1.0.0

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,200 @@
1
+ /**
2
+ * UI Builder - Forms, Chatbots, and Interactive Components
3
+ */
4
+ import { baseLayout, renderEmptyState } from './base.js';
5
+ export function renderWidgetBuilder(widgets, instanceId) {
6
+ if (!widgets || widgets.length === 0) {
7
+ return baseLayout('UI Builder', `
8
+ <div class="header">
9
+ <h1>🎨 UI Builder</h1>
10
+ <p>Create and manage forms, chatbots, and interactive components</p>
11
+ </div>
12
+ ${renderEmptyState('No Components Found', 'You don\'t have any UI components yet. Create your first form, chatbot, or interactive element to engage with your users.')}
13
+ `);
14
+ }
15
+ const activeCount = widgets.filter((w) => w.is_active).length;
16
+ const totalSubmissions = widgets.reduce((sum, w) => sum + (w.submissions_count || 0), 0);
17
+ const widgetCards = widgets
18
+ .map((widget) => {
19
+ const statusBadge = widget.is_active
20
+ ? '<span class="badge badge-success"><span class="dot dot-success"></span>Live</span>'
21
+ : '<span class="badge badge-neutral"><span class="dot dot-neutral"></span>Draft</span>';
22
+ const typeIcon = getWidgetTypeIcon(widget.widget_type);
23
+ const typeBadge = getWidgetTypeBadge(widget.widget_type);
24
+ return `
25
+ <div class="card">
26
+ <div class="card-header">
27
+ <div>
28
+ <div class="card-title">${typeIcon} ${widget.name}</div>
29
+ <div class="card-subtitle">ID: ${widget.id.slice(0, 8)}...</div>
30
+ </div>
31
+ ${statusBadge}
32
+ </div>
33
+
34
+ <div>
35
+ <div class="stat">
36
+ <span class="stat-label">Type</span>
37
+ <span class="stat-value">${typeBadge}</span>
38
+ </div>
39
+ <div class="stat">
40
+ <span class="stat-label">Submissions</span>
41
+ <span class="stat-value">${widget.submissions_count || 0}</span>
42
+ </div>
43
+ <div class="stat">
44
+ <span class="stat-label">Webhook</span>
45
+ <span class="stat-value"><span class="code">${truncateUrl(widget.webhook_url)}</span></span>
46
+ </div>
47
+ <div class="stat">
48
+ <span class="stat-label">Created</span>
49
+ <span class="stat-value">${new Date(widget.created_at).toLocaleDateString()}</span>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="actions">
54
+ <button class="btn btn-primary">Edit</button>
55
+ <button class="btn btn-secondary">Preview</button>
56
+ <button class="btn btn-secondary">Get Embed Code</button>
57
+ </div>
58
+ </div>
59
+ `;
60
+ })
61
+ .join('');
62
+ return baseLayout('UI Builder', `
63
+ <div class="header">
64
+ <h1>🎨 UI Builder</h1>
65
+ <p>${widgets.length} components • ${activeCount} live • ${totalSubmissions.toLocaleString()} total submissions</p>
66
+ </div>
67
+
68
+ <div class="grid">
69
+ ${widgetCards}
70
+ </div>
71
+
72
+ <div class="card">
73
+ <h3 style="margin-bottom: 12px;">Create New Component</h3>
74
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px;">
75
+ <button class="btn btn-primary">📝 Form</button>
76
+ <button class="btn btn-secondary">💬 Chatbot</button>
77
+ <button class="btn btn-secondary">📋 Survey</button>
78
+ <button class="btn btn-secondary">📞 Contact Form</button>
79
+ </div>
80
+ </div>
81
+ `);
82
+ }
83
+ export function renderWidgetDetails(widget) {
84
+ const statusBadge = widget.is_active
85
+ ? '<span class="badge badge-success">Live</span>'
86
+ : '<span class="badge badge-neutral">Draft</span>';
87
+ const typeIcon = getWidgetTypeIcon(widget.widget_type);
88
+ const embedCode = generateEmbedCode(widget.id);
89
+ return baseLayout(`${widget.name}`, `
90
+ <div class="header">
91
+ <h1>${typeIcon} ${widget.name}</h1>
92
+ <p>Component ID: <span class="code">${widget.id}</span> • ${statusBadge}</p>
93
+ </div>
94
+
95
+ <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 24px;">
96
+ <div class="card">
97
+ <div class="stat">
98
+ <span class="stat-label">Type</span>
99
+ <span class="stat-value">${getWidgetTypeBadge(widget.widget_type)}</span>
100
+ </div>
101
+ </div>
102
+ <div class="card">
103
+ <div class="stat">
104
+ <span class="stat-label">Status</span>
105
+ <span class="stat-value">${statusBadge}</span>
106
+ </div>
107
+ </div>
108
+ <div class="card">
109
+ <div class="stat">
110
+ <span class="stat-label">Submissions</span>
111
+ <span class="stat-value">${widget.submissions_count || 0}</span>
112
+ </div>
113
+ </div>
114
+ <div class="card">
115
+ <div class="stat">
116
+ <span class="stat-label">Last Updated</span>
117
+ <span class="stat-value">${new Date(widget.updated_at).toLocaleDateString()}</span>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <div class="card" style="margin-bottom: 24px;">
123
+ <h3 style="margin-bottom: 16px;">Webhook Configuration</h3>
124
+ <div class="stat">
125
+ <span class="stat-label">Webhook URL</span>
126
+ <span class="stat-value"><span class="code">${widget.webhook_url}</span></span>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="card" style="margin-bottom: 24px;">
131
+ <h3 style="margin-bottom: 16px;">Embed Code</h3>
132
+ <div style="background: rgba(38, 38, 38, 0.5); border: 1px solid #262626; border-radius: 8px; padding: 16px; font-family: monospace; font-size: 13px; overflow-x: auto;">
133
+ <pre style="margin: 0; color: #22c55e;">${escapeHtml(embedCode)}</pre>
134
+ </div>
135
+ <button class="btn btn-secondary" style="margin-top: 12px;">📋 Copy Embed Code</button>
136
+ </div>
137
+
138
+ ${widget.config ? renderWidgetConfig(widget.config) : ''}
139
+
140
+ <div class="actions">
141
+ <button class="btn btn-primary">Edit</button>
142
+ <button class="btn btn-secondary">Preview</button>
143
+ ${widget.is_active ? '<button class="btn btn-secondary">Unpublish</button>' : '<button class="btn btn-primary">Publish</button>'}
144
+ <button class="btn btn-danger">Delete</button>
145
+ </div>
146
+ `);
147
+ }
148
+ function getWidgetTypeIcon(type) {
149
+ const icons = {
150
+ form: '📝',
151
+ chat: '💬',
152
+ chatbot: '🤖',
153
+ survey: '📋',
154
+ contact: '📞',
155
+ booking: '📅',
156
+ custom: '⚙️',
157
+ };
158
+ return icons[type.toLowerCase()] || '🎨';
159
+ }
160
+ function getWidgetTypeBadge(type) {
161
+ const typeMap = {
162
+ form: 'Form',
163
+ chat: 'Chat',
164
+ chatbot: 'Chatbot',
165
+ survey: 'Survey',
166
+ contact: 'Contact',
167
+ booking: 'Booking',
168
+ custom: 'Custom',
169
+ };
170
+ const displayName = typeMap[type.toLowerCase()] || type;
171
+ return `<span class="code">${displayName}</span>`;
172
+ }
173
+ function truncateUrl(url) {
174
+ if (url.length <= 40)
175
+ return url;
176
+ return url.slice(0, 37) + '...';
177
+ }
178
+ function generateEmbedCode(widgetId) {
179
+ return `<!-- FlowEngine Widget -->
180
+ <div id="flowengine-widget-${widgetId}"></div>
181
+ <script src="https://flowengine.cloud/widget.js"></script>
182
+ <script>
183
+ FlowEngine.init('${widgetId}');
184
+ </script>`;
185
+ }
186
+ function escapeHtml(html) {
187
+ return html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
188
+ }
189
+ function renderWidgetConfig(config) {
190
+ const configJson = JSON.stringify(config, null, 2);
191
+ return `
192
+ <div class="card" style="margin-bottom: 24px;">
193
+ <h3 style="margin-bottom: 16px;">Configuration</h3>
194
+ <div style="background: rgba(38, 38, 38, 0.5); border: 1px solid #262626; border-radius: 8px; padding: 16px; font-family: monospace; font-size: 13px; overflow-x: auto; max-height: 300px; overflow-y: auto;">
195
+ <pre style="margin: 0; color: #a3a3a3;">${escapeHtml(configJson)}</pre>
196
+ </div>
197
+ </div>
198
+ `;
199
+ }
200
+ //# sourceMappingURL=widgets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widgets.js","sourceRoot":"","sources":["../../src/ui/widgets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Workflows Manager UI
3
+ */
4
+ export interface Workflow {
5
+ id: string;
6
+ name: string;
7
+ active: boolean;
8
+ created_at: string;
9
+ updated_at: string;
10
+ executions_count?: number;
11
+ last_execution_status?: string;
12
+ last_execution_at?: string;
13
+ tags?: string[];
14
+ }
15
+ export declare function renderWorkflowsManager(workflows: Workflow[], instanceId?: string): string;
16
+ export declare function renderWorkflowDetails(workflow: Workflow, executions: any[]): string;
17
+ //# sourceMappingURL=workflows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/ui/workflows.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAgGzF;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,MAAM,CAuDnF"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Workflows Manager UI
3
+ */
4
+ import { baseLayout, renderEmptyState } from './base.js';
5
+ export function renderWorkflowsManager(workflows, instanceId) {
6
+ if (!workflows || workflows.length === 0) {
7
+ return baseLayout('Workflows', `
8
+ <div class="header">
9
+ <h1>⚡ Workflows</h1>
10
+ <p>Manage your automation workflows</p>
11
+ </div>
12
+ ${renderEmptyState('No Workflows Found', 'You don\'t have any workflows yet. Create your first workflow to automate your processes.')}
13
+ `);
14
+ }
15
+ const activeCount = workflows.filter((w) => w.active).length;
16
+ const totalExecutions = workflows.reduce((sum, w) => sum + (w.executions_count || 0), 0);
17
+ const workflowCards = workflows
18
+ .map((workflow) => {
19
+ const statusBadge = workflow.active
20
+ ? '<span class="badge badge-success"><span class="dot dot-success"></span>Active</span>'
21
+ : '<span class="badge badge-neutral"><span class="dot dot-neutral"></span>Inactive</span>';
22
+ const executionBadge = getExecutionBadge(workflow.last_execution_status);
23
+ return `
24
+ <div class="card">
25
+ <div class="card-header">
26
+ <div>
27
+ <div class="card-title">${workflow.name}</div>
28
+ <div class="card-subtitle">ID: ${workflow.id.slice(0, 8)}...</div>
29
+ </div>
30
+ ${statusBadge}
31
+ </div>
32
+
33
+ <div>
34
+ <div class="stat">
35
+ <span class="stat-label">Total Executions</span>
36
+ <span class="stat-value">${workflow.executions_count || 0}</span>
37
+ </div>
38
+ ${workflow.last_execution_at
39
+ ? `
40
+ <div class="stat">
41
+ <span class="stat-label">Last Run</span>
42
+ <span class="stat-value">${executionBadge} ${formatRelativeTime(workflow.last_execution_at)}</span>
43
+ </div>`
44
+ : ''}
45
+ <div class="stat">
46
+ <span class="stat-label">Updated</span>
47
+ <span class="stat-value">${formatRelativeTime(workflow.updated_at)}</span>
48
+ </div>
49
+ </div>
50
+
51
+ ${workflow.tags && workflow.tags.length > 0
52
+ ? `
53
+ <div style="margin-top: 12px; display: flex; gap: 6px; flex-wrap: wrap;">
54
+ ${workflow.tags.map((tag) => `<span class="badge badge-neutral" style="font-size: 11px;">${tag}</span>`).join('')}
55
+ </div>`
56
+ : ''}
57
+
58
+ <div class="actions">
59
+ ${workflow.active ? '<button class="btn btn-secondary">⏸ Pause</button>' : '<button class="btn btn-primary">▶️ Activate</button>'}
60
+ <button class="btn btn-secondary">View Executions</button>
61
+ <button class="btn btn-danger">Archive</button>
62
+ </div>
63
+ </div>
64
+ `;
65
+ })
66
+ .join('');
67
+ return baseLayout('Workflows', `
68
+ <div class="header">
69
+ <h1>⚡ Workflows</h1>
70
+ <p>${workflows.length} workflows • ${activeCount} active • ${totalExecutions.toLocaleString()} total executions</p>
71
+ </div>
72
+
73
+ <div class="grid">
74
+ ${workflowCards}
75
+ </div>
76
+
77
+ <div class="card">
78
+ <h3 style="margin-bottom: 12px;">Quick Actions</h3>
79
+ <div style="display: flex; gap: 12px;">
80
+ <button class="btn btn-primary">+ New Workflow</button>
81
+ <button class="btn btn-secondary">Import Template</button>
82
+ <button class="btn btn-secondary">View All Executions</button>
83
+ </div>
84
+ </div>
85
+ `);
86
+ }
87
+ export function renderWorkflowDetails(workflow, executions) {
88
+ const statusBadge = workflow.active
89
+ ? '<span class="badge badge-success">Active</span>'
90
+ : '<span class="badge badge-neutral">Inactive</span>';
91
+ const recentExecutions = executions.slice(0, 10);
92
+ return baseLayout(`Workflow: ${workflow.name}`, `
93
+ <div class="header">
94
+ <h1>⚡ ${workflow.name}</h1>
95
+ <p>Workflow ID: <span class="code">${workflow.id}</span> • ${statusBadge}</p>
96
+ </div>
97
+
98
+ <div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 24px;">
99
+ <div class="card">
100
+ <div class="stat">
101
+ <span class="stat-label">Status</span>
102
+ <span class="stat-value">${statusBadge}</span>
103
+ </div>
104
+ </div>
105
+ <div class="card">
106
+ <div class="stat">
107
+ <span class="stat-label">Total Runs</span>
108
+ <span class="stat-value">${workflow.executions_count || 0}</span>
109
+ </div>
110
+ </div>
111
+ <div class="card">
112
+ <div class="stat">
113
+ <span class="stat-label">Last Run</span>
114
+ <span class="stat-value">${workflow.last_execution_at ? formatRelativeTime(workflow.last_execution_at) : 'Never'}</span>
115
+ </div>
116
+ </div>
117
+ <div class="card">
118
+ <div class="stat">
119
+ <span class="stat-label">Success Rate</span>
120
+ <span class="stat-value">${calculateSuccessRate(executions)}%</span>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <div class="card" style="margin-bottom: 24px;">
126
+ <h3 style="margin-bottom: 16px;">Recent Executions</h3>
127
+ ${renderExecutionsTable(recentExecutions)}
128
+ </div>
129
+
130
+ <div class="actions">
131
+ ${workflow.active ? '<button class="btn btn-secondary">⏸ Pause Workflow</button>' : '<button class="btn btn-primary">▶️ Activate Workflow</button>'}
132
+ <button class="btn btn-secondary">Edit Workflow</button>
133
+ <button class="btn btn-secondary">View Parameters</button>
134
+ <button class="btn btn-danger">Archive</button>
135
+ </div>
136
+ `);
137
+ }
138
+ function renderExecutionsTable(executions) {
139
+ if (!executions || executions.length === 0) {
140
+ return renderEmptyState('No Executions', 'This workflow hasn\'t been executed yet.');
141
+ }
142
+ const rows = executions
143
+ .map((exec) => `
144
+ <tr>
145
+ <td>${getExecutionBadge(exec.status)}</td>
146
+ <td><span class="code">${exec.id.slice(0, 12)}...</span></td>
147
+ <td>${formatRelativeTime(exec.started_at)}</td>
148
+ <td>${exec.finished_at ? calculateDuration(exec.started_at, exec.finished_at) : 'Running...'}</td>
149
+ </tr>
150
+ `)
151
+ .join('');
152
+ return `
153
+ <table class="table">
154
+ <thead>
155
+ <tr>
156
+ <th>Status</th>
157
+ <th>Execution ID</th>
158
+ <th>Started</th>
159
+ <th>Duration</th>
160
+ </tr>
161
+ </thead>
162
+ <tbody>
163
+ ${rows}
164
+ </tbody>
165
+ </table>
166
+ `;
167
+ }
168
+ function getExecutionBadge(status) {
169
+ if (!status)
170
+ return '<span class="badge badge-neutral">Unknown</span>';
171
+ const statusLower = status.toLowerCase();
172
+ if (statusLower === 'success' || statusLower === 'succeeded') {
173
+ return '<span class="badge badge-success">✓ Success</span>';
174
+ }
175
+ else if (statusLower === 'error' || statusLower === 'failed') {
176
+ return '<span class="badge badge-error">✗ Failed</span>';
177
+ }
178
+ else if (statusLower === 'running') {
179
+ return '<span class="badge badge-warning">⏳ Running</span>';
180
+ }
181
+ else {
182
+ return `<span class="badge badge-neutral">${status}</span>`;
183
+ }
184
+ }
185
+ function formatRelativeTime(timestamp) {
186
+ const date = new Date(timestamp);
187
+ const now = new Date();
188
+ const diffMs = now.getTime() - date.getTime();
189
+ const diffMins = Math.floor(diffMs / 60000);
190
+ const diffHours = Math.floor(diffMins / 60);
191
+ const diffDays = Math.floor(diffHours / 24);
192
+ if (diffMins < 1)
193
+ return 'Just now';
194
+ if (diffMins < 60)
195
+ return `${diffMins}m ago`;
196
+ if (diffHours < 24)
197
+ return `${diffHours}h ago`;
198
+ if (diffDays < 7)
199
+ return `${diffDays}d ago`;
200
+ return date.toLocaleDateString();
201
+ }
202
+ function calculateDuration(start, end) {
203
+ const diffMs = new Date(end).getTime() - new Date(start).getTime();
204
+ const diffSecs = Math.floor(diffMs / 1000);
205
+ if (diffSecs < 60)
206
+ return `${diffSecs}s`;
207
+ const mins = Math.floor(diffSecs / 60);
208
+ const secs = diffSecs % 60;
209
+ return `${mins}m ${secs}s`;
210
+ }
211
+ function calculateSuccessRate(executions) {
212
+ if (!executions || executions.length === 0)
213
+ return 0;
214
+ const successful = executions.filter((e) => e.status?.toLowerCase() === 'success' || e.status?.toLowerCase() === 'succeeded').length;
215
+ return Math.round((successful / executions.length) * 100);
216
+ }
217
+ //# sourceMappingURL=workflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../src/ui/workflows.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "flowengine-mcp-app",
3
+ "version": "1.0.0",
4
+ "description": "MCP App for FlowEngine - Interactive UI for managing workflows, portals, widgets, and hosting directly in Claude Code",
5
+ "type": "module",
6
+ "bin": {
7
+ "flowengine-mcp": "./build/index.js"
8
+ },
9
+ "main": "./build/index.js",
10
+ "files": [
11
+ "build/**/*",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/flowengine/flowengine.git",
18
+ "directory": "flowengine-mcp"
19
+ },
20
+ "homepage": "https://flowengine.cloud",
21
+ "bugs": {
22
+ "url": "https://github.com/flowengine/flowengine/issues"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "prepare": "npm run build",
27
+ "dev": "tsc --watch",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "keywords": [
31
+ "flowengine",
32
+ "mcp",
33
+ "mcp-app",
34
+ "model-context-protocol",
35
+ "claude",
36
+ "automation",
37
+ "n8n",
38
+ "ui",
39
+ "workflows",
40
+ "no-code"
41
+ ],
42
+ "author": "FlowEngine",
43
+ "license": "MIT",
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.0.4"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.10.5",
49
+ "typescript": "^5.7.3"
50
+ },
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ }
54
+ }