import './Connections.css';
import React from 'react';
import { Pause, Play, RefreshCcw, Settings, Tag, X as IconClose } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import Select from '~/components/shared/Select';
import {
useConnectionColumns,
useConnectionFilters,
useConnectionsStream,
useSourceMapState,
} from '~/modules/connections/hooks';
import { CONNECTIONS_PADDING_BOTTOM } from '~/modules/connections/utils';
import { FormattedConn } from '~/store/connections';
import { ClashAPIConfig } from '~/types';
import * as connAPI from '../api/connections';
import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight';
import s from './Connections.module.scss';
import ConnectionTable from './ConnectionTable';
import ContentHeader from './ContentHeader';
import Input from './Input';
import ModalCloseAllConnections from './ModalCloseAllConnections';
import ModalManageConnectionColumns from './ModalManageConnectionColumns';
import ModalSourceIP from './ModalSourceIP';
import { Fab, position as fabPosition } from './shared/Fab';
import SvgYacd from './SvgYacd';
const { useState, useCallback } = React;
function renderTableOrPlaceholder(
columns,
hiddenColumns,
conns: FormattedConn[],
height: number,
apiConfig: ClashAPIConfig
) {
return conns.length > 0 ? (
) : (
);
}
function ConnQty({ qty }) {
return qty < 100 ? '' + qty : '99+';
}
type Props = {
apiConfig: ClashAPIConfig;
};
export default function Connections({ apiConfig }: Props) {
const { t } = useTranslation();
const [showModalColumn, setModalColumn] = useState(false);
const { hiddenColumns, setHiddenColumns, columns, setColumns, resetColumns } =
useConnectionColumns();
const closeModalColumn = () => {
setModalColumn(false);
};
const { sourceMapModal, sourceMap, setSourceMap, openModalSource, closeModalSource } =
useSourceMapState();
const [refContainer, containerHeight] = useRemainingViewPortHeight();
const { conns, closedConns, isRefreshPaused, toggleIsRefreshPaused, closeAllConnections } =
useConnectionsStream(apiConfig, sourceMap);
const {
filterKeyword,
setFilterKeyword,
filterSourceIpStr,
setFilterSourceIpStr,
filteredConns,
filteredClosedConns,
connIpSet,
} = useConnectionFilters({ conns, closedConns, sourceMap, t });
const [isCloseFilterModalOpen, setIsCloseFilterModalOpen] = useState(false);
const openCloseFilterModal = useCallback(() => setIsCloseFilterModalOpen(true), []);
const closeCloseFilterModal = useCallback(() => setIsCloseFilterModalOpen(false), []);
const closeFilterConnections = useCallback(async () => {
for (const connection of filteredConns) {
await connAPI.closeConnById(apiConfig, connection.id);
}
closeCloseFilterModal();
}, [apiConfig, filteredConns, closeCloseFilterModal]);
const [isCloseAllModalOpen, setIsCloseAllModalOpen] = useState(false);
const openCloseAllModal = useCallback(() => setIsCloseAllModalOpen(true), []);
const closeCloseAllModal = useCallback(() => setIsCloseAllModalOpen(false), []);
const handleCloseAllConnections = useCallback(() => {
closeAllConnections();
closeCloseAllModal();
}, [closeAllConnections, closeCloseAllModal]);
return (
{t('Active')}
{t('Closed')}
setFilterKeyword(e.target.value)}
/>
{renderTableOrPlaceholder(
columns,
hiddenColumns,
filteredConns,
containerHeight - CONNECTIONS_PADDING_BOTTOM,
apiConfig
)}
: }
mainButtonStyles={isRefreshPaused ? { background: '#e74c3c' } : {}}
style={fabPosition}
text={isRefreshPaused ? t('Resume Refresh') : t('Pause Refresh')}
onClick={toggleIsRefreshPaused}
/>
{renderTableOrPlaceholder(
columns,
hiddenColumns,
filteredClosedConns,
containerHeight - CONNECTIONS_PADDING_BOTTOM,
apiConfig
)}
);
}