@semiont/cli 0.1.0-build.2

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,238 @@
1
+
2
+ /* Semiont Web Dashboard Styles */
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
11
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
12
+ min-height: 100vh;
13
+ padding: 20px;
14
+ }
15
+
16
+ .dashboard-container {
17
+ max-width: 1400px;
18
+ margin: 0 auto;
19
+ }
20
+
21
+ .dashboard-header {
22
+ background: white;
23
+ border-radius: 12px;
24
+ padding: 20px;
25
+ margin-bottom: 20px;
26
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
27
+ display: flex;
28
+ justify-content: space-between;
29
+ align-items: center;
30
+ }
31
+
32
+ .dashboard-title {
33
+ font-size: 24px;
34
+ font-weight: bold;
35
+ color: #2d3748;
36
+ }
37
+
38
+ .dashboard-subtitle {
39
+ color: #718096;
40
+ margin-top: 4px;
41
+ }
42
+
43
+ .refresh-info {
44
+ text-align: right;
45
+ color: #718096;
46
+ font-size: 14px;
47
+ }
48
+
49
+ .dashboard-grid {
50
+ display: grid;
51
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
52
+ gap: 20px;
53
+ margin-bottom: 20px;
54
+ }
55
+
56
+ .dashboard-panel {
57
+ background: white;
58
+ border-radius: 12px;
59
+ padding: 20px;
60
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
61
+ }
62
+
63
+ .panel-title {
64
+ font-size: 18px;
65
+ font-weight: 600;
66
+ color: #2d3748;
67
+ margin-bottom: 16px;
68
+ padding-bottom: 8px;
69
+ border-bottom: 2px solid #e2e8f0;
70
+ }
71
+
72
+ .service-item {
73
+ display: flex;
74
+ align-items: center;
75
+ padding: 12px;
76
+ margin-bottom: 8px;
77
+ border-radius: 8px;
78
+ background: #f7fafc;
79
+ transition: all 0.2s;
80
+ }
81
+
82
+ .service-item:hover {
83
+ background: #edf2f7;
84
+ transform: translateX(4px);
85
+ }
86
+
87
+ .status-indicator {
88
+ width: 12px;
89
+ height: 12px;
90
+ border-radius: 50%;
91
+ margin-right: 12px;
92
+ animation: pulse 2s infinite;
93
+ }
94
+
95
+ .status-healthy { background: #48bb78; }
96
+ .status-warning { background: #ed8936; }
97
+ .status-unhealthy { background: #f56565; }
98
+ .status-unknown { background: #a0aec0; }
99
+
100
+ @keyframes pulse {
101
+ 0% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7); }
102
+ 70% { box-shadow: 0 0 0 10px rgba(72, 187, 120, 0); }
103
+ 100% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0); }
104
+ }
105
+
106
+ .service-name {
107
+ font-weight: 500;
108
+ color: #2d3748;
109
+ flex: 1;
110
+ }
111
+
112
+ .service-details {
113
+ color: #a0aec0;
114
+ font-size: 12px;
115
+ margin-top: 4px;
116
+ }
117
+
118
+ .logs-panel {
119
+ grid-column: 1 / -1;
120
+ max-height: 400px;
121
+ overflow-y: auto;
122
+ }
123
+
124
+ .log-entry {
125
+ font-family: 'Courier New', monospace;
126
+ font-size: 13px;
127
+ padding: 8px;
128
+ border-bottom: 1px solid #e2e8f0;
129
+ display: flex;
130
+ gap: 12px;
131
+ }
132
+
133
+ .log-timestamp {
134
+ color: #718096;
135
+ min-width: 80px;
136
+ }
137
+
138
+ .log-service {
139
+ color: #4299e1;
140
+ min-width: 80px;
141
+ }
142
+
143
+ .log-level {
144
+ min-width: 50px;
145
+ font-weight: 600;
146
+ }
147
+
148
+ .log-level-error { color: #f56565; }
149
+ .log-level-warn { color: #ed8936; }
150
+ .log-level-info { color: #4299e1; }
151
+ .log-level-debug { color: #a0aec0; }
152
+
153
+ .log-message {
154
+ flex: 1;
155
+ color: #2d3748;
156
+ }
157
+
158
+ .connection-status {
159
+ position: fixed;
160
+ bottom: 20px;
161
+ right: 20px;
162
+ padding: 8px 16px;
163
+ border-radius: 20px;
164
+ font-size: 12px;
165
+ font-weight: 500;
166
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
167
+ }
168
+
169
+ .connected {
170
+ background: #48bb78;
171
+ color: white;
172
+ }
173
+
174
+ .disconnected {
175
+ background: #f56565;
176
+ color: white;
177
+ }
178
+
179
+ .action-buttons {
180
+ display: flex;
181
+ gap: 8px;
182
+ margin-top: 8px;
183
+ flex-wrap: wrap;
184
+ }
185
+
186
+ .action-button {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ gap: 4px;
190
+ padding: 4px 10px;
191
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
192
+ color: white;
193
+ text-decoration: none;
194
+ border-radius: 6px;
195
+ font-size: 12px;
196
+ font-weight: 500;
197
+ transition: all 0.2s;
198
+ border: 1px solid rgba(0, 0, 0, 0.1);
199
+ }
200
+
201
+ .action-button:hover {
202
+ transform: translateY(-1px);
203
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
204
+ }
205
+
206
+ .action-button.console {
207
+ background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
208
+ }
209
+
210
+ .action-button.logs {
211
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
212
+ }
213
+
214
+ .action-button.metrics {
215
+ background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%);
216
+ }
217
+
218
+ .loading {
219
+ display: flex;
220
+ justify-content: center;
221
+ align-items: center;
222
+ height: 200px;
223
+ color: #718096;
224
+ }
225
+
226
+ .spinner {
227
+ border: 3px solid #e2e8f0;
228
+ border-top: 3px solid #4299e1;
229
+ border-radius: 50%;
230
+ width: 40px;
231
+ height: 40px;
232
+ animation: spin 1s linear infinite;
233
+ }
234
+
235
+ @keyframes spin {
236
+ 0% { transform: rotate(0deg); }
237
+ 100% { transform: rotate(360deg); }
238
+ }
@@ -0,0 +1,14 @@
1
+
2
+ // Map external modules to globals
3
+ const React = window.React;
4
+ const ReactDOM = window.ReactDOM;
5
+ const require = (name) => {
6
+ if (name === 'react') return React;
7
+ if (name === 'react-dom') return ReactDOM;
8
+ throw new Error('Unknown module: ' + name);
9
+ };
10
+
11
+ "use strict";var SemiontDashboard=(()=>{var y=Object.create;var u=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var z=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var C=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(n,o)=>(typeof require<"u"?require:n)[o]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});var B=(a,n)=>{for(var o in n)u(a,o,{get:n[o],enumerable:!0})},h=(a,n,o,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of w(n))!D.call(a,i)&&i!==o&&u(a,i,{get:()=>n[i],enumerable:!(r=S(n,i))||r.enumerable});return a};var A=(a,n,o)=>(o=a!=null?y(z(a)):{},h(n||!a||!a.__esModule?u(o,"default",{value:a,enumerable:!0}):o,a)),L=a=>h(u({},"__esModule",{value:!0}),a);var x={};B(x,{WebDashboardApp:()=>v});var s=A(C("react"),1),U=({status:a})=>{let n={healthy:"#48bb78",unhealthy:"#f56565",warning:"#ed8936",unknown:"#a0aec0"};return s.default.createElement("div",{className:`status-indicator status-${a}`,style:{background:n[a]}})},f=({services:a,title:n,showActions:o=!0})=>{let r=e=>{let t=[],l=e.awsRegion||"us-east-1";if(e.ecsServiceName&&e.ecsClusterName&&(t.push({label:"\u{1F4CA} Console",url:`https://console.aws.amazon.com/ecs/home?region=${l}#/clusters/${e.ecsClusterName}/services/${e.ecsServiceName}/details`,className:"console"}),e.logGroupName&&t.push({label:"\u{1F4DD} Logs",url:`https://console.aws.amazon.com/cloudwatch/home?region=${l}#logsV2:log-groups/log-group/${encodeURIComponent(e.logGroupName)}`,className:"logs"}),t.push({label:"\u{1F4C8} Metrics",url:`https://console.aws.amazon.com/cloudwatch/home?region=${l}#metricsV2:graph=~();query=~'*7bAWS*2fECS*2cClusterName*2cServiceName*7d*20${e.ecsClusterName}*20${e.ecsServiceName}`,className:"metrics"})),e.rdsInstanceId&&(t.push({label:"\u{1F4CA} Console",url:`https://console.aws.amazon.com/rds/home?region=${l}#database:id=${e.rdsInstanceId};is-cluster=false`,className:"console"}),t.push({label:"\u{1F4C8} Metrics",url:`https://console.aws.amazon.com/cloudwatch/home?region=${l}#metricsV2:graph=~();query=~'*7bAWS*2fRDS*2cDBInstanceIdentifier*7d*20${e.rdsInstanceId}`,className:"metrics"})),e.efsFileSystemId&&(t.push({label:"\u{1F4CA} Console",url:`https://console.aws.amazon.com/efs/home?region=${l}#/file-systems/${e.efsFileSystemId}`,className:"console"}),t.push({label:"\u{1F4C8} Metrics",url:`https://console.aws.amazon.com/cloudwatch/home?region=${l}#metricsV2:graph=~();query=~'*7bAWS*2fEFS*2cFileSystemId*7d*20${e.efsFileSystemId}`,className:"metrics"})),e.albArn){let d=e.albArn.split("/");if(d.length>=3){let p=d[d.length-2];t.push({label:"\u{1F4CA} Console",url:`https://console.aws.amazon.com/ec2/v2/home?region=${l}#LoadBalancers:search=${p};sort=loadBalancerName`,className:"console"})}t.push({label:"\u{1F4C8} Metrics",url:`https://console.aws.amazon.com/cloudwatch/home?region=${l}#metricsV2:graph=~();query=~'*7bAWS*2fApplicationELB*2cLoadBalancer*7d`,className:"metrics"})}return t},i=e=>{if(e===0)return"0 B";let t=1024,l=["B","KB","MB","GB","TB"],d=Math.floor(Math.log(e)/Math.log(t));return(e/Math.pow(t,d)).toFixed(2)+" "+l[d]};return s.default.createElement("div",{className:"dashboard-panel"},s.default.createElement("div",{className:"panel-title"},n),a.map((e,t)=>s.default.createElement("div",{key:t,className:"service-item",style:{marginBottom:"12px"}},s.default.createElement(U,{status:e.status}),s.default.createElement("div",{style:{flex:1}},s.default.createElement("div",{className:"service-name"},e.name,e.revision&&s.default.createElement("span",{style:{color:"#00bcd4",marginLeft:"8px",fontSize:"0.9em"}},"rev:",e.revision),e.runningCount!==void 0&&e.desiredCount!==void 0&&s.default.createElement("span",{style:{color:"#999",marginLeft:"8px",fontSize:"0.9em"}},"[",e.runningCount,"/",e.desiredCount,"]")),e.details&&s.default.createElement("div",{className:"service-details"},e.details),e.name==="Filesystem"&&e.storageTotalBytes&&s.default.createElement(s.default.Fragment,null,s.default.createElement("div",{className:"service-details",style:{color:"#2563eb",fontSize:"0.9em",marginTop:"8px"}},s.default.createElement("strong",null,"Storage:")),e.storageUsedBytes!==void 0&&e.storageTotalBytes&&s.default.createElement("div",{className:"service-details",style:{color:"#718096",fontSize:"0.9em",paddingLeft:"16px"}},"Used: ",i(e.storageUsedBytes)," / ",i(e.storageTotalBytes),e.storageUsedPercent!==void 0&&s.default.createElement("span",{style:{marginLeft:"8px",color:e.storageUsedPercent>90?"#ef4444":e.storageUsedPercent>70?"#f59e0b":"#10b981"}},"(",e.storageUsedPercent.toFixed(1),"%)")),e.storageAvailableBytes!==void 0&&s.default.createElement("div",{className:"service-details",style:{color:"#718096",fontSize:"0.9em",paddingLeft:"16px"}},"Available: ",i(e.storageAvailableBytes)),e.throughputUtilization!==void 0&&s.default.createElement("div",{className:"service-details",style:{color:"#718096",fontSize:"0.9em",paddingLeft:"16px"}},"Throughput: ",e.throughputUtilization.toFixed(1),"%"),e.clientConnections!==void 0&&s.default.createElement("div",{className:"service-details",style:{color:"#718096",fontSize:"0.9em",paddingLeft:"16px"}},"Connections: ",e.clientConnections)),e.name!=="Filesystem"&&(e.cpuUtilization!==void 0||e.memoryUtilization!==void 0)&&s.default.createElement("div",{className:"service-details",style:{color:"#718096",fontSize:"0.9em"}},e.cpuUtilization!==void 0&&s.default.createElement("span",null,"CPU: ",e.cpuUtilization.toFixed(1),"%"),e.cpuUtilization!==void 0&&e.memoryUtilization!==void 0&&s.default.createElement("span",{style:{margin:"0 8px"}},"\u2022"),e.memoryUtilization!==void 0&&s.default.createElement("span",null,"Memory: ",e.memoryUtilization.toFixed(1),"%")),e.deploymentStatus&&e.deploymentStatus!=="PRIMARY"&&s.default.createElement("div",{className:"service-details",style:{color:"#ff9800"}},"Deployment: ",e.deploymentStatus),e.loadBalancerDns&&s.default.createElement("div",{className:"service-details",style:{color:"#00bcd4",fontSize:"0.9em"}},"ALB: ",e.loadBalancerDns),e.wafWebAclId&&s.default.createElement("div",{className:"service-details",style:{color:"#4caf50",fontSize:"0.9em"}},"WAF: Protected \u2713"),o&&r(e).length>0&&s.default.createElement("div",{className:"action-buttons"},r(e).map((l,d)=>s.default.createElement("a",{key:d,href:l.url,target:"_blank",rel:"noopener noreferrer",className:`action-button ${l.className}`},l.label)))))))},$=({logs:a})=>{let n=o=>`log-level log-level-${o}`;return s.default.createElement("div",{className:"dashboard-panel logs-panel"},s.default.createElement("div",{className:"panel-title"},"Recent Logs"),a.length===0?s.default.createElement("div",{style:{padding:"20px",color:"#718096",textAlign:"center"}},"No recent logs"):a.slice(0,50).map((o,r)=>s.default.createElement("div",{key:r,className:"log-entry"},s.default.createElement("span",{className:"log-timestamp"},new Date(o.timestamp).toLocaleTimeString()),s.default.createElement("span",{className:"log-service"},o.service),s.default.createElement("span",{className:n(o.level)},o.level.toUpperCase()),s.default.createElement("span",{className:"log-message"},o.message))))},v=({environment:a,refreshInterval:n})=>{let[o,r]=(0,s.useState)(null),[i,e]=(0,s.useState)(!1),[t,l]=(0,s.useState)(null),[,d]=(0,s.useState)(null);(0,s.useEffect)(()=>{let m=window.io;if(!m){console.error("Socket.IO not loaded");return}let c=m();return d(c),c.on("connect",()=>{e(!0)}),c.on("disconnect",()=>{e(!1)}),c.on("dashboard-update",g=>{r(g),l(new Date)}),c.on("dashboard-error",g=>{console.error("Dashboard error:",g)}),()=>{c.disconnect()}},[]);let p=m=>m?m.toLocaleTimeString():"Never";if(!o)return s.default.createElement("div",{className:"dashboard-container"},s.default.createElement("div",{className:"dashboard-panel"},s.default.createElement("div",{className:"loading"},s.default.createElement("div",{className:"spinner"}))));let N=o.services.filter(m=>["Frontend","Backend","Load Balancer","WAF","DNS (Route 53)"].includes(m.name)),b=o.services.filter(m=>["Database","Filesystem"].includes(m.name));return s.default.createElement("div",{className:"dashboard-container"},s.default.createElement("div",{className:"dashboard-header"},s.default.createElement("div",null,s.default.createElement("div",{className:"dashboard-title"},"Semiont System Dashboard"),s.default.createElement("div",{className:"dashboard-subtitle"},"Environment: ",a)),s.default.createElement("div",{className:"refresh-info"},s.default.createElement("div",null,"Last updated: ",p(t)),s.default.createElement("div",null,"Auto-refresh: every ",n,"s"))),s.default.createElement("div",{className:"dashboard-grid"},s.default.createElement(f,{services:N,title:"App Services",showActions:!0}),s.default.createElement(f,{services:b,title:"Data",showActions:!0})),s.default.createElement($,{logs:o.logs}),s.default.createElement("div",{className:`connection-status ${i?"connected":"disconnected"}`},i?"\u{1F7E2} Connected":"\u{1F534} Disconnected"))};typeof window<"u"&&(window.SemiontDashboard=window.SemiontDashboard||{},window.SemiontDashboard.WebDashboardApp=v);return L(x);})();
12
+ // Ensure global is set
13
+ if (typeof window !== "undefined") { window.SemiontDashboard = SemiontDashboard; }
14
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/dashboard/web-dashboard-app.tsx"],
4
+ "sourcesContent": ["/**\n * Web Dashboard React Application\n * \n * This is the React app for the web dashboard that reuses the same components\n * as the terminal dashboard, eliminating duplication\n */\n\nimport React, { useState, useEffect } from 'react';\nimport { ServiceStatus, LogEntry, MetricData } from './dashboard-components';\n\n// Type declarations for browser globals\ndeclare const window: any;\n\n// Dashboard data interface (shared with terminal)\nexport interface DashboardData {\n services: ServiceStatus[];\n logs: LogEntry[];\n metrics: MetricData[];\n lastUpdate: Date;\n isRefreshing: boolean;\n}\n\n// Status indicator component\nconst StatusIndicator: React.FC<{ status: ServiceStatus['status'] }> = ({ status }) => {\n const colors = {\n healthy: '#48bb78',\n unhealthy: '#f56565',\n warning: '#ed8936',\n unknown: '#a0aec0'\n };\n \n return (\n <div \n className={`status-indicator status-${status}`}\n style={{ background: colors[status] }}\n />\n );\n};\n\n// Service panel component\nconst ServicePanel: React.FC<{ \n services: ServiceStatus[];\n title: string;\n showActions?: boolean;\n}> = ({ services, title, showActions = true }) => {\n const getConsoleLinks = (service: ServiceStatus) => {\n const links: Array<{ label: string; url: string; className: string }> = [];\n const region = service.awsRegion || 'us-east-1';\n \n // ECS Service links\n if (service.ecsServiceName && service.ecsClusterName) {\n links.push({\n label: '\uD83D\uDCCA Console',\n url: `https://console.aws.amazon.com/ecs/home?region=${region}#/clusters/${service.ecsClusterName}/services/${service.ecsServiceName}/details`,\n className: 'console'\n });\n if (service.logGroupName) {\n links.push({\n label: '\uD83D\uDCDD Logs',\n url: `https://console.aws.amazon.com/cloudwatch/home?region=${region}#logsV2:log-groups/log-group/${encodeURIComponent(service.logGroupName)}`,\n className: 'logs'\n });\n }\n links.push({\n label: '\uD83D\uDCC8 Metrics',\n url: `https://console.aws.amazon.com/cloudwatch/home?region=${region}#metricsV2:graph=~();query=~'*7bAWS*2fECS*2cClusterName*2cServiceName*7d*20${service.ecsClusterName}*20${service.ecsServiceName}`,\n className: 'metrics'\n });\n }\n \n // RDS Database link\n if (service.rdsInstanceId) {\n links.push({\n label: '\uD83D\uDCCA Console',\n url: `https://console.aws.amazon.com/rds/home?region=${region}#database:id=${service.rdsInstanceId};is-cluster=false`,\n className: 'console'\n });\n links.push({\n label: '\uD83D\uDCC8 Metrics',\n url: `https://console.aws.amazon.com/cloudwatch/home?region=${region}#metricsV2:graph=~();query=~'*7bAWS*2fRDS*2cDBInstanceIdentifier*7d*20${service.rdsInstanceId}`,\n className: 'metrics'\n });\n }\n \n // EFS Filesystem link\n if (service.efsFileSystemId) {\n links.push({\n label: '\uD83D\uDCCA Console',\n url: `https://console.aws.amazon.com/efs/home?region=${region}#/file-systems/${service.efsFileSystemId}`,\n className: 'console'\n });\n links.push({\n label: '\uD83D\uDCC8 Metrics',\n url: `https://console.aws.amazon.com/cloudwatch/home?region=${region}#metricsV2:graph=~();query=~'*7bAWS*2fEFS*2cFileSystemId*7d*20${service.efsFileSystemId}`,\n className: 'metrics'\n });\n }\n \n // Load Balancer link\n if (service.albArn) {\n const arnParts = service.albArn.split('/');\n if (arnParts.length >= 3) {\n const loadBalancerName = arnParts[arnParts.length - 2];\n links.push({\n label: '\uD83D\uDCCA Console',\n url: `https://console.aws.amazon.com/ec2/v2/home?region=${region}#LoadBalancers:search=${loadBalancerName};sort=loadBalancerName`,\n className: 'console'\n });\n }\n links.push({\n label: '\uD83D\uDCC8 Metrics',\n url: `https://console.aws.amazon.com/cloudwatch/home?region=${region}#metricsV2:graph=~();query=~'*7bAWS*2fApplicationELB*2cLoadBalancer*7d`,\n className: 'metrics'\n });\n }\n \n return links;\n };\n\n const formatBytes = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];\n };\n\n return (\n <div className=\"dashboard-panel\">\n <div className=\"panel-title\">{title}</div>\n {services.map((service, index) => (\n <div key={index} className=\"service-item\" style={{ marginBottom: '12px' }}>\n <StatusIndicator status={service.status} />\n <div style={{ flex: 1 }}>\n <div className=\"service-name\">\n {service.name}\n {service.revision && (\n <span style={{ color: '#00bcd4', marginLeft: '8px', fontSize: '0.9em' }}>\n rev:{service.revision}\n </span>\n )}\n {service.runningCount !== undefined && service.desiredCount !== undefined && (\n <span style={{ color: '#999', marginLeft: '8px', fontSize: '0.9em' }}>\n [{service.runningCount}/{service.desiredCount}]\n </span>\n )}\n </div>\n {service.details && (\n <div className=\"service-details\">{service.details}</div>\n )}\n \n {/* EFS Storage Metrics */}\n {service.name === 'Filesystem' && service.storageTotalBytes && (\n <>\n <div className=\"service-details\" style={{ color: '#2563eb', fontSize: '0.9em', marginTop: '8px' }}>\n <strong>Storage:</strong>\n </div>\n {service.storageUsedBytes !== undefined && service.storageTotalBytes && (\n <div className=\"service-details\" style={{ color: '#718096', fontSize: '0.9em', paddingLeft: '16px' }}>\n Used: {formatBytes(service.storageUsedBytes)} / {formatBytes(service.storageTotalBytes)}\n {service.storageUsedPercent !== undefined && (\n <span style={{ \n marginLeft: '8px',\n color: service.storageUsedPercent > 90 ? '#ef4444' : \n service.storageUsedPercent > 70 ? '#f59e0b' : '#10b981'\n }}>\n ({service.storageUsedPercent.toFixed(1)}%)\n </span>\n )}\n </div>\n )}\n {service.storageAvailableBytes !== undefined && (\n <div className=\"service-details\" style={{ color: '#718096', fontSize: '0.9em', paddingLeft: '16px' }}>\n Available: {formatBytes(service.storageAvailableBytes)}\n </div>\n )}\n {service.throughputUtilization !== undefined && (\n <div className=\"service-details\" style={{ color: '#718096', fontSize: '0.9em', paddingLeft: '16px' }}>\n Throughput: {service.throughputUtilization.toFixed(1)}%\n </div>\n )}\n {service.clientConnections !== undefined && (\n <div className=\"service-details\" style={{ color: '#718096', fontSize: '0.9em', paddingLeft: '16px' }}>\n Connections: {service.clientConnections}\n </div>\n )}\n </>\n )}\n \n {/* Regular metrics for other services */}\n {service.name !== 'Filesystem' && (service.cpuUtilization !== undefined || service.memoryUtilization !== undefined) && (\n <div className=\"service-details\" style={{ color: '#718096', fontSize: '0.9em' }}>\n {service.cpuUtilization !== undefined && (\n <span>CPU: {service.cpuUtilization.toFixed(1)}%</span>\n )}\n {service.cpuUtilization !== undefined && service.memoryUtilization !== undefined && (\n <span style={{ margin: '0 8px' }}>\u2022</span>\n )}\n {service.memoryUtilization !== undefined && (\n <span>Memory: {service.memoryUtilization.toFixed(1)}%</span>\n )}\n </div>\n )}\n \n {service.deploymentStatus && service.deploymentStatus !== 'PRIMARY' && (\n <div className=\"service-details\" style={{ color: '#ff9800' }}>\n Deployment: {service.deploymentStatus}\n </div>\n )}\n \n {service.loadBalancerDns && (\n <div className=\"service-details\" style={{ color: '#00bcd4', fontSize: '0.9em' }}>\n ALB: {service.loadBalancerDns}\n </div>\n )}\n \n {service.wafWebAclId && (\n <div className=\"service-details\" style={{ color: '#4caf50', fontSize: '0.9em' }}>\n WAF: Protected \u2713\n </div>\n )}\n \n {/* Action Buttons */}\n {showActions && getConsoleLinks(service).length > 0 && (\n <div className=\"action-buttons\">\n {getConsoleLinks(service).map((link, linkIndex) => (\n <a \n key={linkIndex}\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`action-button ${link.className}`}\n >\n {link.label}\n </a>\n ))}\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n );\n};\n\n// Log viewer component\nconst LogViewer: React.FC<{ logs: LogEntry[] }> = ({ logs }) => {\n const getLevelClass = (level: string) => {\n return `log-level log-level-${level}`;\n };\n\n return (\n <div className=\"dashboard-panel logs-panel\">\n <div className=\"panel-title\">Recent Logs</div>\n {logs.length === 0 ? (\n <div style={{ padding: '20px', color: '#718096', textAlign: 'center' }}>\n No recent logs\n </div>\n ) : (\n logs.slice(0, 50).map((log, index) => (\n <div key={index} className=\"log-entry\">\n <span className=\"log-timestamp\">\n {new Date(log.timestamp).toLocaleTimeString()}\n </span>\n <span className=\"log-service\">{log.service}</span>\n <span className={getLevelClass(log.level)}>\n {log.level.toUpperCase()}\n </span>\n <span className=\"log-message\">{log.message}</span>\n </div>\n ))\n )}\n </div>\n );\n};\n\n// Main Web Dashboard Component\nexport const WebDashboardApp: React.FC<{\n environment: string;\n refreshInterval: number;\n}> = ({ environment, refreshInterval }) => {\n const [data, setData] = useState<DashboardData | null>(null);\n const [connected, setConnected] = useState(false);\n const [lastUpdate, setLastUpdate] = useState<Date | null>(null);\n const [, setSocket] = useState<any>(null);\n\n useEffect(() => {\n // @ts-ignore - Socket.IO is loaded via script tag\n const io = window.io;\n if (!io) {\n console.error('Socket.IO not loaded');\n return;\n }\n\n const newSocket = io();\n setSocket(newSocket);\n \n newSocket.on('connect', () => {\n setConnected(true);\n });\n \n newSocket.on('disconnect', () => {\n setConnected(false);\n });\n \n newSocket.on('dashboard-update', (newData: DashboardData) => {\n setData(newData);\n setLastUpdate(new Date());\n });\n \n newSocket.on('dashboard-error', (error: any) => {\n console.error('Dashboard error:', error);\n });\n \n return () => {\n newSocket.disconnect();\n };\n }, []);\n\n const formatTime = (date: Date | null) => {\n if (!date) return 'Never';\n return date.toLocaleTimeString();\n };\n\n if (!data) {\n return (\n <div className=\"dashboard-container\">\n <div className=\"dashboard-panel\">\n <div className=\"loading\">\n <div className=\"spinner\"></div>\n </div>\n </div>\n </div>\n );\n }\n\n // Split services by category\n const appServices = data.services.filter(s => \n ['Frontend', 'Backend', 'Load Balancer', 'WAF', 'DNS (Route 53)'].includes(s.name)\n );\n const dataServices = data.services.filter(s => \n ['Database', 'Filesystem'].includes(s.name)\n );\n\n return (\n <div className=\"dashboard-container\">\n <div className=\"dashboard-header\">\n <div>\n <div className=\"dashboard-title\">Semiont System Dashboard</div>\n <div className=\"dashboard-subtitle\">Environment: {environment}</div>\n </div>\n <div className=\"refresh-info\">\n <div>Last updated: {formatTime(lastUpdate)}</div>\n <div>Auto-refresh: every {refreshInterval}s</div>\n </div>\n </div>\n \n <div className=\"dashboard-grid\">\n <ServicePanel \n services={appServices}\n title=\"App Services\"\n showActions={true}\n />\n \n <ServicePanel \n services={dataServices}\n title=\"Data\"\n showActions={true}\n />\n </div>\n \n <LogViewer logs={data.logs} />\n \n <div className={`connection-status ${connected ? 'connected' : 'disconnected'}`}>\n {connected ? '\uD83D\uDFE2 Connected' : '\uD83D\uDD34 Disconnected'}\n </div>\n </div>\n );\n};\n\n// Export for browser usage\nif (typeof window !== 'undefined') {\n window.SemiontDashboard = window.SemiontDashboard || {};\n window.SemiontDashboard.WebDashboardApp = WebDashboardApp;\n}"],
5
+ "mappings": "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",
6
+ "names": ["web_dashboard_app_exports", "__export", "WebDashboardApp", "import_react", "StatusIndicator", "status", "colors", "React", "ServicePanel", "services", "title", "showActions", "getConsoleLinks", "service", "links", "region", "arnParts", "loadBalancerName", "formatBytes", "bytes", "k", "sizes", "i", "index", "link", "linkIndex", "LogViewer", "logs", "getLevelClass", "level", "log", "environment", "refreshInterval", "data", "setData", "connected", "setConnected", "lastUpdate", "setLastUpdate", "setSocket", "io", "newSocket", "newData", "error", "formatTime", "date", "appServices", "s", "dataServices"]
7
+ }