119 lines
2.9 KiB
TypeScript
119 lines
2.9 KiB
TypeScript
import * as appstate from '../../appstate.js';
|
|
import { viewHostCss } from '../shared/css.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,
|
|
viewHostCss,
|
|
css`
|
|
dees-statsgrid {
|
|
margin-bottom: 32px;
|
|
}
|
|
`,
|
|
];
|
|
|
|
public render(): TemplateResult {
|
|
const metrics = this.statsState.securityMetrics;
|
|
|
|
if (!metrics) {
|
|
return html`
|
|
<div class="loadingMessage">
|
|
<p>Loading security metrics...</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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`
|
|
<dees-heading level="hr">Blocked IPs</dees-heading>
|
|
|
|
<dees-statsgrid
|
|
.tiles=${tiles}
|
|
.minTileWidth=${200}
|
|
></dees-statsgrid>
|
|
|
|
<dees-table
|
|
.heading1=${'Blocked IP Addresses'}
|
|
.heading2=${'IPs blocked due to suspicious activity'}
|
|
.data=${blockedIPs.map((ip) => ({ 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();
|
|
},
|
|
},
|
|
]}
|
|
></dees-table>
|
|
`;
|
|
}
|
|
|
|
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.`);
|
|
}
|
|
}
|