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,
});
}}
>
`;
}
}