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