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:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/cloudly',
|
||||
version: '5.0.6',
|
||||
version: '5.1.0',
|
||||
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
|
||||
}
|
||||
|
@@ -245,6 +245,7 @@ export const addClusterAction = dataState.createAction(
|
||||
statePartArg,
|
||||
payloadArg: {
|
||||
clusterName: string;
|
||||
setupMode?: 'manual' | 'hetzner' | 'aws' | 'digitalocean';
|
||||
}
|
||||
) => {
|
||||
let currentState = statePartArg.getState();
|
||||
|
@@ -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