feat(domains): enhance domain management with activation states and sync options
This commit is contained in:
		| @@ -69,12 +69,15 @@ export class DnsManager { | |||||||
|             this.cloudlyRef.authManager.validIdentityGuard, |             this.cloudlyRef.authManager.validIdentityGuard, | ||||||
|           ]); |           ]); | ||||||
|  |  | ||||||
|           // Validate domain exists if domainId is provided |           // Validate domain exists and is activated if domainId is provided | ||||||
|           if (reqArg.dnsEntryData.domainId) { |           if (reqArg.dnsEntryData.domainId) { | ||||||
|             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); |             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); | ||||||
|             if (!domain) { |             if (!domain) { | ||||||
|               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); |               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); | ||||||
|             } |             } | ||||||
|  |             if ((domain.data as any).activationState !== 'activated') { | ||||||
|  |               throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`); | ||||||
|  |             } | ||||||
|             // Set the zone from the domain name |             // Set the zone from the domain name | ||||||
|             reqArg.dnsEntryData.zone = domain.data.name; |             reqArg.dnsEntryData.zone = domain.data.name; | ||||||
|           } |           } | ||||||
| @@ -97,12 +100,15 @@ export class DnsManager { | |||||||
|             this.cloudlyRef.authManager.validIdentityGuard, |             this.cloudlyRef.authManager.validIdentityGuard, | ||||||
|           ]); |           ]); | ||||||
|  |  | ||||||
|           // Validate domain exists if domainId is provided |           // Validate domain exists and is activated if domainId is provided | ||||||
|           if (reqArg.dnsEntryData.domainId) { |           if (reqArg.dnsEntryData.domainId) { | ||||||
|             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); |             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); | ||||||
|             if (!domain) { |             if (!domain) { | ||||||
|               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); |               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); | ||||||
|             } |             } | ||||||
|  |             if ((domain.data as any).activationState !== 'activated') { | ||||||
|  |               throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`); | ||||||
|  |             } | ||||||
|             // Set the zone from the domain name |             // Set the zone from the domain name | ||||||
|             reqArg.dnsEntryData.zone = domain.data.name; |             reqArg.dnsEntryData.zone = domain.data.name; | ||||||
|           } |           } | ||||||
| @@ -258,4 +264,4 @@ export class DnsManager { | |||||||
|   public async stop() { |   public async stop() { | ||||||
|     console.log('DNS Manager stopped'); |     console.log('DNS Manager stopped'); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -36,6 +36,9 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | |||||||
|       verificationStatus: domainDataArg.verificationStatus || 'pending', |       verificationStatus: domainDataArg.verificationStatus || 'pending', | ||||||
|       nameservers: domainDataArg.nameservers || [], |       nameservers: domainDataArg.nameservers || [], | ||||||
|       autoRenew: domainDataArg.autoRenew !== false, |       autoRenew: domainDataArg.autoRenew !== false, | ||||||
|  |       activationState: domainDataArg.activationState || 'available', | ||||||
|  |       syncSource: domainDataArg.syncSource ?? null, | ||||||
|  |       lastSyncAt: domainDataArg.lastSyncAt, | ||||||
|       createdAt: Date.now(), |       createdAt: Date.now(), | ||||||
|       updatedAt: Date.now(), |       updatedAt: Date.now(), | ||||||
|     }; |     }; | ||||||
| @@ -55,6 +58,7 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | |||||||
|     } |     } | ||||||
|     Object.assign(domain.data, domainDataArg, { |     Object.assign(domain.data, domainDataArg, { | ||||||
|       updatedAt: Date.now(), |       updatedAt: Date.now(), | ||||||
|  |       activationState: domain.data.activationState || 'available', | ||||||
|     }); |     }); | ||||||
|     await domain.save(); |     await domain.save(); | ||||||
|     return domain; |     return domain; | ||||||
| @@ -201,4 +205,4 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | |||||||
|     }); |     }); | ||||||
|     return dnsEntries; |     return dnsEntries; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,6 +7,86 @@ import { logger } from '../logger.js'; | |||||||
|  */ |  */ | ||||||
| export function createPredefinedTasks(taskManager: CloudlyTaskManager) { | export function createPredefinedTasks(taskManager: CloudlyTaskManager) { | ||||||
|    |    | ||||||
|  |   // Cloudflare Domain Sync Task | ||||||
|  |   const cfDomainSync = new plugins.taskbuffer.Task({ | ||||||
|  |     name: 'cloudflare-domain-sync', | ||||||
|  |     taskFunction: async () => { | ||||||
|  |       const execution = taskManager.getCurrentExecution('cloudflare-domain-sync'); | ||||||
|  |       try { | ||||||
|  |         await execution?.addLog('Starting Cloudflare domain sync…', 'info'); | ||||||
|  |         const cf = taskManager.cloudlyRef.cloudflareConnector?.cloudflare; | ||||||
|  |         if (!cf) { | ||||||
|  |           await execution?.addLog('Cloudflare not configured; skipping sync.', 'warning'); | ||||||
|  |           return { created: 0, updated: 0, totalZones: 0 }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const zones = await cf.convenience.listZones(); | ||||||
|  |         await execution?.setMetric('totalZones', zones.length); | ||||||
|  |         await execution?.addLog(`Fetched ${zones.length} zones from Cloudflare`, 'info'); | ||||||
|  |  | ||||||
|  |         let created = 0; | ||||||
|  |         let updated = 0; | ||||||
|  |         const now = Date.now(); | ||||||
|  |  | ||||||
|  |         for (const zone of zones) { | ||||||
|  |           // zone fields from Cloudflare typings | ||||||
|  |           const zoneName = (zone as any).name as string; | ||||||
|  |           const zoneId = (zone as any).id as string; | ||||||
|  |           const zoneStatus = ((zone as any).status || 'active') as 'active'|'pending'|'suspended'|'transferred'|'expired'; | ||||||
|  |           const nameServers: string[] = (zone as any).name_servers || []; | ||||||
|  |  | ||||||
|  |           const existing = await taskManager.cloudlyRef.domainManager.CDomain.getDomainByName(zoneName); | ||||||
|  |           if (existing) { | ||||||
|  |             if (execution && (taskManager.isCancellationRequested(execution.id) || existing.data == null)) { | ||||||
|  |               await execution?.addLog('Cancellation requested. Stopping CF sync…', 'warning'); | ||||||
|  |               break; | ||||||
|  |             } | ||||||
|  |             await execution?.addLog(`Updating domain: ${zoneName}`, 'info'); | ||||||
|  |             await taskManager.cloudlyRef.domainManager.CDomain.updateDomain(existing.id, { | ||||||
|  |               status: zoneStatus as any, | ||||||
|  |               nameservers: nameServers, | ||||||
|  |               cloudflareZoneId: zoneId, | ||||||
|  |               syncSource: 'cloudflare', | ||||||
|  |               lastSyncAt: now, | ||||||
|  |               activationState: existing.data.activationState || 'available', | ||||||
|  |             }); | ||||||
|  |             updated++; | ||||||
|  |           } else { | ||||||
|  |             await execution?.addLog(`Creating domain: ${zoneName}`, 'info'); | ||||||
|  |             await taskManager.cloudlyRef.domainManager.CDomain.createDomain({ | ||||||
|  |               name: zoneName, | ||||||
|  |               description: `Synced from Cloudflare zone ${zoneId}`, | ||||||
|  |               status: zoneStatus as any, | ||||||
|  |               verificationStatus: 'pending', | ||||||
|  |               nameservers: nameServers, | ||||||
|  |               autoRenew: true, | ||||||
|  |               cloudflareZoneId: zoneId, | ||||||
|  |               activationState: 'available', | ||||||
|  |               syncSource: 'cloudflare', | ||||||
|  |               lastSyncAt: now, | ||||||
|  |             } as any); | ||||||
|  |             created++; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await execution?.setMetric('created', created); | ||||||
|  |         await execution?.setMetric('updated', updated); | ||||||
|  |         await execution?.addLog(`Cloudflare sync done: ${created} created, ${updated} updated`, 'success'); | ||||||
|  |         return { created, updated, totalZones: zones.length }; | ||||||
|  |       } catch (error) { | ||||||
|  |         await execution?.addLog(`Cloudflare sync error: ${error.message}`, 'error'); | ||||||
|  |         throw error; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   taskManager.registerTask('cloudflare-domain-sync', cfDomainSync, { | ||||||
|  |     description: 'Import and update domains from Cloudflare zones', | ||||||
|  |     category: 'system', | ||||||
|  |     schedule: '0 3 * * *', // Daily at 3 AM | ||||||
|  |     enabled: true, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   // DNS Sync Task |   // DNS Sync Task | ||||||
|   const dnsSync = new plugins.taskbuffer.Task({ |   const dnsSync = new plugins.taskbuffer.Task({ | ||||||
|     name: 'dns-sync', |     name: 'dns-sync', | ||||||
| @@ -79,8 +159,10 @@ export function createPredefinedTasks(taskManager: CloudlyTaskManager) { | |||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         // Get all domains |         // Get all domains (only activated ones are considered for renewal) | ||||||
|         const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({}); |         const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({ | ||||||
|  |           'data.activationState': 'activated', | ||||||
|  |         } as any); | ||||||
|         await execution?.setMetric('totalDomains', domains.length); |         await execution?.setMetric('totalDomains', domains.length); | ||||||
|          |          | ||||||
|         let renewedCount = 0; |         let renewedCount = 0; | ||||||
|   | |||||||
| @@ -71,6 +71,14 @@ export interface IDomain { | |||||||
|      * SSL certificate status |      * SSL certificate status | ||||||
|      */ |      */ | ||||||
|     sslStatus?: 'active' | 'pending' | 'expired' | 'none'; |     sslStatus?: 'active' | 'pending' | 'expired' | 'none'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cloudly activation state controls whether we actively manage DNS/certificates | ||||||
|  |      * - available: discovered/imported, not actively managed | ||||||
|  |      * - activated: actively managed (DNS edits allowed, certs considered) | ||||||
|  |      * - ignored: explicitly ignored from management/automation | ||||||
|  |      */ | ||||||
|  |     activationState?: 'available' | 'activated' | 'ignored'; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Last verification attempt timestamp |      * Last verification attempt timestamp | ||||||
| @@ -91,6 +99,12 @@ export interface IDomain { | |||||||
|      * Cloudflare zone ID if managed by Cloudflare |      * Cloudflare zone ID if managed by Cloudflare | ||||||
|      */ |      */ | ||||||
|     cloudflareZoneId?: string; |     cloudflareZoneId?: string; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sync metadata | ||||||
|  |      */ | ||||||
|  |     syncSource?: 'cloudflare' | 'manual' | null; | ||||||
|  |     lastSyncAt?: number; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Whether domain is managed externally |      * Whether domain is managed externally | ||||||
| @@ -107,4 +121,4 @@ export interface IDomain { | |||||||
|      */ |      */ | ||||||
|     updatedAt?: number; |     updatedAt?: number; | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -93,6 +93,12 @@ export class CloudlyViewDns extends DeesElement { | |||||||
|                   { name: 'Create DNS Entry', action: async (modalArg: any) => { |                   { name: 'Create DNS Entry', action: async (modalArg: any) => { | ||||||
|                       const form = modalArg.shadowRoot.querySelector('dees-form') as any; |                       const form = modalArg.shadowRoot.querySelector('dees-form') as any; | ||||||
|                       const formData = await form.gatherData(); |                       const formData = await form.gatherData(); | ||||||
|  |                       // Guard: only allow on activated domains | ||||||
|  |                       const domain = (this.data.domains || []).find((d: any) => d.id === formData.domainId); | ||||||
|  |                       if (!domain || (domain.data as any).activationState !== 'activated') { | ||||||
|  |                         plugins.deesCatalog.DeesToast.createAndShow({ message: 'Selected domain is not activated. Activate it first.', type: 'error' }); | ||||||
|  |                         return; | ||||||
|  |                       } | ||||||
|                       await appstate.dataState.dispatchAction(appstate.createDnsEntryAction, { dnsEntryData: { type: formData.type, domainId: formData.domainId, zone: '', name: formData.name || '@', value: formData.value, ttl: parseInt(formData.ttl) || 3600, priority: formData.priority ? parseInt(formData.priority) : undefined, weight: formData.weight ? parseInt(formData.weight) : undefined, port: formData.port ? parseInt(formData.port) : undefined, active: formData.active, description: formData.description || undefined, }, }); |                       await appstate.dataState.dispatchAction(appstate.createDnsEntryAction, { dnsEntryData: { type: formData.type, domainId: formData.domainId, zone: '', name: formData.name || '@', value: formData.value, ttl: parseInt(formData.ttl) || 3600, priority: formData.priority ? parseInt(formData.priority) : undefined, weight: formData.weight ? parseInt(formData.weight) : undefined, port: formData.port ? parseInt(formData.port) : undefined, active: formData.active, description: formData.description || undefined, }, }); | ||||||
|                       await modalArg.destroy(); |                       await modalArg.destroy(); | ||||||
|                     } }, |                     } }, | ||||||
| @@ -123,6 +129,13 @@ export class CloudlyViewDns extends DeesElement { | |||||||
|                   { name: 'Update DNS Entry', action: async (modalArg: any) => { |                   { name: 'Update DNS Entry', action: async (modalArg: any) => { | ||||||
|                       const form = modalArg.shadowRoot.querySelector('dees-form') as any; |                       const form = modalArg.shadowRoot.querySelector('dees-form') as any; | ||||||
|                       const formData = await form.gatherData(); |                       const formData = await form.gatherData(); | ||||||
|  |                       if (formData.domainId) { | ||||||
|  |                         const domain = (this.data.domains || []).find((d: any) => d.id === formData.domainId); | ||||||
|  |                         if (!domain || (domain.data as any).activationState !== 'activated') { | ||||||
|  |                           plugins.deesCatalog.DeesToast.createAndShow({ message: 'Selected domain is not activated. Activate it first.', type: 'error' }); | ||||||
|  |                           return; | ||||||
|  |                         } | ||||||
|  |                       } | ||||||
|                       await appstate.dataState.dispatchAction(appstate.updateDnsEntryAction, { dnsEntryId: dnsEntry.id, dnsEntryData: { ...dnsEntry.data, type: formData.type, domainId: formData.domainId, zone: '', name: formData.name || '@', value: formData.value, ttl: parseInt(formData.ttl) || 3600, priority: formData.priority ? parseInt(formData.priority) : undefined, weight: formData.weight ? parseInt(formData.weight) : undefined, port: formData.port ? parseInt(formData.port) : undefined, active: formData.active, description: formData.description || undefined, }, }); |                       await appstate.dataState.dispatchAction(appstate.updateDnsEntryAction, { dnsEntryId: dnsEntry.id, dnsEntryData: { ...dnsEntry.data, type: formData.type, domainId: formData.domainId, zone: '', name: formData.name || '@', value: formData.value, ttl: parseInt(formData.ttl) || 3600, priority: formData.priority ? parseInt(formData.priority) : undefined, weight: formData.weight ? parseInt(formData.weight) : undefined, port: formData.port ? parseInt(formData.port) : undefined, active: formData.active, description: formData.description || undefined, }, }); | ||||||
|                       await modalArg.destroy(); |                       await modalArg.destroy(); | ||||||
|                     } }, |                     } }, | ||||||
| @@ -140,4 +153,3 @@ export class CloudlyViewDns extends DeesElement { | |||||||
| } | } | ||||||
|  |  | ||||||
| declare global { interface HTMLElementTagNameMap { 'cloudly-view-dns': CloudlyViewDns; } } | declare global { interface HTMLElementTagNameMap { 'cloudly-view-dns': CloudlyViewDns; } } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,6 +37,10 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
|       .ssl-expired { color: #f44336; } |       .ssl-expired { color: #f44336; } | ||||||
|       .ssl-none { color: #9E9E9E; } |       .ssl-none { color: #9E9E9E; } | ||||||
|       .nameserver-list { font-size: 0.85em; color: #666; } |       .nameserver-list { font-size: 0.85em; color: #666; } | ||||||
|  |       .activation-badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.85em; font-weight: 500; } | ||||||
|  |       .activation-available { background: #2b2b2b; color: #bbb; border: 1px solid #444; } | ||||||
|  |       .activation-activated { background: #4CAF50; color: #fff; } | ||||||
|  |       .activation-ignored { background: #9E9E9E; color: #fff; } | ||||||
|       .expiry-warning { color: #FF9800; font-weight: 500; } |       .expiry-warning { color: #FF9800; font-weight: 500; } | ||||||
|       .expiry-critical { color: #f44336; font-weight: bold; } |       .expiry-critical { color: #f44336; font-weight: bold; } | ||||||
|     `, |     `, | ||||||
| @@ -45,6 +49,7 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
|   private getStatusBadge(status: string) { return html`<span class="status-badge status-${status}">${status.toUpperCase()}</span>`; } |   private getStatusBadge(status: string) { return html`<span class="status-badge status-${status}">${status.toUpperCase()}</span>`; } | ||||||
|   private getVerificationBadge(status: string) { const displayText = status === 'not_required' ? 'Not Required' : status.replace('_', ' ').toUpperCase(); return html`<span class="verification-badge verification-${status}">${displayText}</span>`; } |   private getVerificationBadge(status: string) { const displayText = status === 'not_required' ? 'Not Required' : status.replace('_', ' ').toUpperCase(); return html`<span class="verification-badge verification-${status}">${displayText}</span>`; } | ||||||
|   private getSslBadge(sslStatus?: string) { if (!sslStatus) return html`<span class="ssl-badge ssl-none">—</span>`; const icon = sslStatus === 'active' ? '🔒' : sslStatus === 'expired' ? '⚠️' : '🔓'; return html`<span class="ssl-badge ssl-${sslStatus}">${icon} ${sslStatus.toUpperCase()}</span>`; } |   private getSslBadge(sslStatus?: string) { if (!sslStatus) return html`<span class="ssl-badge ssl-none">—</span>`; const icon = sslStatus === 'active' ? '🔒' : sslStatus === 'expired' ? '⚠️' : '🔓'; return html`<span class="ssl-badge ssl-${sslStatus}">${icon} ${sslStatus.toUpperCase()}</span>`; } | ||||||
|  |   private getActivationBadge(state?: 'available'|'activated'|'ignored') { const s = state || 'available'; return html`<span class="activation-badge activation-${s}">${s.toUpperCase()}</span>`; } | ||||||
|   private formatDate(timestamp?: number) { if (!timestamp) return '—'; const date = new Date(timestamp); return date.toLocaleDateString(); } |   private formatDate(timestamp?: number) { if (!timestamp) return '—'; const date = new Date(timestamp); return date.toLocaleDateString(); } | ||||||
|   private getDaysUntilExpiry(expiresAt?: number) { if (!expiresAt) return null; const days = Math.floor((expiresAt - Date.now()) / (1000 * 60 * 60 * 24)); return days; } |   private getDaysUntilExpiry(expiresAt?: number) { if (!expiresAt) return null; const days = Math.floor((expiresAt - Date.now()) / (1000 * 60 * 60 * 24)); return days; } | ||||||
|   private getExpiryDisplay(expiresAt?: number) { const days = this.getDaysUntilExpiry(expiresAt); if (days === null) return '—'; if (days < 0) { return html`<span class="expiry-critical">Expired ${Math.abs(days)} days ago</span>`; } else if (days <= 30) { return html`<span class="expiry-warning">Expires in ${days} days</span>`; } else { return `${days} days`; } } |   private getExpiryDisplay(expiresAt?: number) { const days = this.getDaysUntilExpiry(expiresAt); if (days === null) return '—'; if (days < 0) { return html`<span class="expiry-critical">Expired ${Math.abs(days)} days ago</span>`; } else if (days <= 30) { return html`<span class="expiry-warning">Expires in ${days} days</span>`; } else { return `${days} days`; } } | ||||||
| @@ -63,6 +68,7 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
|             Status: this.getStatusBadge(itemArg.data.status), |             Status: this.getStatusBadge(itemArg.data.status), | ||||||
|             Verification: this.getVerificationBadge(itemArg.data.verificationStatus), |             Verification: this.getVerificationBadge(itemArg.data.verificationStatus), | ||||||
|             SSL: this.getSslBadge(itemArg.data.sslStatus), |             SSL: this.getSslBadge(itemArg.data.sslStatus), | ||||||
|  |             Activation: this.getActivationBadge((itemArg.data as any).activationState), | ||||||
|             'DNS Records': dnsCount, |             'DNS Records': dnsCount, | ||||||
|             Registrar: itemArg.data.registrar?.name || '—', |             Registrar: itemArg.data.registrar?.name || '—', | ||||||
|             Expires: this.getExpiryDisplay(itemArg.data.expiresAt), |             Expires: this.getExpiryDisplay(itemArg.data.expiresAt), | ||||||
| @@ -71,6 +77,7 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
|           }; |           }; | ||||||
|         }} |         }} | ||||||
|         .dataActions=${[ |         .dataActions=${[ | ||||||
|  |           { name: 'Sync from Cloudflare', iconName: 'cloud', type: ['header'], actionFunc: async () => { await appstate.dataState.dispatchAction(appstate.taskActions.triggerTask, { taskName: 'cloudflare-domain-sync' } as any); await appstate.dataState.dispatchAction(appstate.getAllDataAction, null); plugins.deesCatalog.DeesToast.createAndShow({ message: 'Triggered Cloudflare sync', type: 'success' }); } }, | ||||||
|           { name: 'Add Domain', iconName: 'plus', type: ['header', 'footer'], actionFunc: async () => { |           { name: 'Add Domain', iconName: 'plus', type: ['header', 'footer'], actionFunc: async () => { | ||||||
|               const modal = await plugins.deesCatalog.DeesModal.createAndShow({ |               const modal = await plugins.deesCatalog.DeesModal.createAndShow({ | ||||||
|                 heading: 'Add Domain', |                 heading: 'Add Domain', | ||||||
| @@ -164,6 +171,9 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
|                 menuOptions: [ { name: 'Cancel', action: async (modalArg: any) => { await modalArg.destroy(); } }, { name: 'Delete', action: async (modalArg: any) => { await appstate.dataState.dispatchAction(appstate.deleteDomainAction, { domainId: domain.id, }); await modalArg.destroy(); } }, ], |                 menuOptions: [ { name: 'Cancel', action: async (modalArg: any) => { await modalArg.destroy(); } }, { name: 'Delete', action: async (modalArg: any) => { await appstate.dataState.dispatchAction(appstate.deleteDomainAction, { domainId: domain.id, }); await modalArg.destroy(); } }, ], | ||||||
|               }); |               }); | ||||||
|             } }, |             } }, | ||||||
|  |           { name: 'Activate', iconName: 'check', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg: any) => { const domain = actionDataArg.item as plugins.interfaces.data.IDomain; await appstate.dataState.dispatchAction(appstate.updateDomainAction, { domainId: domain.id, domainData: { ...(domain.data as any), activationState: 'activated' } as any }); } }, | ||||||
|  |           { name: 'Deactivate', iconName: 'slash', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg: any) => { const domain = actionDataArg.item as plugins.interfaces.data.IDomain; await appstate.dataState.dispatchAction(appstate.updateDomainAction, { domainId: domain.id, domainData: { ...(domain.data as any), activationState: 'available' } as any }); } }, | ||||||
|  |           { name: 'Ignore', iconName: 'ban', type: ['contextmenu', 'inRow'], actionFunc: async (actionDataArg: any) => { const domain = actionDataArg.item as plugins.interfaces.data.IDomain; await appstate.dataState.dispatchAction(appstate.updateDomainAction, { domainId: domain.id, domainData: { ...(domain.data as any), activationState: 'ignored' } as any }); } }, | ||||||
|         ] as plugins.deesCatalog.ITableAction[]} |         ] as plugins.deesCatalog.ITableAction[]} | ||||||
|       ></dees-table> |       ></dees-table> | ||||||
|     `; |     `; | ||||||
| @@ -173,4 +183,3 @@ export class CloudlyViewDomains extends DeesElement { | |||||||
| declare global { | declare global { | ||||||
|   interface HTMLElementTagNameMap { 'cloudly-view-domains': CloudlyViewDomains; } |   interface HTMLElementTagNameMap { 'cloudly-view-domains': CloudlyViewDomains; } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user