import * as plugins from '../plugins.js'; import * as shared from '../elements/shared/index.js'; import { DeesElement, customElement, html, state, css, cssManager, } from '@design.estate/dees-element'; import * as appstate from '../appstate.js'; @customElement('cloudly-view-services') export class CloudlyViewServices extends DeesElement { @state() private data: appstate.IDataState = { secretGroups: [], secretBundles: [], }; constructor() { super(); const subscription = appstate.dataState .select((stateArg) => stateArg) .subscribe((dataArg) => { this.data = dataArg; }); this.rxSubscriptions.push(subscription); } public static styles = [ cssManager.defaultStyles, shared.viewHostCss, css` .category-badge { padding: 2px 8px; border-radius: 4px; font-size: 0.9em; font-weight: 500; } .category-base { background: #2196f3; color: white; } .category-distributed { background: #9c27b0; color: white; } .category-workload { background: #4caf50; color: white; } .strategy-badge { padding: 2px 8px; border-radius: 4px; font-size: 0.85em; background: #444; color: #ccc; margin-left: 4px; } `, ]; private getCategoryIcon(category: string): string { switch (category) { case 'base': return 'lucide:ServerCog'; case 'distributed': return 'lucide:Network'; case 'workload': return 'lucide:Container'; default: return 'lucide:Box'; } } private getCategoryBadgeHtml(category: string): any { const className = `category-badge category-${category}`; return html`${category}`; } private getStrategyBadgeHtml(strategy: string): any { return html`${strategy}`; } public render() { return html` Services { return { Name: itemArg.data.name, Description: itemArg.data.description, Category: this.getCategoryBadgeHtml(itemArg.data.serviceCategory || 'workload'), 'Deployment Strategy': html` ${this.getStrategyBadgeHtml(itemArg.data.deploymentStrategy || 'custom')} ${itemArg.data.maxReplicas ? html`Max: ${itemArg.data.maxReplicas}` : ''} ${itemArg.data.antiAffinity ? html`⚡ Anti-affinity` : ''} `, 'Image': `${itemArg.data.imageId}:${itemArg.data.imageVersion}`, 'Scale Factor': itemArg.data.scaleFactor, 'Balancing': itemArg.data.balancingStrategy, 'Deployments': itemArg.data.deploymentIds?.length || 0, }; }} .dataActions=${[ { name: 'Add Service', iconName: 'plus', type: ['header', 'footer'], actionFunc: async (dataActionArg) => { const modal = await plugins.deesCatalog.DeesModal.createAndShow({ heading: 'Add Service', content: html` `, menuOptions: [ { name: 'Create Service', action: async (modalArg) => { const form = modalArg.shadowRoot.querySelector('dees-form') as any; const formData = await form.gatherData(); await appstate.dataState.dispatchAction(appstate.createServiceAction, { serviceData: { name: formData.name, description: formData.description, serviceCategory: formData.serviceCategory, deploymentStrategy: formData.deploymentStrategy, maxReplicas: formData.maxReplicas ? parseInt(formData.maxReplicas) : undefined, antiAffinity: formData.antiAffinity, imageId: formData.imageId, imageVersion: formData.imageVersion, scaleFactor: parseInt(formData.scaleFactor), balancingStrategy: formData.balancingStrategy, ports: { web: parseInt(formData.webPort), }, environment: {}, domains: [], deploymentIds: [], }, }); await modalArg.destroy(); }, }, { name: 'Cancel', action: async (modalArg) => { modalArg.destroy(); }, }, ], }); }, }, { name: 'Edit', iconName: 'edit', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg) => { const service = actionDataArg.item as plugins.interfaces.data.IService; const modal = await plugins.deesCatalog.DeesModal.createAndShow({ heading: `Edit Service: ${service.data.name}`, content: html` `, menuOptions: [ { name: 'Update Service', action: async (modalArg) => { const form = modalArg.shadowRoot.querySelector('dees-form') as any; const formData = await form.gatherData(); await appstate.dataState.dispatchAction(appstate.updateServiceAction, { serviceId: service.id, serviceData: { ...service.data, name: formData.name, description: formData.description, serviceCategory: formData.serviceCategory, deploymentStrategy: formData.deploymentStrategy, maxReplicas: formData.maxReplicas ? parseInt(formData.maxReplicas) : undefined, antiAffinity: formData.antiAffinity, imageVersion: formData.imageVersion, scaleFactor: parseInt(formData.scaleFactor), balancingStrategy: formData.balancingStrategy, }, }); await modalArg.destroy(); }, }, { name: 'Cancel', action: async (modalArg) => { modalArg.destroy(); }, }, ], }); }, }, { name: 'Deploy', iconName: 'rocket', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg) => { const service = actionDataArg.item as plugins.interfaces.data.IService; // TODO: Implement deployment action console.log('Deploy service:', service); }, }, { name: 'Delete', iconName: 'trash', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg) => { const service = actionDataArg.item as plugins.interfaces.data.IService; plugins.deesCatalog.DeesModal.createAndShow({ heading: `Delete Service: ${service.data.name}`, content: html`
Are you sure you want to delete this service?
${service.data.name}
${service.data.description}
This will also delete ${service.data.deploymentIds?.length || 0} deployment(s)
`, menuOptions: [ { name: 'Cancel', action: async (modalArg) => { await modalArg.destroy(); }, }, { name: 'Delete', action: async (modalArg) => { await appstate.dataState.dispatchAction(appstate.deleteServiceAction, { serviceId: service.id, }); await modalArg.destroy(); }, }, ], }); }, }, ] as plugins.deesCatalog.ITableAction[]} >
`; } }