显示客户端链接的ip:port

This commit is contained in:
YHH
2025-10-16 17:33:43 +08:00
parent 43bdd7e43b
commit 3cda3c2238
8 changed files with 156 additions and 19 deletions

View File

@@ -1,7 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { LogService, LogEntry } from '@esengine/editor-core';
import { LogLevel } from '@esengine/ecs-framework';
import { Trash2, AlertCircle, Info, AlertTriangle, XCircle, Bug, Search, Maximize2, ChevronRight, ChevronDown } from 'lucide-react';
import { Trash2, AlertCircle, Info, AlertTriangle, XCircle, Bug, Search, Maximize2, ChevronRight, ChevronDown, Wifi } from 'lucide-react';
import { JsonViewer } from './JsonViewer';
import '../styles/ConsolePanel.css';
@@ -19,6 +19,7 @@ export function ConsolePanel({ logService }: ConsolePanelProps) {
LogLevel.Error,
LogLevel.Fatal
]));
const [showRemoteOnly, setShowRemoteOnly] = useState(false);
const [autoScroll, setAutoScroll] = useState(true);
const [expandedLogs, setExpandedLogs] = useState<Set<number>>(new Set());
const [jsonViewerData, setJsonViewerData] = useState<any>(null);
@@ -65,6 +66,7 @@ export function ConsolePanel({ logService }: ConsolePanelProps) {
const filteredLogs = logs.filter(log => {
if (!levelFilter.has(log.level)) return false;
if (showRemoteOnly && log.source !== 'remote') return false;
if (filter && !log.message.toLowerCase().includes(filter.toLowerCase())) {
return false;
}
@@ -224,6 +226,8 @@ export function ConsolePanel({ logService }: ConsolePanelProps) {
[LogLevel.Error]: logs.filter(l => l.level === LogLevel.Error || l.level === LogLevel.Fatal).length
};
const remoteLogCount = logs.filter(l => l.source === 'remote').length;
return (
<div className="console-panel">
<div className="console-toolbar">
@@ -246,6 +250,14 @@ export function ConsolePanel({ logService }: ConsolePanelProps) {
</div>
</div>
<div className="console-toolbar-right">
<button
className={`console-filter-btn ${showRemoteOnly ? 'active' : ''}`}
onClick={() => setShowRemoteOnly(!showRemoteOnly)}
title="Show Remote Logs Only"
>
<Wifi size={14} />
{remoteLogCount > 0 && <span>{remoteLogCount}</span>}
</button>
<button
className={`console-filter-btn ${levelFilter.has(LogLevel.Debug) ? 'active' : ''}`}
onClick={() => toggleLevelFilter(LogLevel.Debug)}
@@ -317,6 +329,11 @@ export function ConsolePanel({ logService }: ConsolePanelProps) {
<div className={`log-entry-source ${log.source === 'remote' ? 'source-remote' : ''}`}>
[{log.source === 'remote' ? '🌐 Remote' : log.source}]
</div>
{log.clientId && (
<div className="log-entry-client" title={`Client: ${log.clientId}`}>
{log.clientId}
</div>
)}
<div className="log-entry-message">
{formatMessage(log.message, isExpanded)}
</div>

View File

@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { Entity } from '@esengine/ecs-framework';
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
import { useLocale } from '../hooks/useLocale';
import { Box, Layers, Wifi } from 'lucide-react';
import { Box, Layers, Wifi, Search } from 'lucide-react';
import { ProfilerService, RemoteEntity } from '../services/ProfilerService';
import '../styles/SceneHierarchy.css';
@@ -16,6 +16,7 @@ export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps)
const [remoteEntities, setRemoteEntities] = useState<RemoteEntity[]>([]);
const [isRemoteConnected, setIsRemoteConnected] = useState(false);
const [selectedId, setSelectedId] = useState<number | null>(null);
const [searchQuery, setSearchQuery] = useState('');
const { t } = useLocale();
// Subscribe to local entity changes
@@ -106,8 +107,33 @@ export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps)
});
};
// Filter entities based on search query
const filterEntities = <T extends Entity | RemoteEntity>(entityList: T[]): T[] => {
if (!searchQuery.trim()) return entityList;
const query = searchQuery.toLowerCase();
return entityList.filter(entity => {
const name = 'name' in entity ? entity.name : `Entity ${entity.id}`;
const id = entity.id.toString();
// Search by name or ID
if (name.toLowerCase().includes(query) || id.includes(query)) {
return true;
}
// Search by component types (for remote entities)
if ('componentTypes' in entity && Array.isArray(entity.componentTypes)) {
return entity.componentTypes.some(type =>
type.toLowerCase().includes(query)
);
}
return false;
});
};
// Determine which entities to display
const displayEntities = isRemoteConnected ? remoteEntities : entities;
const displayEntities = filterEntities(isRemoteConnected ? remoteEntities : entities);
const showRemoteIndicator = isRemoteConnected && remoteEntities.length > 0;
return (
@@ -121,6 +147,15 @@ export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps)
</div>
)}
</div>
<div className="hierarchy-search">
<Search size={14} />
<input
type="text"
placeholder={t('hierarchy.search') || 'Search entities...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<div className="hierarchy-content scrollable">
{displayEntities.length === 0 ? (
<div className="empty-state">
@@ -134,7 +169,7 @@ export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps)
</div>
) : isRemoteConnected ? (
<ul className="entity-list">
{remoteEntities.map(entity => (
{displayEntities.map(entity => (
<li
key={entity.id}
className={`entity-item remote-entity ${selectedId === entity.id ? 'selected' : ''} ${!entity.enabled ? 'disabled' : ''}`}
@@ -143,6 +178,11 @@ export function SceneHierarchy({ entityStore, messageHub }: SceneHierarchyProps)
>
<Box size={14} className="entity-icon" />
<span className="entity-name">{entity.name}</span>
{entity.tag !== 0 && (
<span className="entity-tag" title={`Tag: ${entity.tag}`}>
#{entity.tag}
</span>
)}
{entity.componentCount > 0 && (
<span className="component-count">{entity.componentCount}</span>
)}