feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
import * as plugins from '../plugins.js';
|
|
|
|
|
import * as appstate from '../appstate.js';
|
2026-03-04 01:11:19 +00:00
|
|
|
import * as interfaces from '../../dist_ts_interfaces/index.js';
|
2026-02-02 00:36:19 +00:00
|
|
|
import { appRouter } from '../router.js';
|
2025-06-01 19:46:10 +00:00
|
|
|
import {
|
|
|
|
|
DeesElement,
|
|
|
|
|
css,
|
|
|
|
|
cssManager,
|
|
|
|
|
customElement,
|
|
|
|
|
html,
|
|
|
|
|
state,
|
|
|
|
|
type TemplateResult
|
|
|
|
|
} from '@design.estate/dees-element';
|
2026-04-08 08:24:55 +00:00
|
|
|
import type { IView } from '@design.estate/dees-catalog';
|
2025-06-01 19:46:10 +00:00
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
// Top-level / flat views
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
import { OpsViewLogs } from './ops-view-logs.js';
|
2026-02-13 17:05:33 +00:00
|
|
|
import { OpsViewCertificates } from './ops-view-certificates.js';
|
2026-04-08 08:24:55 +00:00
|
|
|
|
|
|
|
|
// Overview group
|
|
|
|
|
import { OpsViewOverview } from './overview/ops-view-overview.js';
|
|
|
|
|
import { OpsViewConfig } from './overview/ops-view-config.js';
|
|
|
|
|
|
|
|
|
|
// Network group
|
|
|
|
|
import { OpsViewNetworkActivity } from './network/ops-view-network-activity.js';
|
|
|
|
|
import { OpsViewRoutes } from './network/ops-view-routes.js';
|
|
|
|
|
import { OpsViewSourceProfiles } from './network/ops-view-sourceprofiles.js';
|
|
|
|
|
import { OpsViewNetworkTargets } from './network/ops-view-networktargets.js';
|
|
|
|
|
import { OpsViewTargetProfiles } from './network/ops-view-targetprofiles.js';
|
|
|
|
|
import { OpsViewRemoteIngress } from './network/ops-view-remoteingress.js';
|
|
|
|
|
import { OpsViewVpn } from './network/ops-view-vpn.js';
|
|
|
|
|
|
|
|
|
|
// Email group
|
|
|
|
|
import { OpsViewEmails } from './email/ops-view-emails.js';
|
|
|
|
|
import { OpsViewEmailSecurity } from './email/ops-view-email-security.js';
|
|
|
|
|
|
|
|
|
|
// Access group
|
|
|
|
|
import { OpsViewApiTokens } from './access/ops-view-apitokens.js';
|
2026-04-08 09:01:08 +00:00
|
|
|
import { OpsViewUsers } from './access/ops-view-users.js';
|
2026-04-08 08:24:55 +00:00
|
|
|
|
|
|
|
|
// Security group
|
|
|
|
|
import { OpsViewSecurityOverview } from './security/ops-view-security-overview.js';
|
|
|
|
|
import { OpsViewSecurityBlocked } from './security/ops-view-security-blocked.js';
|
|
|
|
|
import { OpsViewSecurityAuthentication } from './security/ops-view-security-authentication.js';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extended IView with explicit URL slug. Without an explicit `slug`, the URL
|
|
|
|
|
* slug is derived from `name.toLowerCase().replace(/\s+/g, '')`.
|
|
|
|
|
*/
|
|
|
|
|
interface ITabbedView extends IView {
|
|
|
|
|
slug?: string;
|
|
|
|
|
subViews?: ITabbedView[];
|
|
|
|
|
}
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
|
2025-06-01 19:46:10 +00:00
|
|
|
@customElement('ops-dashboard')
|
|
|
|
|
export class OpsDashboard extends DeesElement {
|
2026-02-01 19:21:37 +00:00
|
|
|
@state() accessor loginState: appstate.ILoginState = {
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
identity: null,
|
|
|
|
|
isLoggedIn: false,
|
|
|
|
|
};
|
2026-02-01 19:21:37 +00:00
|
|
|
|
|
|
|
|
@state() accessor uiState: appstate.IUiState = {
|
2025-07-04 18:50:15 +00:00
|
|
|
activeView: 'overview',
|
2026-04-08 07:45:26 +00:00
|
|
|
activeSubview: null,
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
sidebarCollapsed: false,
|
|
|
|
|
autoRefresh: true,
|
2025-07-04 18:50:15 +00:00
|
|
|
refreshInterval: 1000,
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
theme: 'light',
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-02 20:31:08 +00:00
|
|
|
@state() accessor configState: appstate.IConfigState = {
|
|
|
|
|
config: null,
|
|
|
|
|
isLoading: false,
|
|
|
|
|
error: null,
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
// Store viewTabs as a property to maintain object references (used for === selectedView identity)
|
|
|
|
|
private viewTabs: ITabbedView[] = [
|
2025-07-04 18:58:10 +00:00
|
|
|
{
|
|
|
|
|
name: 'Overview',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:layoutDashboard',
|
2026-04-08 08:24:55 +00:00
|
|
|
subViews: [
|
|
|
|
|
{ slug: 'stats', name: 'Stats', iconName: 'lucide:activity', element: OpsViewOverview },
|
|
|
|
|
{ slug: 'configuration', name: 'Configuration', iconName: 'lucide:settings', element: OpsViewConfig },
|
|
|
|
|
],
|
2026-02-23 21:34:50 +00:00
|
|
|
},
|
2025-07-04 18:58:10 +00:00
|
|
|
{
|
|
|
|
|
name: 'Network',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:network',
|
2026-04-08 08:24:55 +00:00
|
|
|
subViews: [
|
|
|
|
|
{ slug: 'activity', name: 'Network Activity', iconName: 'lucide:activity', element: OpsViewNetworkActivity },
|
|
|
|
|
{ slug: 'routes', name: 'Routes', iconName: 'lucide:route', element: OpsViewRoutes },
|
|
|
|
|
{ slug: 'sourceprofiles', name: 'Source Profiles', iconName: 'lucide:shieldCheck', element: OpsViewSourceProfiles },
|
|
|
|
|
{ slug: 'networktargets', name: 'Network Targets', iconName: 'lucide:server', element: OpsViewNetworkTargets },
|
|
|
|
|
{ slug: 'targetprofiles', name: 'Target Profiles', iconName: 'lucide:target', element: OpsViewTargetProfiles },
|
|
|
|
|
{ slug: 'remoteingress', name: 'Remote Ingress', iconName: 'lucide:globe', element: OpsViewRemoteIngress },
|
|
|
|
|
{ slug: 'vpn', name: 'VPN', iconName: 'lucide:shield', element: OpsViewVpn },
|
|
|
|
|
],
|
2025-07-04 18:58:10 +00:00
|
|
|
},
|
|
|
|
|
{
|
2026-04-08 08:24:55 +00:00
|
|
|
name: 'Email',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:mail',
|
2026-04-08 08:24:55 +00:00
|
|
|
subViews: [
|
|
|
|
|
{ slug: 'log', name: 'Email Log', iconName: 'lucide:scrollText', element: OpsViewEmails },
|
|
|
|
|
{ slug: 'security', name: 'Email Security', iconName: 'lucide:shieldCheck', element: OpsViewEmailSecurity },
|
|
|
|
|
],
|
2025-07-04 18:58:10 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Logs',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:scrollText',
|
2025-07-04 18:58:10 +00:00
|
|
|
element: OpsViewLogs,
|
|
|
|
|
},
|
2026-02-23 12:40:26 +00:00
|
|
|
{
|
2026-04-08 08:24:55 +00:00
|
|
|
name: 'Access',
|
|
|
|
|
iconName: 'lucide:keyRound',
|
|
|
|
|
subViews: [
|
|
|
|
|
{ slug: 'apitokens', name: 'API Tokens', iconName: 'lucide:key', element: OpsViewApiTokens },
|
2026-04-08 09:01:08 +00:00
|
|
|
{ slug: 'users', name: 'Users', iconName: 'lucide:users', element: OpsViewUsers },
|
2026-04-08 08:24:55 +00:00
|
|
|
],
|
2026-02-23 12:40:26 +00:00
|
|
|
},
|
2025-07-04 18:58:10 +00:00
|
|
|
{
|
|
|
|
|
name: 'Security',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:shield',
|
2026-04-08 08:24:55 +00:00
|
|
|
subViews: [
|
|
|
|
|
{ slug: 'overview', name: 'Overview', iconName: 'lucide:eye', element: OpsViewSecurityOverview },
|
|
|
|
|
{ slug: 'blocked', name: 'Blocked IPs', iconName: 'lucide:shieldBan', element: OpsViewSecurityBlocked },
|
|
|
|
|
{ slug: 'authentication', name: 'Authentication', iconName: 'lucide:lock', element: OpsViewSecurityAuthentication },
|
|
|
|
|
],
|
2025-07-04 18:58:10 +00:00
|
|
|
},
|
2026-02-13 17:05:33 +00:00
|
|
|
{
|
|
|
|
|
name: 'Certificates',
|
2026-02-23 21:40:34 +00:00
|
|
|
iconName: 'lucide:badgeCheck',
|
2026-02-13 17:05:33 +00:00
|
|
|
element: OpsViewCertificates,
|
|
|
|
|
},
|
2025-07-04 18:58:10 +00:00
|
|
|
];
|
|
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
/** URL slug for a view (explicit `slug` field, or lowercased name with spaces stripped). */
|
|
|
|
|
private slugFor(view: ITabbedView): string {
|
|
|
|
|
return view.slug ?? view.name.toLowerCase().replace(/\s+/g, '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Find the parent group of a subview, or undefined for top-level views. */
|
|
|
|
|
private findParent(view: ITabbedView): ITabbedView | undefined {
|
|
|
|
|
return this.viewTabs.find((v) => v.subViews?.includes(view));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Look up a view (or subview) by its URL slug pair. */
|
|
|
|
|
private findViewBySlug(viewSlug: string, subSlug: string | null): ITabbedView | undefined {
|
|
|
|
|
const top = this.viewTabs.find((v) => this.slugFor(v) === viewSlug);
|
|
|
|
|
if (!top) return undefined;
|
|
|
|
|
if (subSlug && top.subViews) {
|
|
|
|
|
return top.subViews.find((sv) => this.slugFor(sv) === subSlug) ?? top;
|
|
|
|
|
}
|
|
|
|
|
return top;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 20:31:08 +00:00
|
|
|
private get globalMessages() {
|
|
|
|
|
const messages: Array<{ id: string; type: string; message: string; dismissible?: boolean }> = [];
|
|
|
|
|
const config = this.configState.config;
|
|
|
|
|
if (config && !config.cache.enabled) {
|
|
|
|
|
messages.push({
|
|
|
|
|
id: 'db-disabled',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
message: 'Database is disabled. Creating and editing routes, profiles, targets, and API tokens is not available.',
|
|
|
|
|
dismissible: false,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return messages;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 22:21:55 +00:00
|
|
|
/**
|
2026-04-08 08:24:55 +00:00
|
|
|
* Get the current view tab based on the UI state's activeView/activeSubview.
|
2026-02-02 22:21:55 +00:00
|
|
|
* Used to pass the correct selectedView to dees-simple-appdash on initial render.
|
|
|
|
|
*/
|
2026-04-08 08:24:55 +00:00
|
|
|
private get currentViewTab(): ITabbedView {
|
|
|
|
|
return (
|
|
|
|
|
this.findViewBySlug(this.uiState.activeView, this.uiState.activeSubview) ?? this.viewTabs[0]
|
|
|
|
|
);
|
2026-02-02 22:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
document.title = 'DCRouter OpsServer';
|
2026-04-08 08:24:55 +00:00
|
|
|
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
// Subscribe to login state
|
|
|
|
|
const loginSubscription = appstate.loginStatePart
|
|
|
|
|
.select((stateArg) => stateArg)
|
|
|
|
|
.subscribe((loginState) => {
|
|
|
|
|
this.loginState = loginState;
|
|
|
|
|
// Trigger data fetch when logged in
|
|
|
|
|
if (loginState.isLoggedIn) {
|
|
|
|
|
appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
|
|
|
|
|
appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.rxSubscriptions.push(loginSubscription);
|
2026-04-08 08:24:55 +00:00
|
|
|
|
2026-04-02 20:31:08 +00:00
|
|
|
// Subscribe to config state (for global warnings)
|
|
|
|
|
const configSubscription = appstate.configStatePart
|
|
|
|
|
.select((stateArg) => stateArg)
|
|
|
|
|
.subscribe((configState) => {
|
|
|
|
|
this.configState = configState;
|
|
|
|
|
});
|
|
|
|
|
this.rxSubscriptions.push(configSubscription);
|
|
|
|
|
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
// Subscribe to UI state
|
|
|
|
|
const uiSubscription = appstate.uiStatePart
|
|
|
|
|
.select((stateArg) => stateArg)
|
|
|
|
|
.subscribe((uiState) => {
|
|
|
|
|
this.uiState = uiState;
|
2026-02-02 00:36:19 +00:00
|
|
|
// Sync appdash view when state changes (e.g., from URL navigation)
|
2026-04-08 08:24:55 +00:00
|
|
|
this.syncAppdashView(uiState.activeView, uiState.activeSubview);
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
});
|
|
|
|
|
this.rxSubscriptions.push(uiSubscription);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 00:36:19 +00:00
|
|
|
/**
|
|
|
|
|
* Sync the dees-simple-appdash view selection with the current state.
|
2026-04-08 08:24:55 +00:00
|
|
|
* This is needed when the URL changes externally (back/forward, deep link).
|
2026-02-02 00:36:19 +00:00
|
|
|
*/
|
2026-04-08 08:24:55 +00:00
|
|
|
private syncAppdashView(viewSlug: string, subviewSlug: string | null): void {
|
2026-02-02 00:36:19 +00:00
|
|
|
const appDash = this.shadowRoot?.querySelector('dees-simple-appdash') as any;
|
|
|
|
|
if (!appDash) return;
|
|
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
const targetView = this.findViewBySlug(viewSlug, subviewSlug);
|
|
|
|
|
if (!targetView) return;
|
2026-02-02 00:36:19 +00:00
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
if (appDash.selectedView === targetView) return;
|
2026-02-02 00:36:19 +00:00
|
|
|
|
2026-04-08 08:24:55 +00:00
|
|
|
// Use loadView to update both selectedView and the mounted element.
|
|
|
|
|
// It will dispatch view-select; our handler skips when state already matches.
|
|
|
|
|
appDash.loadView(targetView);
|
2026-02-02 00:36:19 +00:00
|
|
|
}
|
|
|
|
|
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
public static styles = [
|
|
|
|
|
cssManager.defaultStyles,
|
|
|
|
|
css`
|
2026-02-02 00:36:19 +00:00
|
|
|
:host {
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100vh;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
.maincontainer {
|
|
|
|
|
position: relative;
|
2026-02-02 00:36:19 +00:00
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
];
|
|
|
|
|
|
2025-06-01 19:46:10 +00:00
|
|
|
public render(): TemplateResult {
|
|
|
|
|
return html`
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
<div class="maincontainer">
|
2026-02-02 22:21:55 +00:00
|
|
|
<dees-simple-login
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
name="DCRouter OpsServer"
|
|
|
|
|
>
|
2026-02-02 22:21:55 +00:00
|
|
|
<dees-simple-appdash
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
name="DCRouter OpsServer"
|
2025-07-04 18:58:10 +00:00
|
|
|
.viewTabs=${this.viewTabs}
|
2026-02-02 22:21:55 +00:00
|
|
|
.selectedView=${this.currentViewTab}
|
2026-04-02 20:31:08 +00:00
|
|
|
.globalMessages=${this.globalMessages}
|
feat: Add operations view components for logs, overview, security, and stats
- Implemented `ops-view-logs` for displaying and filtering logs with streaming capabilities.
- Created `ops-view-overview` to show server, email, DNS statistics, and charts.
- Developed `ops-view-security` for monitoring security metrics, blocked IPs, and authentication attempts.
- Added `ops-view-stats` to present comprehensive statistics on server, email, DNS, and security metrics.
- Introduced shared styles and components including `ops-sectionheading` for consistent UI.
2025-06-08 12:03:17 +00:00
|
|
|
>
|
|
|
|
|
</dees-simple-appdash>
|
|
|
|
|
</dees-simple-login>
|
|
|
|
|
</div>
|
2025-06-01 19:46:10 +00:00
|
|
|
`;
|
|
|
|
|
}
|
2025-06-08 12:51:48 +00:00
|
|
|
|
|
|
|
|
public async firstUpdated() {
|
2026-03-26 07:40:56 +00:00
|
|
|
const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
|
|
|
|
|
simpleLogin.addEventListener('login', (e: Event) => {
|
2026-04-08 08:24:55 +00:00
|
|
|
// Handle login event
|
2026-03-26 07:40:56 +00:00
|
|
|
const detail = (e as CustomEvent).detail;
|
|
|
|
|
this.login(detail.data.username, detail.data.password);
|
2025-06-08 12:51:48 +00:00
|
|
|
});
|
|
|
|
|
|
2025-07-02 11:33:50 +00:00
|
|
|
// Handle view changes
|
2026-03-26 07:40:56 +00:00
|
|
|
const appDash = this.shadowRoot!.querySelector('dees-simple-appdash');
|
2025-07-02 11:33:50 +00:00
|
|
|
if (appDash) {
|
2026-03-26 07:40:56 +00:00
|
|
|
appDash.addEventListener('view-select', (e: Event) => {
|
2026-04-08 08:24:55 +00:00
|
|
|
const view = (e as CustomEvent).detail.view as ITabbedView;
|
|
|
|
|
const parent = this.findParent(view);
|
|
|
|
|
const currentState = appstate.uiStatePart.getState();
|
|
|
|
|
if (parent) {
|
|
|
|
|
const parentSlug = this.slugFor(parent);
|
|
|
|
|
const subSlug = this.slugFor(view);
|
|
|
|
|
// Skip if already on this exact subview — preserves URL on initial mount
|
|
|
|
|
if (currentState?.activeView === parentSlug && currentState?.activeSubview === subSlug) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
appRouter.navigateToView(parentSlug, subSlug);
|
|
|
|
|
} else {
|
|
|
|
|
const slug = this.slugFor(view);
|
|
|
|
|
if (currentState?.activeView === slug && !currentState?.activeSubview) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
appRouter.navigateToView(slug);
|
|
|
|
|
}
|
2025-07-02 11:33:50 +00:00
|
|
|
});
|
2026-02-02 00:36:19 +00:00
|
|
|
|
2025-07-04 18:50:15 +00:00
|
|
|
// Handle logout event
|
|
|
|
|
appDash.addEventListener('logout', async () => {
|
|
|
|
|
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
|
|
|
|
|
});
|
2025-07-02 11:33:50 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-02 00:36:19 +00:00
|
|
|
// Handle initial state - check if we have a stored session that's still valid
|
2026-03-26 07:40:56 +00:00
|
|
|
const loginState = appstate.loginStatePart.getState()!;
|
2026-02-02 00:36:19 +00:00
|
|
|
if (loginState.identity?.jwt) {
|
|
|
|
|
if (loginState.identity.expiresAt > Date.now()) {
|
2026-03-04 01:11:19 +00:00
|
|
|
// Client-side expiry looks valid — verify with server (keypair may have changed)
|
|
|
|
|
try {
|
|
|
|
|
const verifyRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
|
|
|
|
interfaces.requests.IReq_VerifyIdentity
|
|
|
|
|
>('/typedrequest', 'verifyIdentity');
|
|
|
|
|
const response = await verifyRequest.fire({ identity: loginState.identity });
|
|
|
|
|
if (response.valid) {
|
|
|
|
|
// JWT confirmed valid by server
|
|
|
|
|
this.loginState = loginState;
|
2026-03-26 07:40:56 +00:00
|
|
|
await (simpleLogin as any).switchToSlottedContent();
|
2026-03-04 01:11:19 +00:00
|
|
|
await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
|
|
|
|
|
await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
|
|
|
|
|
} else {
|
|
|
|
|
// Server rejected the JWT — clear state, show login
|
|
|
|
|
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Server unreachable or error — clear state, show login
|
|
|
|
|
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
|
|
|
|
|
}
|
2026-02-02 00:36:19 +00:00
|
|
|
} else {
|
|
|
|
|
// JWT expired, clear the stored state
|
|
|
|
|
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
|
|
|
|
|
}
|
2025-06-08 12:51:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async login(username: string, password: string) {
|
|
|
|
|
const domtools = await this.domtoolsPromise;
|
|
|
|
|
console.log(`Attempting to login...`);
|
2026-03-26 07:40:56 +00:00
|
|
|
const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
|
|
|
|
|
const form = simpleLogin.shadowRoot!.querySelector('dees-form') as any;
|
2025-06-08 12:51:48 +00:00
|
|
|
form.setStatus('pending', 'Logging in...');
|
2026-04-08 08:24:55 +00:00
|
|
|
|
2025-06-08 12:51:48 +00:00
|
|
|
const state = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
|
|
|
|
|
username,
|
|
|
|
|
password,
|
|
|
|
|
});
|
2026-04-08 08:24:55 +00:00
|
|
|
|
2025-06-08 12:51:48 +00:00
|
|
|
if (state.identity) {
|
|
|
|
|
console.log('Login successful');
|
|
|
|
|
this.loginState = state;
|
2026-03-26 07:40:56 +00:00
|
|
|
form!.setStatus('success', 'Logged in!');
|
|
|
|
|
await simpleLogin!.switchToSlottedContent();
|
2025-06-08 12:51:48 +00:00
|
|
|
await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
|
|
|
|
|
await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
|
|
|
|
|
} else {
|
2026-03-26 07:40:56 +00:00
|
|
|
form!.setStatus('error', 'Login failed!');
|
2025-06-08 12:51:48 +00:00
|
|
|
await domtools.convenience.smartdelay.delayFor(2000);
|
2026-03-26 07:40:56 +00:00
|
|
|
form!.reset();
|
2025-06-08 12:51:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-08 08:24:55 +00:00
|
|
|
}
|