import * as appstate from '../../appstate.js'; import { DeesElement, customElement, html, state, css, cssManager, type TemplateResult, } from '@design.estate/dees-element'; import { type IStatsTile } from '@design.estate/dees-catalog'; declare global { interface HTMLElementTagNameMap { 'ops-view-security-blocked': OpsViewSecurityBlocked; } } @customElement('ops-view-security-blocked') export class OpsViewSecurityBlocked extends DeesElement { @state() accessor statsState: appstate.IStatsState = appstate.statsStatePart.getState()!; constructor() { super(); const sub = appstate.statsStatePart .select((s) => s) .subscribe((s) => { this.statsState = s; }); this.rxSubscriptions.push(sub); } public static styles = [ cssManager.defaultStyles, css` :host { display: block; } dees-statsgrid { margin-bottom: 32px; } `, ]; public render(): TemplateResult { const metrics = this.statsState.securityMetrics; if (!metrics) { return html`

Loading security metrics...

`; } const blockedIPs: string[] = metrics.blockedIPs || []; const tiles: IStatsTile[] = [ { id: 'totalBlocked', title: 'Blocked IPs', value: blockedIPs.length, type: 'number', icon: 'lucide:ShieldBan', color: blockedIPs.length > 0 ? '#ef4444' : '#22c55e', description: 'Currently blocked addresses', }, ]; return html` Blocked IPs ({ ip }))} .displayFunction=${(item) => ({ 'IP Address': item.ip, 'Reason': 'Suspicious activity', })} .dataActions=${[ { name: 'Unblock', iconName: 'lucide:shield-off', type: ['contextmenu' as const], actionFunc: async (item) => { await this.unblockIP(item.ip); }, }, { name: 'Clear All', iconName: 'lucide:trash-2', type: ['header' as const], actionFunc: async () => { await this.clearBlockedIPs(); }, }, ]} > `; } private async clearBlockedIPs() { // SmartProxy manages IP blocking — not yet exposed via API alert('Clearing blocked IPs is not yet supported from the UI.'); } private async unblockIP(ip: string) { // SmartProxy manages IP blocking — not yet exposed via API alert(`Unblocking IP ${ip} is not yet supported from the UI.`); } }