165 lines
5.2 KiB
TypeScript
165 lines
5.2 KiB
TypeScript
|
|
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-dashboard')
|
||
|
|
export class ObViewDashboard extends DeesElement {
|
||
|
|
@state()
|
||
|
|
accessor systemState: appstate.ISystemState = { status: null };
|
||
|
|
|
||
|
|
@state()
|
||
|
|
accessor servicesState: appstate.IServicesState = {
|
||
|
|
services: [],
|
||
|
|
currentService: null,
|
||
|
|
currentServiceLogs: [],
|
||
|
|
currentServiceStats: null,
|
||
|
|
platformServices: [],
|
||
|
|
currentPlatformService: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
@state()
|
||
|
|
accessor networkState: appstate.INetworkState = {
|
||
|
|
targets: [],
|
||
|
|
stats: null,
|
||
|
|
trafficStats: null,
|
||
|
|
dnsRecords: [],
|
||
|
|
domains: [],
|
||
|
|
certificates: [],
|
||
|
|
};
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
super();
|
||
|
|
|
||
|
|
const systemSub = appstate.systemStatePart
|
||
|
|
.select((s) => s)
|
||
|
|
.subscribe((newState) => {
|
||
|
|
this.systemState = newState;
|
||
|
|
});
|
||
|
|
this.rxSubscriptions.push(systemSub);
|
||
|
|
|
||
|
|
const servicesSub = appstate.servicesStatePart
|
||
|
|
.select((s) => s)
|
||
|
|
.subscribe((newState) => {
|
||
|
|
this.servicesState = newState;
|
||
|
|
});
|
||
|
|
this.rxSubscriptions.push(servicesSub);
|
||
|
|
|
||
|
|
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.systemStatePart.dispatchAction(appstate.fetchSystemStatusAction, null),
|
||
|
|
appstate.servicesStatePart.dispatchAction(appstate.fetchServicesAction, null),
|
||
|
|
appstate.servicesStatePart.dispatchAction(appstate.fetchPlatformServicesAction, null),
|
||
|
|
appstate.networkStatePart.dispatchAction(appstate.fetchNetworkStatsAction, null),
|
||
|
|
appstate.networkStatePart.dispatchAction(appstate.fetchCertificatesAction, null),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public render(): TemplateResult {
|
||
|
|
const status = this.systemState.status;
|
||
|
|
const services = this.servicesState.services;
|
||
|
|
const platformServices = this.servicesState.platformServices;
|
||
|
|
const networkStats = this.networkState.stats;
|
||
|
|
const certificates = this.networkState.certificates;
|
||
|
|
|
||
|
|
const runningServices = services.filter((s) => s.status === 'running').length;
|
||
|
|
const stoppedServices = services.filter((s) => s.status === 'stopped').length;
|
||
|
|
|
||
|
|
const validCerts = certificates.filter((c) => c.isValid).length;
|
||
|
|
const expiringCerts = certificates.filter(
|
||
|
|
(c) => c.isValid && c.expiresAt && c.expiresAt - Date.now() < 30 * 24 * 60 * 60 * 1000,
|
||
|
|
).length;
|
||
|
|
const expiredCerts = certificates.filter((c) => !c.isValid).length;
|
||
|
|
|
||
|
|
return html`
|
||
|
|
<ob-sectionheading>Dashboard</ob-sectionheading>
|
||
|
|
<sz-dashboard-view
|
||
|
|
.data=${{
|
||
|
|
cluster: {
|
||
|
|
totalServices: services.length,
|
||
|
|
running: runningServices,
|
||
|
|
stopped: stoppedServices,
|
||
|
|
dockerStatus: status?.docker?.running ? 'running' : 'stopped',
|
||
|
|
},
|
||
|
|
resourceUsage: {
|
||
|
|
cpu: status?.docker?.cpuUsage || 0,
|
||
|
|
memoryUsed: status?.docker?.memoryUsage || 0,
|
||
|
|
memoryTotal: status?.docker?.memoryTotal || 0,
|
||
|
|
networkIn: 0,
|
||
|
|
networkOut: 0,
|
||
|
|
topConsumers: [],
|
||
|
|
},
|
||
|
|
platformServices: platformServices.map((ps) => ({
|
||
|
|
name: ps.displayName,
|
||
|
|
status: ps.status === 'running' ? 'running' : 'stopped',
|
||
|
|
running: ps.status === 'running',
|
||
|
|
})),
|
||
|
|
traffic: {
|
||
|
|
requests: 0,
|
||
|
|
errors: 0,
|
||
|
|
errorPercent: 0,
|
||
|
|
avgResponse: 0,
|
||
|
|
reqPerMin: 0,
|
||
|
|
status2xx: 0,
|
||
|
|
status3xx: 0,
|
||
|
|
status4xx: 0,
|
||
|
|
status5xx: 0,
|
||
|
|
},
|
||
|
|
proxy: {
|
||
|
|
httpPort: networkStats?.proxy?.httpPort || 80,
|
||
|
|
httpsPort: networkStats?.proxy?.httpsPort || 443,
|
||
|
|
httpActive: networkStats?.proxy?.running || false,
|
||
|
|
httpsActive: networkStats?.proxy?.running || false,
|
||
|
|
routeCount: networkStats?.proxy?.routes || 0,
|
||
|
|
},
|
||
|
|
certificates: {
|
||
|
|
valid: validCerts,
|
||
|
|
expiring: expiringCerts,
|
||
|
|
expired: expiredCerts,
|
||
|
|
},
|
||
|
|
dnsConfigured: true,
|
||
|
|
acmeConfigured: true,
|
||
|
|
quickActions: [
|
||
|
|
{ label: 'Deploy Service', icon: 'lucide:Plus', primary: true },
|
||
|
|
{ label: 'Add Domain', icon: 'lucide:Globe' },
|
||
|
|
{ label: 'View Logs', icon: 'lucide:FileText' },
|
||
|
|
],
|
||
|
|
}}
|
||
|
|
@action-click=${(e: CustomEvent) => this.handleQuickAction(e)}
|
||
|
|
></sz-dashboard-view>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
|
||
|
|
private handleQuickAction(e: CustomEvent) {
|
||
|
|
const action = e.detail?.action || e.detail?.label;
|
||
|
|
if (action === 'Deploy Service') {
|
||
|
|
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: 'services' });
|
||
|
|
} else if (action === 'Add Domain') {
|
||
|
|
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: 'network' });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|