import { DeesElement, html, customElement, type TemplateResult, css, state, cssManager, } from '@design.estate/dees-element'; import * as appstate from '../appstate.js'; import * as interfaces from '../../dist_ts_interfaces/index.js'; import { viewHostCss } from './shared/css.js'; import { type IStatsTile } from '@design.estate/dees-catalog'; declare global { interface HTMLElementTagNameMap { 'ops-view-networktargets': OpsViewNetworkTargets; } } @customElement('ops-view-networktargets') export class OpsViewNetworkTargets extends DeesElement { @state() accessor profilesState: appstate.IProfilesTargetsState = appstate.profilesTargetsStatePart.getState()!; constructor() { super(); const sub = appstate.profilesTargetsStatePart.select().subscribe((newState) => { this.profilesState = newState; }); this.rxSubscriptions.push(sub); } async connectedCallback() { await super.connectedCallback(); await appstate.profilesTargetsStatePart.dispatchAction(appstate.fetchProfilesAndTargetsAction, null); } public static styles = [ cssManager.defaultStyles, viewHostCss, css` .targetsContainer { display: flex; flex-direction: column; gap: 24px; } `, ]; public render(): TemplateResult { const targets = this.profilesState.targets; const statsTiles: IStatsTile[] = [ { id: 'totalTargets', title: 'Total Targets', type: 'number', value: targets.length, icon: 'lucide:server', description: 'Reusable network targets', color: '#8b5cf6', }, ]; return html` Network Targets
({ Name: target.name, Host: Array.isArray(target.host) ? target.host.join(', ') : target.host, Port: target.port, Description: target.description || '-', })} .dataActions=${[ { name: 'Create Target', iconName: 'lucide:plus', type: ['header' as const], actionFunc: async () => { await this.showCreateTargetDialog(); }, }, { name: 'Refresh', iconName: 'lucide:rotateCw', type: ['header' as const], actionFunc: async () => { await appstate.profilesTargetsStatePart.dispatchAction(appstate.fetchProfilesAndTargetsAction, null); }, }, { name: 'Edit', iconName: 'lucide:pencil', type: ['inRow', 'contextmenu'] as any, actionFunc: async (actionData: any) => { const target = actionData.item as interfaces.data.INetworkTarget; await this.showEditTargetDialog(target); }, }, { name: 'Delete', iconName: 'lucide:trash2', type: ['inRow', 'contextmenu'] as any, actionFunc: async (actionData: any) => { const target = actionData.item as interfaces.data.INetworkTarget; await this.deleteTarget(target); }, }, ]} >
`; } private async showCreateTargetDialog() { const { DeesModal } = await import('@design.estate/dees-catalog'); DeesModal.createAndShow({ heading: 'Create Network Target', content: html` `, menuOptions: [ { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() }, { name: 'Create', action: async (modalArg: any) => { const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form'); if (!form) return; const data = await form.collectFormData(); await appstate.profilesTargetsStatePart.dispatchAction(appstate.createTargetAction, { name: String(data.name), description: data.description ? String(data.description) : undefined, host: String(data.host), port: parseInt(String(data.port)) || 443, }); modalArg.destroy(); }, }, ], }); } private async showEditTargetDialog(target: interfaces.data.INetworkTarget) { const hostStr = Array.isArray(target.host) ? target.host.join(', ') : target.host; const { DeesModal } = await import('@design.estate/dees-catalog'); DeesModal.createAndShow({ heading: `Edit Target: ${target.name}`, content: html` `, menuOptions: [ { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() }, { name: 'Save', action: async (modalArg: any) => { const form = modalArg.shadowRoot?.querySelector('.content')?.querySelector('dees-form'); if (!form) return; const data = await form.collectFormData(); await appstate.profilesTargetsStatePart.dispatchAction(appstate.updateTargetAction, { id: target.id, name: String(data.name), description: data.description ? String(data.description) : undefined, host: String(data.host), port: parseInt(String(data.port)) || 443, }); modalArg.destroy(); }, }, ], }); } private async deleteTarget(target: interfaces.data.INetworkTarget) { await appstate.profilesTargetsStatePart.dispatchAction(appstate.deleteTargetAction, { id: target.id, force: false, }); const currentState = appstate.profilesTargetsStatePart.getState()!; if (currentState.error?.includes('in use')) { const { DeesModal } = await import('@design.estate/dees-catalog'); DeesModal.createAndShow({ heading: 'Target In Use', content: html`

${currentState.error} Force delete?

`, menuOptions: [ { name: 'Force Delete', action: async (modalArg: any) => { await appstate.profilesTargetsStatePart.dispatchAction(appstate.deleteTargetAction, { id: target.id, force: true, }); modalArg.destroy(); }, }, { name: 'Cancel', action: async (modalArg: any) => modalArg.destroy() }, ], }); } } }