Add traffic group sorting controls
This commit is contained in:
@@ -11,11 +11,13 @@ import { formatByteString } from '../../utils/format.js';
|
||||
import {
|
||||
groupTrafficConnections,
|
||||
reconcileTrafficGroups,
|
||||
sortTrafficGroups,
|
||||
trafficGroupMatches,
|
||||
type DisplayedTrafficGroup,
|
||||
type TrafficConnectionGroup,
|
||||
type TrafficQualityFilter,
|
||||
type TrafficRouteFilter,
|
||||
type TrafficSort,
|
||||
} from './trafficRows.js';
|
||||
|
||||
const POLL_MS = 1_000;
|
||||
@@ -310,6 +312,7 @@ export function TrafficPanel({ feature }: { feature: TrafficFeature }) {
|
||||
const [query, setQuery] = useState('');
|
||||
const [routeFilter, setRouteFilter] = useState<TrafficRouteFilter>('all');
|
||||
const [qualityFilter, setQualityFilter] = useState<TrafficQualityFilter>('all');
|
||||
const [sortMode, setSortMode] = useState<TrafficSort>('popular');
|
||||
const [retentionSeconds, setRetentionSeconds] = useState<RetentionSeconds>(storedRetentionSeconds);
|
||||
const [displayedGroups, setDisplayedGroups] = useState<DisplayedTrafficGroup[]>([]);
|
||||
const [reducedMotion, setReducedMotion] = useState(() => (
|
||||
@@ -324,9 +327,9 @@ export function TrafficPanel({ feature }: { feature: TrafficFeature }) {
|
||||
return snapshotTime - Date.parse(connection.closedAt) < retentionSeconds * 1_000;
|
||||
}), [snapshot, snapshotTime, retentionSeconds]);
|
||||
const trafficGroups = useMemo(() => groupTrafficConnections(retainedConnections), [retainedConnections]);
|
||||
const groups = useMemo(() => trafficGroups.filter((group) => (
|
||||
const groups = useMemo(() => sortTrafficGroups(trafficGroups.filter((group) => (
|
||||
trafficGroupMatches(group, query, routeFilter, qualityFilter)
|
||||
)), [trafficGroups, query, routeFilter, qualityFilter]);
|
||||
)), sortMode), [trafficGroups, query, routeFilter, qualityFilter, sortMode]);
|
||||
|
||||
useEffect(() => {
|
||||
const media = matchMedia('(prefers-reduced-motion: reduce)');
|
||||
@@ -438,6 +441,20 @@ export function TrafficPanel({ feature }: { feature: TrafficFeature }) {
|
||||
onClick={() => setQualityFilter(value)}
|
||||
>{label}</button>)}
|
||||
</div>
|
||||
<div className="client-traffic-retention">
|
||||
<span>Сортировка</span>
|
||||
<div className="client-traffic-filters" role="group" aria-label="Сортировка соединений">
|
||||
{([
|
||||
['popular', 'Популярные'],
|
||||
['recent', 'Последние'],
|
||||
] as const).map(([value, label]) => <button
|
||||
type="button"
|
||||
key={value}
|
||||
aria-pressed={sortMode === value}
|
||||
onClick={() => setSortMode(value)}
|
||||
>{label}</button>)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="client-traffic-retention">
|
||||
<span>Показывать завершённые</span>
|
||||
<div className="client-traffic-filters" role="group" aria-label="Время показа завершённых соединений">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { byteString } from '../../utils/format.js';
|
||||
|
||||
export type TrafficRouteFilter = 'all' | 'vpn' | 'direct' | 'other';
|
||||
export type TrafficQualityFilter = 'all' | 'recognized' | 'attention';
|
||||
export type TrafficSort = 'popular' | 'recent';
|
||||
|
||||
export interface TrafficConnectionGroup {
|
||||
id: string;
|
||||
@@ -90,6 +91,22 @@ export function groupTrafficConnections(connections: LiveTrafficConnection[]) {
|
||||
return [...grouped].map(([id, members]) => buildTrafficGroup(id, members));
|
||||
}
|
||||
|
||||
function newestStartedAt(group: TrafficConnectionGroup) {
|
||||
return group.connections.reduce((latest, connection) => (
|
||||
connection.startedAt > latest ? connection.startedAt : latest
|
||||
), '');
|
||||
}
|
||||
|
||||
export function sortTrafficGroups(groups: TrafficConnectionGroup[], mode: TrafficSort) {
|
||||
return [...groups].sort((left, right) => {
|
||||
const frequency = right.connections.length - left.connections.length;
|
||||
const recent = newestStartedAt(right).localeCompare(newestStartedAt(left));
|
||||
const primary = mode === 'popular' ? frequency || recent : recent || frequency;
|
||||
if (primary) return primary;
|
||||
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
||||
});
|
||||
}
|
||||
|
||||
export function trafficGroupMatches(
|
||||
group: TrafficConnectionGroup,
|
||||
query: string,
|
||||
|
||||
Reference in New Issue
Block a user