import * as plugins from '../plugins.js'; import * as shared from './shared/index.js'; import * as appstate from '../appstate.js'; import { DeesElement, customElement, html, state, css, cssManager, type TemplateResult, } from '@design.estate/dees-element'; @customElement('ob-view-network') export class ObViewNetwork extends DeesElement { @state() accessor networkState: appstate.INetworkState = { targets: [], stats: null, trafficStats: null, dnsRecords: [], domains: [], certificates: [], }; @state() accessor currentTab: 'proxy' | 'dns' | 'domains' | 'domain-detail' = 'proxy'; @state() accessor selectedDomain: string = ''; constructor() { super(); const networkSub = appstate.networkStatePart .select((s) => s) .subscribe((newState) => { this.networkState = newState; }); this.rxSubscriptions.push(networkSub); } public static styles = [ cssManager.defaultStyles, shared.viewHostCss, css``, ]; async connectedCallback() { super.connectedCallback(); await Promise.all([ appstate.networkStatePart.dispatchAction(appstate.fetchNetworkTargetsAction, null), appstate.networkStatePart.dispatchAction(appstate.fetchNetworkStatsAction, null), appstate.networkStatePart.dispatchAction(appstate.fetchTrafficStatsAction, null), appstate.networkStatePart.dispatchAction(appstate.fetchDnsRecordsAction, null), appstate.networkStatePart.dispatchAction(appstate.fetchDomainsAction, null), appstate.networkStatePart.dispatchAction(appstate.fetchCertificatesAction, null), ]); } public render(): TemplateResult { switch (this.currentTab) { case 'dns': return this.renderDnsView(); case 'domains': return this.renderDomainsView(); case 'domain-detail': return this.renderDomainDetailView(); default: return this.renderProxyView(); } } private renderProxyView(): TemplateResult { const stats = this.networkState.stats; return html` Network ({ type: t.type, name: t.name, domain: t.domain, target: `${t.targetHost}:${t.targetPort}`, status: t.status, }))} .logs=${[]} @refresh=${() => { appstate.networkStatePart.dispatchAction(appstate.fetchNetworkTargetsAction, null); appstate.networkStatePart.dispatchAction(appstate.fetchNetworkStatsAction, null); }} > `; } private renderDnsView(): TemplateResult { return html` DNS Records { appstate.networkStatePart.dispatchAction(appstate.syncDnsAction, null); }} @delete=${(e: CustomEvent) => { console.log('Delete DNS record:', e.detail); }} > `; } private renderDomainsView(): TemplateResult { const certs = this.networkState.certificates; return html` Domains { const cert = certs.find((c) => c.certDomain === d.domain); let certStatus: 'valid' | 'expiring' | 'expired' | 'pending' = 'pending'; if (cert) { if (!cert.isValid) certStatus = 'expired'; else if (cert.expiresAt && cert.expiresAt - Date.now() < 30 * 24 * 60 * 60 * 1000) certStatus = 'expiring'; else certStatus = 'valid'; } return { domain: d.domain, provider: 'cloudflare', serviceCount: d.services?.length || 0, certificateStatus: certStatus, }; })} @sync=${() => { appstate.networkStatePart.dispatchAction(appstate.fetchDomainsAction, null); }} @view=${(e: CustomEvent) => { this.selectedDomain = e.detail.domain || e.detail; this.currentTab = 'domain-detail'; }} > `; } private renderDomainDetailView(): TemplateResult { const domainDetail = this.networkState.domains.find( (d) => d.domain === this.selectedDomain, ); const cert = this.networkState.certificates.find( (c) => c.certDomain === this.selectedDomain, ); return html` Domain Details r.domain?.includes(this.selectedDomain)) .map((r) => ({ id: r.id || '', type: r.type, name: r.domain, value: r.value, ttl: 3600, }))} @renew-certificate=${() => { appstate.networkStatePart.dispatchAction(appstate.renewCertificateAction, { domain: this.selectedDomain, }); }} > `; } }