2025-09-14 17:28:21 +00:00
import * as plugins from '../../../plugins.js' ;
import * as shared from '../../shared/index.js' ;
import {
DeesElement ,
customElement ,
html ,
state ,
css ,
cssManager ,
} from '@design.estate/dees-element' ;
import * as appstate from '../../../appstate.js' ;
@customElement ( 'cloudly-view-dns' )
export class CloudlyViewDns extends DeesElement {
@state ( )
private data : appstate.IDataState = { secretGroups : [ ] , secretBundles : [ ] , dnsEntries : [ ] , domains : [ ] } as any ;
constructor ( ) {
super ( ) ;
const subscription = appstate . dataState . select ( ( stateArg ) = > stateArg ) . subscribe ( ( dataArg ) = > { this . data = dataArg ; } ) ;
this . rxSubscriptions . push ( subscription ) ;
}
async connectedCallback() {
super . connectedCallback ( ) ;
await appstate . dataState . dispatchAction ( appstate . getAllDataAction , { } ) ;
}
public static styles = [
cssManager . defaultStyles ,
shared . viewHostCss ,
css `
. dns - type - badge { display : inline - block ; padding : 2px 8 px ; border - radius : 4px ; font - size : 0.85em ; font - weight : 500 ; color : white ; }
. type - A { background : # 4 CAF50 ; }
. type - AAAA { background : # 45 a049 ; }
. type - CNAME { background : # 2196 F3 ; }
. type - MX { background : # FF9800 ; }
. type - TXT { background : # 9 C27B0 ; }
. type - NS { background : # 795548 ; }
. type - SOA { background : # 607 D8B ; }
. type - SRV { background : # E91E63 ; }
. type - CAA { background : # 00 BCD4 ; }
. type - PTR { background : # 673 AB7 ; }
. status - active { color : # 4 CAF50 ; }
. status - inactive { color : # f44336 ; }
` ,
] ;
private getRecordTypeBadge ( type : string ) { return html ` <span class="dns-type-badge type- ${ type } "> ${ type } </span> ` ; }
private getStatusBadge ( active : boolean ) { return html ` <span class=" ${ active ? 'status-active' : 'status-inactive' } "> ${ active ? '✓ Active' : '✗ Inactive' } </span> ` ; }
public render() {
return html `
< cloudly - sectionheading > DNS Management < / c l o u d l y - s e c t i o n h e a d i n g >
< dees - table
. heading1 = $ { 'DNS Entries' }
. heading2 = $ { 'Manage DNS records for your domains' }
. data = $ { this . data . dnsEntries || [ ] }
. displayFunction = $ { ( itemArg : plugins.interfaces.data.IDnsEntry ) = > {
return {
Type : this.getRecordTypeBadge ( itemArg . data . type ) ,
Name : itemArg.data.name === '@' ? '<root>' : itemArg . data . name ,
Value : itemArg.data.value ,
TTL : ` ${ itemArg . data . ttl } s ` ,
Priority : itemArg.data.priority || '-' ,
Zone : itemArg.data.zone ,
Status : this.getStatusBadge ( itemArg . data . active ) ,
Description : itemArg.data.description || '-' ,
} ;
} }
. dataActions = $ { [
{ name : 'Add DNS Entry' , iconName : 'plus' , type : [ 'header' , 'footer' ] , actionFunc : async ( ) = > {
const modal = await plugins . deesCatalog . DeesModal . createAndShow ( {
heading : 'Add DNS Entry' ,
content : html `
< dees - form >
< dees - input - dropdown .key = $ { 'type' } .label = $ { 'Record Type' } .options = $ { [
{ key : 'A' , option : 'A - IPv4 Address' } , { key : 'AAAA' , option : 'AAAA - IPv6 Address' } , { key : 'CNAME' , option : 'CNAME - Canonical Name' } , { key : 'MX' , option : 'MX - Mail Exchange' } , { key : 'TXT' , option : 'TXT - Text Record' } , { key : 'NS' , option : 'NS - Name Server' } , { key : 'SOA' , option : 'SOA - Start of Authority' } , { key : 'SRV' , option : 'SRV - Service' } , { key : 'CAA' , option : 'CAA - Certification Authority' } , { key : 'PTR' , option : 'PTR - Pointer' } , ] } . value = $ { 'A' } . required = $ { true } > < / d e e s - i n p u t - d r o p d o w n >
< dees - input - dropdown .key = $ { 'domainId' } .label = $ { 'Domain' } .options = $ { this.data.domains ? .map ( domain = > ( { key : domain.id , option : domain.data.name } ) ) || [ ] } . required = $ { true } > < / d e e s - i n p u t - d r o p d o w n >
< dees - input - text .key = $ { 'name' } .label = $ { 'Name' } .placeholder = $ { '@ for root, www, mail, etc.' } .value = $ { '@' } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'value' } .label = $ { 'Value' } .placeholder = $ { 'IP address, domain, or text value' } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'ttl' } .label = $ { 'TTL (seconds)' } .value = $ { '3600' } .type = $ { 'number' } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'priority' } .label = $ { 'Priority (MX/SRV only)' } .type = $ { 'number' } .placeholder = $ { '10' } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'weight' } .label = $ { 'Weight (SRV only)' } .type = $ { 'number' } .placeholder = $ { '0' } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'port' } .label = $ { 'Port (SRV only)' } .type = $ { 'number' } .placeholder = $ { '443' } > < / d e e s - i n p u t - t e x t >
< dees - input - checkbox .key = $ { 'active' } .label = $ { 'Active' } .value = $ { true } > < / d e e s - i n p u t - c h e c k b o x >
< dees - input - text .key = $ { 'description' } .label = $ { 'Description (optional)' } .placeholder = $ { 'What is this record for?' } > < / d e e s - i n p u t - t e x t >
< / d e e s - f o r m >
` ,
menuOptions : [
{ name : 'Create DNS Entry' , action : async ( modalArg : any ) = > {
const form = modalArg . shadowRoot . querySelector ( 'dees-form' ) as any ;
const formData = await form . gatherData ( ) ;
2025-09-14 17:38:16 +00:00
// 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 ;
}
2025-09-14 17:28:21 +00:00
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 ( ) ;
} } ,
{ name : 'Cancel' , action : async ( modalArg : any ) = > modalArg . destroy ( ) } ,
] ,
} ) ;
} } ,
{ name : 'Edit' , iconName : 'edit' , type : [ 'contextmenu' , 'inRow' ] , actionFunc : async ( actionDataArg : any ) = > {
const dnsEntry = actionDataArg . item as plugins . interfaces . data . IDnsEntry ;
const modal = await plugins . deesCatalog . DeesModal . createAndShow ( {
heading : ` Edit DNS Entry ` ,
content : html `
< dees - form >
< dees - input - dropdown .key = $ { 'type' } .label = $ { 'Record Type' } .options = $ { [
{ key : 'A' , option : 'A - IPv4 Address' } , { key : 'AAAA' , option : 'AAAA - IPv6 Address' } , { key : 'CNAME' , option : 'CNAME - Canonical Name' } , { key : 'MX' , option : 'MX - Mail Exchange' } , { key : 'TXT' , option : 'TXT - Text Record' } , { key : 'NS' , option : 'NS - Name Server' } , { key : 'SOA' , option : 'SOA - Start of Authority' } , { key : 'SRV' , option : 'SRV - Service' } , { key : 'CAA' , option : 'CAA - Certification Authority' } , { key : 'PTR' , option : 'PTR - Pointer' } , ] } . value = $ { dnsEntry . data . type } . required = $ { true } > < / d e e s - i n p u t - d r o p d o w n >
< dees - input - dropdown .key = $ { 'domainId' } .label = $ { 'Domain' } .options = $ { this.data.domains ? .map ( domain = > ( { key : domain.id , option : domain.data.name } ) ) || [ ] } . value = $ { dnsEntry . data . domainId || '' } . required = $ { true } > < / d e e s - i n p u t - d r o p d o w n >
< dees - input - text .key = $ { 'name' } .label = $ { 'Name' } .value = $ { dnsEntry.data.name } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'value' } .label = $ { 'Value' } .value = $ { dnsEntry.data.value } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'ttl' } .label = $ { 'TTL (seconds)' } .value = $ { dnsEntry.data.ttl } .type = $ { 'number' } .required = $ { true } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'priority' } .label = $ { 'Priority (MX/SRV only)' } .value = $ { dnsEntry.data.priority | | '' } .type = $ { 'number' } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'weight' } .label = $ { 'Weight (SRV only)' } .value = $ { dnsEntry.data.weight | | '' } .type = $ { 'number' } > < / d e e s - i n p u t - t e x t >
< dees - input - text .key = $ { 'port' } .label = $ { 'Port (SRV only)' } .value = $ { dnsEntry.data.port | | '' } .type = $ { 'number' } > < / d e e s - i n p u t - t e x t >
< dees - input - checkbox .key = $ { 'active' } .label = $ { 'Active' } .value = $ { dnsEntry.data.active } > < / d e e s - i n p u t - c h e c k b o x >
< dees - input - text .key = $ { 'description' } .label = $ { 'Description (optional)' } .value = $ { dnsEntry.data.description | | '' } > < / d e e s - i n p u t - t e x t >
< / d e e s - f o r m >
` ,
menuOptions : [
{ name : 'Update DNS Entry' , action : async ( modalArg : any ) = > {
const form = modalArg . shadowRoot . querySelector ( 'dees-form' ) as any ;
const formData = await form . gatherData ( ) ;
2025-09-14 17:38:16 +00:00
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 ;
}
}
2025-09-14 17:28:21 +00:00
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 ( ) ;
} } ,
{ name : 'Cancel' , action : async ( modalArg : any ) = > modalArg . destroy ( ) } ,
] ,
} ) ;
} } ,
{ name : 'Duplicate' , iconName : 'copy' , type : [ 'contextmenu' , 'inRow' ] , actionFunc : async ( actionDataArg : any ) = > { const dnsEntry = actionDataArg . item as plugins . interfaces . data . IDnsEntry ; await appstate . dataState . dispatchAction ( appstate . createDnsEntryAction , { dnsEntryData : { . . . dnsEntry . data , description : ` Copy of ${ dnsEntry . data . description || dnsEntry . data . name } ` , } , } ) ; } } ,
{ name : 'Toggle Active' , iconName : 'power' , type : [ 'contextmenu' , 'inRow' ] , actionFunc : async ( actionDataArg : any ) = > { const dnsEntry = actionDataArg . item as plugins . interfaces . data . IDnsEntry ; await appstate . dataState . dispatchAction ( appstate . updateDnsEntryAction , { dnsEntryId : dnsEntry.id , dnsEntryData : { . . . dnsEntry . data , active : ! dnsEntry . data . active , } , } ) ; } } ,
{ name : 'Delete' , iconName : 'trash' , type : [ 'contextmenu' , 'inRow' ] , actionFunc : async ( actionDataArg : any ) = > { const dnsEntry = actionDataArg . item as plugins . interfaces . data . IDnsEntry ; plugins . deesCatalog . DeesModal . createAndShow ( { heading : ` Delete DNS Entry ` , content : html ` <div style="text-align:center">Are you sure you want to delete this DNS entry?</div><div style="margin-top: 16px; padding: 16px; background: #333; border-radius: 8px;"><div style="color: #fff; font-weight: bold;"> ${ dnsEntry . data . type } - ${ dnsEntry . data . name } . ${ dnsEntry . data . zone } </div><div style="color: #aaa; font-size: 0.9em; margin-top: 4px;"> ${ dnsEntry . data . value } </div> ${ dnsEntry . data . description ? html ` <div style= \ "color: #888; font-size: 0.85em; margin-top: 8px; \ "> ${ dnsEntry . data . description } </div> ` : '' } </div> ` , menuOptions : [ { name : 'Cancel' , action : async ( modalArg : any ) = > { await modalArg . destroy ( ) ; } } , { name : 'Delete' , action : async ( modalArg : any ) = > { await appstate . dataState . dispatchAction ( appstate . deleteDnsEntryAction , { dnsEntryId : dnsEntry.id , } ) ; await modalArg . destroy ( ) ; } } , ] , } ) ; } } ,
] as plugins . deesCatalog . ITableAction [ ] }
> < / d e e s - t a b l e >
` ;
}
}
declare global { interface HTMLElementTagNameMap { 'cloudly-view-dns' : CloudlyViewDns ; } }