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.
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/build/client.d.ts +51 -0
- package/build/client.d.ts.map +1 -0
- package/build/client.js +161 -0
- package/build/client.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +650 -0
- package/build/index.js.map +1 -0
- package/build/ui/base.d.ts +7 -0
- package/build/ui/base.d.ts.map +1 -0
- package/build/ui/base.js +301 -0
- package/build/ui/base.js.map +1 -0
- package/build/ui/demo.d.ts +14 -0
- package/build/ui/demo.d.ts.map +1 -0
- package/build/ui/demo.js +222 -0
- package/build/ui/demo.js.map +1 -0
- package/build/ui/instances.d.ts +17 -0
- package/build/ui/instances.d.ts.map +1 -0
- package/build/ui/instances.js +229 -0
- package/build/ui/instances.js.map +1 -0
- package/build/ui/portals.d.ts +14 -0
- package/build/ui/portals.d.ts.map +1 -0
- package/build/ui/portals.js +184 -0
- package/build/ui/portals.js.map +1 -0
- package/build/ui/widgets.d.ts +17 -0
- package/build/ui/widgets.d.ts.map +1 -0
- package/build/ui/widgets.js +200 -0
- package/build/ui/widgets.js.map +1 -0
- package/build/ui/workflows.d.ts +17 -0
- package/build/ui/workflows.d.ts.map +1 -0
- package/build/ui/workflows.js +217 -0
- package/build/ui/workflows.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instance / Hosting Management UI
|
|
3
|
+
*/
|
|
4
|
+
import { baseLayout, renderEmptyState } from './base.js';
|
|
5
|
+
export function renderInstancesManager(instances) {
|
|
6
|
+
if (!instances || instances.length === 0) {
|
|
7
|
+
return baseLayout('Hosting', `
|
|
8
|
+
<div class="header">
|
|
9
|
+
<h1>🚀 Hosting Management</h1>
|
|
10
|
+
<p>Manage your FlowEngine instances</p>
|
|
11
|
+
</div>
|
|
12
|
+
${renderEmptyState('No Instances Found', 'You don\'t have any instances yet. Provision your first instance to get started.')}
|
|
13
|
+
<div class="card">
|
|
14
|
+
<h3 style="margin-bottom: 12px;">Get Started</h3>
|
|
15
|
+
<p style="color: #999; margin-bottom: 16px;">FlowEngine instances are fully-managed n8n automation servers. Each instance includes:</p>
|
|
16
|
+
<ul style="color: #999; margin-left: 20px; margin-bottom: 16px;">
|
|
17
|
+
<li>Dedicated n8n automation server</li>
|
|
18
|
+
<li>Custom domain support</li>
|
|
19
|
+
<li>Automated backups</li>
|
|
20
|
+
<li>Scalable storage</li>
|
|
21
|
+
</ul>
|
|
22
|
+
<button class="btn btn-primary">+ Provision New Instance</button>
|
|
23
|
+
</div>
|
|
24
|
+
`);
|
|
25
|
+
}
|
|
26
|
+
const activeInstances = instances.filter((i) => i.status === 'active' || i.status === 'running');
|
|
27
|
+
const totalStorage = instances.reduce((sum, i) => sum + i.storage_limit_gb, 0);
|
|
28
|
+
const usedStorage = instances.reduce((sum, i) => sum + (i.storage_used_gb || 0), 0);
|
|
29
|
+
const instanceCards = instances
|
|
30
|
+
.map((instance) => {
|
|
31
|
+
const statusBadge = getInstanceStatusBadge(instance.status);
|
|
32
|
+
const storagePercent = instance.storage_used_gb ? Math.round((instance.storage_used_gb / instance.storage_limit_gb) * 100) : 0;
|
|
33
|
+
const storageBarColor = storagePercent > 80 ? '#f87171' : storagePercent > 60 ? '#facc15' : '#4ade80';
|
|
34
|
+
return `
|
|
35
|
+
<div class="card">
|
|
36
|
+
<div class="card-header">
|
|
37
|
+
<div>
|
|
38
|
+
<div class="card-title">${instance.instance_url}</div>
|
|
39
|
+
<div class="card-subtitle">ID: ${instance.id.slice(0, 8)}...</div>
|
|
40
|
+
</div>
|
|
41
|
+
${statusBadge}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div>
|
|
45
|
+
<div class="stat">
|
|
46
|
+
<span class="stat-label">Storage</span>
|
|
47
|
+
<span class="stat-value">${instance.storage_used_gb || 0} GB / ${instance.storage_limit_gb} GB</span>
|
|
48
|
+
</div>
|
|
49
|
+
<div style="width: 100%; height: 6px; background: #262626; border-radius: 3px; overflow: hidden; margin-top: 8px;">
|
|
50
|
+
<div style="width: ${storagePercent}%; height: 100%; background: ${storageBarColor}; transition: width 0.3s;"></div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="stat" style="margin-top: 12px;">
|
|
54
|
+
<span class="stat-label">Subscription</span>
|
|
55
|
+
<span class="stat-value">${instance.subscription_status || 'Active'}</span>
|
|
56
|
+
</div>
|
|
57
|
+
${instance.tier
|
|
58
|
+
? `
|
|
59
|
+
<div class="stat">
|
|
60
|
+
<span class="stat-label">Tier</span>
|
|
61
|
+
<span class="stat-value"><span class="badge badge-neutral">${instance.tier}</span></span>
|
|
62
|
+
</div>`
|
|
63
|
+
: ''}
|
|
64
|
+
<div class="stat">
|
|
65
|
+
<span class="stat-label">Created</span>
|
|
66
|
+
<span class="stat-value">${new Date(instance.created_at).toLocaleDateString()}</span>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="actions">
|
|
71
|
+
<a href="https://${instance.instance_url}" target="_blank" class="btn btn-primary">
|
|
72
|
+
Open Instance →
|
|
73
|
+
</a>
|
|
74
|
+
<button class="btn btn-secondary">Settings</button>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
`;
|
|
78
|
+
})
|
|
79
|
+
.join('');
|
|
80
|
+
return baseLayout('Hosting', `
|
|
81
|
+
<div class="header">
|
|
82
|
+
<h1>🚀 Hosting Management</h1>
|
|
83
|
+
<p>${instances.length} instances • ${activeInstances.length} active • ${usedStorage.toFixed(1)} / ${totalStorage} GB used</p>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="grid">
|
|
87
|
+
${instanceCards}
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<div class="card">
|
|
91
|
+
<h3 style="margin-bottom: 12px;">Quick Actions</h3>
|
|
92
|
+
<div style="display: flex; gap: 12px;">
|
|
93
|
+
<button class="btn btn-primary">+ New Instance</button>
|
|
94
|
+
<button class="btn btn-secondary">View All Backups</button>
|
|
95
|
+
<button class="btn btn-secondary">Billing Settings</button>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
`);
|
|
99
|
+
}
|
|
100
|
+
export function renderInstanceDetails(instance, healthData) {
|
|
101
|
+
const statusBadge = getInstanceStatusBadge(instance.status);
|
|
102
|
+
const storagePercent = instance.storage_used_gb ? Math.round((instance.storage_used_gb / instance.storage_limit_gb) * 100) : 0;
|
|
103
|
+
return baseLayout(`Instance: ${instance.instance_url}`, `
|
|
104
|
+
<div class="header">
|
|
105
|
+
<h1>🚀 ${instance.instance_url}</h1>
|
|
106
|
+
<p>Instance ID: <span class="code">${instance.id}</span> • ${statusBadge}</p>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 24px;">
|
|
110
|
+
<div class="card">
|
|
111
|
+
<div class="stat">
|
|
112
|
+
<span class="stat-label">Status</span>
|
|
113
|
+
<span class="stat-value">${statusBadge}</span>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="card">
|
|
117
|
+
<div class="stat">
|
|
118
|
+
<span class="stat-label">Storage</span>
|
|
119
|
+
<span class="stat-value">${instance.storage_used_gb || 0} / ${instance.storage_limit_gb} GB</span>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="card">
|
|
123
|
+
<div class="stat">
|
|
124
|
+
<span class="stat-label">Subscription</span>
|
|
125
|
+
<span class="stat-value">${instance.subscription_status || 'Active'}</span>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="card">
|
|
129
|
+
<div class="stat">
|
|
130
|
+
<span class="stat-label">Uptime</span>
|
|
131
|
+
<span class="stat-value">${healthData?.uptime || '99.9%'}</span>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div class="card" style="margin-bottom: 24px;">
|
|
137
|
+
<h3 style="margin-bottom: 16px;">Storage Usage</h3>
|
|
138
|
+
<div style="margin-bottom: 12px;">
|
|
139
|
+
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
|
140
|
+
<span style="color: #999; font-size: 14px;">Used: ${instance.storage_used_gb || 0} GB</span>
|
|
141
|
+
<span style="color: #999; font-size: 14px;">${storagePercent}%</span>
|
|
142
|
+
</div>
|
|
143
|
+
<div style="width: 100%; height: 12px; background: #262626; border-radius: 6px; overflow: hidden;">
|
|
144
|
+
<div style="width: ${storagePercent}%; height: 100%; background: linear-gradient(90deg, #4ade80, #22c55e); transition: width 0.3s;"></div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
${storagePercent > 80
|
|
148
|
+
? '<div style="color: #f87171; font-size: 13px; margin-top: 12px;">⚠️ Storage is running low. Consider upgrading your plan.</div>'
|
|
149
|
+
: ''}
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div class="card" style="margin-bottom: 24px;">
|
|
153
|
+
<h3 style="margin-bottom: 16px;">Instance Information</h3>
|
|
154
|
+
<div class="stat">
|
|
155
|
+
<span class="stat-label">URL</span>
|
|
156
|
+
<span class="stat-value"><a href="https://${instance.instance_url}" target="_blank">${instance.instance_url}</a></span>
|
|
157
|
+
</div>
|
|
158
|
+
${instance.tier
|
|
159
|
+
? `
|
|
160
|
+
<div class="stat">
|
|
161
|
+
<span class="stat-label">Tier</span>
|
|
162
|
+
<span class="stat-value"><span class="badge badge-neutral">${instance.tier}</span></span>
|
|
163
|
+
</div>`
|
|
164
|
+
: ''}
|
|
165
|
+
<div class="stat">
|
|
166
|
+
<span class="stat-label">Created</span>
|
|
167
|
+
<span class="stat-value">${new Date(instance.created_at).toLocaleDateString()}</span>
|
|
168
|
+
</div>
|
|
169
|
+
<div class="stat">
|
|
170
|
+
<span class="stat-label">Last Updated</span>
|
|
171
|
+
<span class="stat-value">${new Date(instance.updated_at).toLocaleDateString()}</span>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
${healthData ? renderHealthMetrics(healthData) : ''}
|
|
176
|
+
|
|
177
|
+
<div class="actions">
|
|
178
|
+
<a href="https://${instance.instance_url}" target="_blank" class="btn btn-primary">
|
|
179
|
+
Open Instance →
|
|
180
|
+
</a>
|
|
181
|
+
<button class="btn btn-secondary">Change Domain</button>
|
|
182
|
+
<button class="btn btn-secondary">Upgrade Storage</button>
|
|
183
|
+
<button class="btn btn-secondary">Create Backup</button>
|
|
184
|
+
<button class="btn btn-danger">Delete Instance</button>
|
|
185
|
+
</div>
|
|
186
|
+
`);
|
|
187
|
+
}
|
|
188
|
+
function getInstanceStatusBadge(status) {
|
|
189
|
+
const statusLower = status.toLowerCase();
|
|
190
|
+
if (statusLower === 'active' || statusLower === 'running') {
|
|
191
|
+
return '<span class="badge badge-success"><span class="dot dot-success"></span>Active</span>';
|
|
192
|
+
}
|
|
193
|
+
else if (statusLower === 'paused' || statusLower === 'suspended') {
|
|
194
|
+
return '<span class="badge badge-warning"><span class="dot dot-warning"></span>Paused</span>';
|
|
195
|
+
}
|
|
196
|
+
else if (statusLower === 'error' || statusLower === 'failed') {
|
|
197
|
+
return '<span class="badge badge-error"><span class="dot dot-error"></span>Error</span>';
|
|
198
|
+
}
|
|
199
|
+
else if (statusLower === 'provisioning' || statusLower === 'starting') {
|
|
200
|
+
return '<span class="badge badge-warning"><span class="dot dot-warning"></span>Starting</span>';
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
return '<span class="badge badge-neutral"><span class="dot dot-neutral"></span>Inactive</span>';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function renderHealthMetrics(healthData) {
|
|
207
|
+
return `
|
|
208
|
+
<div class="card" style="margin-bottom: 24px;">
|
|
209
|
+
<h3 style="margin-bottom: 16px;">Health Metrics</h3>
|
|
210
|
+
<div class="stat">
|
|
211
|
+
<span class="stat-label">Response Time</span>
|
|
212
|
+
<span class="stat-value">${healthData.response_time || '120ms'}</span>
|
|
213
|
+
</div>
|
|
214
|
+
<div class="stat">
|
|
215
|
+
<span class="stat-label">CPU Usage</span>
|
|
216
|
+
<span class="stat-value">${healthData.cpu_usage || '23%'}</span>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="stat">
|
|
219
|
+
<span class="stat-label">Memory Usage</span>
|
|
220
|
+
<span class="stat-value">${healthData.memory_usage || '512 MB'}</span>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="stat">
|
|
223
|
+
<span class="stat-label">Last Health Check</span>
|
|
224
|
+
<span class="stat-value">${healthData.last_check ? new Date(healthData.last_check).toLocaleString() : 'Just now'}</span>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=instances.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instances.js","sourceRoot":"","sources":["../../src/ui/instances.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client Portals UI
|
|
3
|
+
*/
|
|
4
|
+
export interface PortalInstance {
|
|
5
|
+
id: string;
|
|
6
|
+
instance_url: string;
|
|
7
|
+
storage_limit_gb: number;
|
|
8
|
+
status: string;
|
|
9
|
+
created_at: string;
|
|
10
|
+
subscription_status?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function renderPortalsDashboard(instances: PortalInstance[]): string;
|
|
13
|
+
export declare function renderPortalDetails(instanceId: string, workflows: any[], widgets: any[]): string;
|
|
14
|
+
//# sourceMappingURL=portals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portals.d.ts","sourceRoot":"","sources":["../../src/ui/portals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,CA6E1E;AAkBD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,CAqChG"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client Portals UI
|
|
3
|
+
*/
|
|
4
|
+
import { baseLayout, renderEmptyState } from './base.js';
|
|
5
|
+
export function renderPortalsDashboard(instances) {
|
|
6
|
+
if (!instances || instances.length === 0) {
|
|
7
|
+
return baseLayout('Client Portals', `
|
|
8
|
+
<div class="header">
|
|
9
|
+
<h1>🏢 Client Portals</h1>
|
|
10
|
+
<p>Manage your client instances and portals</p>
|
|
11
|
+
</div>
|
|
12
|
+
${renderEmptyState('No Portals Found', 'You don\'t have any client portals yet. Create your first instance to get started.')}
|
|
13
|
+
`);
|
|
14
|
+
}
|
|
15
|
+
const instanceCards = instances
|
|
16
|
+
.map((instance) => {
|
|
17
|
+
const statusBadge = getStatusBadge(instance.status, instance.subscription_status);
|
|
18
|
+
const storageUsed = Math.floor(Math.random() * instance.storage_limit_gb * 0.7); // Mock data
|
|
19
|
+
return `
|
|
20
|
+
<div class="card">
|
|
21
|
+
<div class="card-header">
|
|
22
|
+
<div>
|
|
23
|
+
<div class="card-title">${instance.instance_url}</div>
|
|
24
|
+
<div class="card-subtitle">ID: ${instance.id.slice(0, 8)}...</div>
|
|
25
|
+
</div>
|
|
26
|
+
${statusBadge}
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div>
|
|
30
|
+
<div class="stat">
|
|
31
|
+
<span class="stat-label">Storage</span>
|
|
32
|
+
<span class="stat-value">${storageUsed} GB / ${instance.storage_limit_gb} GB</span>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="stat">
|
|
35
|
+
<span class="stat-label">Subscription</span>
|
|
36
|
+
<span class="stat-value">${instance.subscription_status || 'Active'}</span>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="stat">
|
|
39
|
+
<span class="stat-label">Created</span>
|
|
40
|
+
<span class="stat-value">${new Date(instance.created_at).toLocaleDateString()}</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="actions">
|
|
45
|
+
<a href="https://${instance.instance_url}" target="_blank" class="btn btn-primary">
|
|
46
|
+
Open Portal →
|
|
47
|
+
</a>
|
|
48
|
+
<button class="btn btn-secondary">Manage</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
`;
|
|
52
|
+
})
|
|
53
|
+
.join('');
|
|
54
|
+
return baseLayout('Client Portals', `
|
|
55
|
+
<div class="header">
|
|
56
|
+
<h1>🏢 Client Portals</h1>
|
|
57
|
+
<p>Manage ${instances.length} client ${instances.length === 1 ? 'instance' : 'instances'}</p>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="grid">
|
|
61
|
+
${instanceCards}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="card">
|
|
65
|
+
<h3 style="margin-bottom: 12px;">Quick Actions</h3>
|
|
66
|
+
<div style="display: flex; gap: 12px;">
|
|
67
|
+
<button class="btn btn-primary">+ New Portal</button>
|
|
68
|
+
<button class="btn btn-secondary">View All Clients</button>
|
|
69
|
+
<button class="btn btn-secondary">Invite Client</button>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
function getStatusBadge(status, subscriptionStatus) {
|
|
75
|
+
const isActive = status === 'active' || status === 'running';
|
|
76
|
+
const isPaused = status === 'paused' || subscriptionStatus === 'paused';
|
|
77
|
+
const isError = status === 'error' || status === 'failed';
|
|
78
|
+
if (isActive) {
|
|
79
|
+
return '<span class="badge badge-success"><span class="dot dot-success"></span>Active</span>';
|
|
80
|
+
}
|
|
81
|
+
else if (isPaused) {
|
|
82
|
+
return '<span class="badge badge-warning"><span class="dot dot-warning"></span>Paused</span>';
|
|
83
|
+
}
|
|
84
|
+
else if (isError) {
|
|
85
|
+
return '<span class="badge badge-error"><span class="dot dot-error"></span>Error</span>';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return '<span class="badge badge-neutral"><span class="dot dot-neutral"></span>Inactive</span>';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function renderPortalDetails(instanceId, workflows, widgets) {
|
|
92
|
+
return baseLayout('Portal Details', `
|
|
93
|
+
<div class="header">
|
|
94
|
+
<h1>📊 Portal Details</h1>
|
|
95
|
+
<p>Instance: <span class="code">${instanceId.slice(0, 8)}...</span></p>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="card" style="margin-bottom: 24px;">
|
|
99
|
+
<h3 style="margin-bottom: 16px;">Overview</h3>
|
|
100
|
+
<div class="stat">
|
|
101
|
+
<span class="stat-label">Active Workflows</span>
|
|
102
|
+
<span class="stat-value">${workflows.filter((w) => w.active).length} / ${workflows.length}</span>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="stat">
|
|
105
|
+
<span class="stat-label">Widgets</span>
|
|
106
|
+
<span class="stat-value">${widgets.length}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="stat">
|
|
109
|
+
<span class="stat-label">Status</span>
|
|
110
|
+
<span class="stat-value"><span class="badge badge-success">Active</span></span>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<h3 style="margin: 24px 0 16px;">Workflows</h3>
|
|
115
|
+
${renderWorkflowsList(workflows)}
|
|
116
|
+
|
|
117
|
+
<h3 style="margin: 24px 0 16px;">Widgets</h3>
|
|
118
|
+
${renderWidgetsList(widgets)}
|
|
119
|
+
|
|
120
|
+
<div class="actions">
|
|
121
|
+
<button class="btn btn-primary">Open Portal</button>
|
|
122
|
+
<button class="btn btn-secondary">Manage Settings</button>
|
|
123
|
+
</div>
|
|
124
|
+
`);
|
|
125
|
+
}
|
|
126
|
+
function renderWorkflowsList(workflows) {
|
|
127
|
+
if (!workflows || workflows.length === 0) {
|
|
128
|
+
return renderEmptyState('No Workflows', 'No workflows configured for this portal.');
|
|
129
|
+
}
|
|
130
|
+
const rows = workflows
|
|
131
|
+
.slice(0, 5)
|
|
132
|
+
.map((w) => `
|
|
133
|
+
<tr>
|
|
134
|
+
<td>${w.name}</td>
|
|
135
|
+
<td>${w.active ? '<span class="badge badge-success">Active</span>' : '<span class="badge badge-neutral">Inactive</span>'}</td>
|
|
136
|
+
<td>${w.executions_count || 0} runs</td>
|
|
137
|
+
</tr>
|
|
138
|
+
`)
|
|
139
|
+
.join('');
|
|
140
|
+
return `
|
|
141
|
+
<table class="table">
|
|
142
|
+
<thead>
|
|
143
|
+
<tr>
|
|
144
|
+
<th>Workflow</th>
|
|
145
|
+
<th>Status</th>
|
|
146
|
+
<th>Executions</th>
|
|
147
|
+
</tr>
|
|
148
|
+
</thead>
|
|
149
|
+
<tbody>
|
|
150
|
+
${rows}
|
|
151
|
+
</tbody>
|
|
152
|
+
</table>
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
function renderWidgetsList(widgets) {
|
|
156
|
+
if (!widgets || widgets.length === 0) {
|
|
157
|
+
return renderEmptyState('No Widgets', 'No widgets configured for this portal.');
|
|
158
|
+
}
|
|
159
|
+
const rows = widgets
|
|
160
|
+
.slice(0, 5)
|
|
161
|
+
.map((w) => `
|
|
162
|
+
<tr>
|
|
163
|
+
<td>${w.name}</td>
|
|
164
|
+
<td><span class="code">${w.widget_type}</span></td>
|
|
165
|
+
<td>${w.is_active ? '<span class="badge badge-success">Active</span>' : '<span class="badge badge-neutral">Inactive</span>'}</td>
|
|
166
|
+
</tr>
|
|
167
|
+
`)
|
|
168
|
+
.join('');
|
|
169
|
+
return `
|
|
170
|
+
<table class="table">
|
|
171
|
+
<thead>
|
|
172
|
+
<tr>
|
|
173
|
+
<th>Widget</th>
|
|
174
|
+
<th>Type</th>
|
|
175
|
+
<th>Status</th>
|
|
176
|
+
</tr>
|
|
177
|
+
</thead>
|
|
178
|
+
<tbody>
|
|
179
|
+
${rows}
|
|
180
|
+
</tbody>
|
|
181
|
+
</table>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=portals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portals.js","sourceRoot":"","sources":["../../src/ui/portals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Builder - Forms, Chatbots, and Interactive Components
|
|
3
|
+
*/
|
|
4
|
+
export interface Widget {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
widget_type: string;
|
|
8
|
+
webhook_url: string;
|
|
9
|
+
is_active: boolean;
|
|
10
|
+
created_at: string;
|
|
11
|
+
updated_at: string;
|
|
12
|
+
config?: any;
|
|
13
|
+
submissions_count?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function renderWidgetBuilder(widgets: Widget[], instanceId?: string): string;
|
|
16
|
+
export declare function renderWidgetDetails(widget: Widget): string;
|
|
17
|
+
//# sourceMappingURL=widgets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widgets.d.ts","sourceRoot":"","sources":["../../src/ui/widgets.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAwFlF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAqE1D"}
|