feat(cluster): Add cluster setupMode (manual|hetzner|aws|digitalocean) with conditional Hetzner auto-provisioning; UI and dashboard improvements; dependency upgrades
This commit is contained in:
		| @@ -76,66 +76,82 @@ export class CloudlyDashboard extends DeesElement { | ||||
|             .viewTabs=${[ | ||||
|               { | ||||
|                 name: 'Overview', | ||||
|                 iconName: 'lucide:LayoutDashboard', | ||||
|                 element: CloudlyViewOverview, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'SecretGroups', | ||||
|                 iconName: 'lucide:ShieldCheck', | ||||
|                 element: CloudlyViewSecretGroups, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'SecretBundles', | ||||
|                 iconName: 'lucide:LockKeyhole', | ||||
|                 element: CloudlyViewSecretBundles, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Clusters', | ||||
|                 iconName: 'lucide:Network', | ||||
|                 element: CloudlyViewClusters, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'ExternalRegistries', | ||||
|                 iconName: 'lucide:Package', | ||||
|                 element: CloudlyViewExternalRegistries, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Images', | ||||
|                 iconName: 'lucide:Image', | ||||
|                 element: CloudlyViewImages, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Services', | ||||
|                 iconName: 'lucide:Layers', | ||||
|                 element: CloudlyViewServices, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Testing & Building', | ||||
|                 iconName: 'lucide:HardHat', | ||||
|                 element: CloudlyViewServices, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Deployments', | ||||
|                 iconName: 'lucide:Rocket', | ||||
|                 element: CloudlyViewDeployments, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'DNS', | ||||
|                 iconName: 'lucide:Globe', | ||||
|                 element: CloudlyViewDns, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Mails', | ||||
|                 iconName: 'lucide:Mail', | ||||
|                 element: CloudlyViewMails, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Logs', | ||||
|                 iconName: 'lucide:FileText', | ||||
|                 element: CloudlyViewLogs, | ||||
|               }, | ||||
|               { | ||||
|                 name: 's3', | ||||
|                 iconName: 'lucide:Cloud', | ||||
|                 element: CloudlyViewS3, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'DBs', | ||||
|                 iconName: 'lucide:Database', | ||||
|                 element: CloudlyViewDbs, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Backups', | ||||
|                 iconName: 'lucide:Save', | ||||
|                 element: CloudlyViewBackups, | ||||
|               }, | ||||
|               { | ||||
|                 name: 'Fleet', | ||||
|                 iconName: 'lucide:Truck', | ||||
|                 element: CloudlyViewBackups, | ||||
|               } | ||||
|             ] as plugins.deesCatalog.IView[]} | ||||
|   | ||||
| @@ -68,6 +68,18 @@ export class CloudlyViewClusters extends DeesElement { | ||||
|                       .description=${'a descriptive name for the cluster'} | ||||
|                       .value=${''} | ||||
|                     ></dees-input-text> | ||||
|                     <dees-input-dropdown | ||||
|                       .key=${'setupMode'} | ||||
|                       .label=${'Setup Mode'} | ||||
|                       .description=${'How the cluster infrastructure should be managed'} | ||||
|                       .options=${[ | ||||
|                         {option: 'manual', key: 'manual', description: 'Manual Setup - Add your own servers manually'}, | ||||
|                         {option: 'hetzner', key: 'hetzner', description: 'Hetzner Cloud - Auto-provision servers on Hetzner'}, | ||||
|                         {option: 'aws', key: 'aws', description: 'AWS - Auto-provision on Amazon Web Services (coming soon)', disabled: true}, | ||||
|                         {option: 'digitalocean', key: 'digitalocean', description: 'DigitalOcean - Auto-provision on DigitalOcean (coming soon)', disabled: true} | ||||
|                       ]} | ||||
|                       .selectedOption=${'manual'} | ||||
|                     ></dees-input-dropdown> | ||||
|                   </dees-form> | ||||
|                 `, | ||||
|                 menuOptions: [ | ||||
| @@ -76,6 +88,7 @@ export class CloudlyViewClusters extends DeesElement { | ||||
|                     action: async (modalArg) => { | ||||
|                       const data: { | ||||
|                         clusterName: string; | ||||
|                         setupMode: 'manual' | 'hetzner' | 'aws' | 'digitalocean'; | ||||
|                       } = (await modalArg.shadowRoot | ||||
|                         .querySelector('dees-form') | ||||
|                         .collectFormData()) as any; | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import * as plugins from '../plugins.js'; | ||||
| import * as shared from '../elements/shared/index.js'; | ||||
|  | ||||
| import { | ||||
| @@ -34,34 +33,124 @@ export class CloudlyViewOverview extends DeesElement { | ||||
|     cssManager.defaultStyles, | ||||
|     shared.viewHostCss, | ||||
|     css` | ||||
|       .clusterGrid { | ||||
|         display: grid; | ||||
|         grid-template-columns: ${cssManager.cssGridColumns(3, 8)}; | ||||
|         grid-gap: 16px; | ||||
|         margin-bottom: 40px; | ||||
|       dees-statsgrid { | ||||
|         margin-top: 24px; | ||||
|       } | ||||
|     `, | ||||
|   ]; | ||||
|  | ||||
|   public render() { | ||||
|     // Calculate total servers across all clusters | ||||
|     const totalServers = this.data.clusters?.reduce((sum, cluster) =>  | ||||
|       sum + (cluster.data.servers?.length || 0), 0) || 0; | ||||
|  | ||||
|     // Create tiles for the stats grid | ||||
|     const statsTiles = [ | ||||
|       { | ||||
|         id: 'clusters', | ||||
|         title: 'Total Clusters', | ||||
|         value: this.data.clusters?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Network', | ||||
|         description: 'Active clusters' | ||||
|       }, | ||||
|       { | ||||
|         id: 'servers', | ||||
|         title: 'Total Servers', | ||||
|         value: totalServers, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Server', | ||||
|         description: 'Connected servers' | ||||
|       }, | ||||
|       { | ||||
|         id: 'services', | ||||
|         title: 'Services', | ||||
|         value: this.data.services?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Layers', | ||||
|         description: 'Deployed services' | ||||
|       }, | ||||
|       { | ||||
|         id: 'deployments', | ||||
|         title: 'Deployments', | ||||
|         value: this.data.deployments?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Rocket', | ||||
|         description: 'Active deployments' | ||||
|       }, | ||||
|       { | ||||
|         id: 'secretGroups', | ||||
|         title: 'Secret Groups', | ||||
|         value: this.data.secretGroups?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:ShieldCheck', | ||||
|         description: 'Configured secret groups' | ||||
|       }, | ||||
|       { | ||||
|         id: 'secretBundles', | ||||
|         title: 'Secret Bundles', | ||||
|         value: this.data.secretBundles?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:LockKeyhole', | ||||
|         description: 'Available secret bundles' | ||||
|       }, | ||||
|       { | ||||
|         id: 'images', | ||||
|         title: 'Images', | ||||
|         value: this.data.images?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Image', | ||||
|         description: 'Container images' | ||||
|       }, | ||||
|       { | ||||
|         id: 'dns', | ||||
|         title: 'DNS Zones', | ||||
|         value: this.data.dns?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Globe', | ||||
|         description: 'Managed DNS zones' | ||||
|       }, | ||||
|       { | ||||
|         id: 'databases', | ||||
|         title: 'Databases', | ||||
|         value: this.data.dbs?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Database', | ||||
|         description: 'Database instances' | ||||
|       }, | ||||
|       { | ||||
|         id: 'backups', | ||||
|         title: 'Backups', | ||||
|         value: this.data.backups?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Save', | ||||
|         description: 'Available backups' | ||||
|       }, | ||||
|       { | ||||
|         id: 'mails', | ||||
|         title: 'Mail Domains', | ||||
|         value: this.data.mails?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Mail', | ||||
|         description: 'Mail configurations' | ||||
|       }, | ||||
|       { | ||||
|         id: 's3', | ||||
|         title: 'S3 Buckets', | ||||
|         value: this.data.s3?.length || 0, | ||||
|         type: 'number' as const, | ||||
|         iconName: 'lucide:Cloud', | ||||
|         description: 'Storage buckets' | ||||
|       } | ||||
|     ]; | ||||
|  | ||||
|     return html` | ||||
|       <cloudly-sectionheading>Overview</cloudly-sectionheading> | ||||
|       ${this.data.clusters.length === 0 ? html` | ||||
|         You need to create at least one cluster to see an overview. | ||||
|       `: html``} | ||||
|       ${this.data.clusters.map( | ||||
|         (clusterArg) => html` | ||||
|           <dees-label .label=${'cluster: ' + clusterArg.data.name}></dees-label> | ||||
|           <div class="clusterGrid"> | ||||
|             <dees-chart-area .label=${'System Usage'}></dees-chart-area> | ||||
|             <dees-chart-area .label=${'Internet Traffic'}></dees-chart-area> | ||||
|             <dees-chart-area .label=${'Requests'}></dees-chart-area> | ||||
|             <dees-chart-area .label=${'WebSocket Connections'}></dees-chart-area> | ||||
|             <dees-chart-log class="services" .label=${'Deployed Services'}></dees-chart-log> | ||||
|             <dees-chart-log class="eventLog" .label=${'Event Log'}></dees-chart-log> | ||||
|           </div> | ||||
|         ` | ||||
|       )} | ||||
|       <dees-statsgrid | ||||
|         .tiles=${statsTiles} | ||||
|         .minTileWidth=${250} | ||||
|         .gap=${16} | ||||
|       ></dees-statsgrid> | ||||
|     `; | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user