diff options
| author | zephyr <[email protected]> | 2023-06-25 15:03:39 +0800 |
|---|---|---|
| committer | zephyr <[email protected]> | 2023-06-25 15:03:39 +0800 |
| commit | 152615c3f8a100ffec33e305272dec656d569149 (patch) | |
| tree | 732ee7b5150f5409626f2f39ce585924a8a04d32 /src | |
| parent | cc21971645a4a6d60fce48b4da936232bddac9b9 (diff) | |
fix: move client tag and table setting btns to lower right
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/ConnectionTable.module.scss | 7 | ||||
| -rw-r--r-- | src/components/ConnectionTable.tsx | 156 | ||||
| -rw-r--r-- | src/components/Connections.module.scss | 7 | ||||
| -rw-r--r-- | src/components/Connections.tsx | 164 |
4 files changed, 178 insertions, 156 deletions
diff --git a/src/components/ConnectionTable.module.scss b/src/components/ConnectionTable.module.scss index f516003..1f1a48c 100644 --- a/src/components/ConnectionTable.module.scss +++ b/src/components/ConnectionTable.module.scss @@ -83,10 +83,3 @@ .rotate180 { transform: rotate(180deg); } - -.columnManagerRow { - width: 200px; - display: flex; - margin: 5px 0; - justify-content: space-between; -} diff --git a/src/components/ConnectionTable.tsx b/src/components/ConnectionTable.tsx index cf8923e..4c20598 100644 --- a/src/components/ConnectionTable.tsx +++ b/src/components/ConnectionTable.tsx @@ -1,56 +1,13 @@ import cx from 'clsx'; import { formatDistance, Locale } from 'date-fns'; import { enUS, zhCN, zhTW } from 'date-fns/locale'; -import React, { useState } from 'react'; -import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; +import React, { useEffect } from 'react'; import { ChevronDown } from 'react-feather'; import { useTranslation } from 'react-i18next'; import { useSortBy, useTable } from 'react-table'; -import BaseModal from '~/components/shared/BaseModal'; - import prettyBytes from '../misc/pretty-bytes'; -import Button from './Button'; import s from './ConnectionTable.module.scss'; -import Switch from './SwitchThemed'; - -const sortDescFirst = true; - -const getItemStyle = (isDragging, draggableStyle) => { - return { - ...draggableStyle, - ...(isDragging && { - background: 'transparent', - transform: draggableStyle.transform, // modal基于transform会造成偏移 - }), - }; -}; - -const hiddenColumnsOrigin = JSON.stringify(['id']); -const columnsOrigin = JSON.stringify([ - { accessor: 'id', show: false }, - { Header: 'c_type', accessor: 'type' }, - { Header: 'c_process', accessor: 'process' }, - { Header: 'c_host', accessor: 'host' }, - { Header: 'c_rule', accessor: 'rule' }, - { Header: 'c_chains', accessor: 'chains' }, - { Header: 'c_time', accessor: 'start' }, - { Header: 'c_dl_speed', accessor: 'downloadSpeedCurr', sortDescFirst }, - { Header: 'c_ul_speed', accessor: 'uploadSpeedCurr', sortDescFirst }, - { Header: 'c_dl', accessor: 'download', sortDescFirst }, - { Header: 'c_ul', accessor: 'upload', sortDescFirst }, - { Header: 'c_source', accessor: 'source' }, - { Header: 'c_destination_ip', accessor: 'destinationIP' }, - { Header: 'c_sni', accessor: 'sniffHost' }, -]); - -const savedHiddenColumns = localStorage.getItem('hiddenColumns'); -const savedColumns = localStorage.getItem('columns'); - -const hiddenColumns = savedHiddenColumns - ? JSON.parse(savedHiddenColumns) - : JSON.parse(hiddenColumnsOrigin); -const columnsInit = savedColumns ? JSON.parse(savedColumns) : JSON.parse(columnsOrigin); function renderCell(cell: { column: { id: string }; value: number }, locale: Locale) { switch (cell.column.id) { @@ -68,17 +25,15 @@ function renderCell(cell: { column: { id: string }; value: number }, locale: Loc } const sortById = { id: 'id', desc: true }; -const tableState = { - sortBy: [ - // maintain a more stable order - sortById, - ], - hiddenColumns, -}; -function Table({ data }) { - const [showModalColumn, setModalColumn] = useState(false); - const [columns, setColumns] = useState(columnsInit); +function Table({ data, columns, hiddenColumns }) { + const tableState = { + sortBy: [ + // maintain a more stable order + sortById, + ], + hiddenColumns, + }; const table = useTable( { columns, @@ -90,6 +45,10 @@ function Table({ data }) { ); const { getTableProps, setHiddenColumns, headerGroups, rows, prepareRow } = table; + + useEffect(() => { + setHiddenColumns(hiddenColumns); + }, [setHiddenColumns, hiddenColumns]); const { t, i18n } = useTranslation(); let locale: Locale; @@ -102,97 +61,8 @@ function Table({ data }) { locale = enUS; } - const closeModalColumn = () => { - setModalColumn(false); - }; - - const onShowChange = (column, val) => { - if (!val) { - hiddenColumns.push(column.accessor); - } else { - const idx = hiddenColumns.indexOf(column.accessor); - - hiddenColumns.splice(idx, 1); - } - setHiddenColumns(Array.from(hiddenColumns)); - localStorage.setItem('hiddenColumns', JSON.stringify(hiddenColumns)); - }; - - const resetColumns = () => { - hiddenColumns.splice(0, hiddenColumns.length); - hiddenColumns.push('id'); - setHiddenColumns(hiddenColumns); - setColumns(JSON.parse(columnsOrigin)); - localStorage.removeItem('hiddenColumns'); - localStorage.removeItem('columns'); - }; - - const onDragEnd = (result) => { - if (!result.destination) { - return; - } - - const items = Array.from(columns); - const [removed] = items.splice(result.source.index, 1); - items.splice(result.destination.index, 0, removed); - setColumns(items); - localStorage.setItem('columns', JSON.stringify(items)); - }; - return ( <div style={{ marginTop: '5px' }}> - <BaseModal isOpen={showModalColumn} onRequestClose={closeModalColumn}> - <div> - <DragDropContext onDragEnd={onDragEnd}> - <Droppable droppableId="droppable-modal"> - {(provided) => ( - <div {...provided.droppableProps} ref={provided.innerRef}> - {columns - .filter((i) => i.accessor !== 'id') - .map((column) => { - const show = !hiddenColumns.includes(column.accessor); - - return ( - <Draggable - key={column.accessor} - draggableId={column.accessor} - index={columns.findIndex((a) => a.accessor === column.accessor)} - > - {(provided, snapshot) => ( - <div - ref={provided.innerRef} - {...provided.draggableProps} - {...provided.dragHandleProps} - className={s.columnManagerRow} - style={getItemStyle( - snapshot.isDragging, - provided.draggableProps.style - )} - > - <span>{t(column.Header)}</span> - <div style={{ transform: 'scale(0.7)', height: '20px' }}> - <Switch - size="mini" - checked={show} - onChange={(val) => onShowChange(column, val)} - /> - </div> - </div> - )} - </Draggable> - ); - })} - {provided.placeholder} - </div> - )} - </Droppable> - </DragDropContext> - </div> - </BaseModal> - <div className={s.btnSection}> - <Button onClick={() => setModalColumn(true)}>{t('manage_column')}</Button> - <Button onClick={resetColumns}>{t('reset_column')}</Button> - </div> <table {...getTableProps()} className={s.table}> <thead> {headerGroups.map((headerGroup, trindex) => { diff --git a/src/components/Connections.module.scss b/src/components/Connections.module.scss index ded8ce0..f3d507f 100644 --- a/src/components/Connections.module.scss +++ b/src/components/Connections.module.scss @@ -82,3 +82,10 @@ width: 120px; } } + +.columnManagerRow { + width: 200px; + display: flex; + margin: 5px 0; + justify-content: space-between; +} diff --git a/src/components/Connections.tsx b/src/components/Connections.tsx index 2cfa731..e5084e5 100644 --- a/src/components/Connections.tsx +++ b/src/components/Connections.tsx @@ -1,7 +1,8 @@ import './Connections.css'; import React from 'react'; -import { Pause, Play, X as IconClose } from 'react-feather'; +import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; +import { Pause, Play, RefreshCcw, Settings, Tag, X as IconClose } from 'react-feather'; import { useTranslation } from 'react-i18next'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; @@ -20,6 +21,7 @@ import ModalCloseAllConnections from './ModalCloseAllConnections'; import { Action, Fab, position as fabPosition } from './shared/Fab'; import { connect } from './StateProvider'; import SvgYacd from './SvgYacd'; +import Switch from './SwitchThemed'; const { useEffect, useState, useRef, useCallback } = React; @@ -27,6 +29,16 @@ const sourceMapInit = localStorage.getItem('sourceMap') ? JSON.parse(localStorage.getItem('sourceMap')) : []; +const getItemStyle = (isDragging, draggableStyle) => { + return { + ...draggableStyle, + ...(isDragging && { + background: 'transparent', + transform: draggableStyle.transform, // modal基于transform会造成偏移 + }), + }; +}; + const paddingBottom = 30; function arrayToIdKv<T extends { id: string }>(items: T[]) { @@ -191,9 +203,9 @@ function modifyChains(chains: string[]): string { return `${first} -> ${last}`; } -function renderTableOrPlaceholder(conns: FormattedConn[]) { +function renderTableOrPlaceholder(columns, hiddenColumns, conns: FormattedConn[]) { return conns.length > 0 ? ( - <ConnectionTable data={conns} /> + <ConnectionTable data={conns} columns={columns} hiddenColumns={hiddenColumns} /> ) : ( <div className={s.placeHolder}> <SvgYacd width={200} height={200} c1="var(--color-text)" /> @@ -205,7 +217,76 @@ function ConnQty({ qty }) { return qty < 100 ? '' + qty : '99+'; } +const sortDescFirst = true; + +const hiddenColumnsOrigin = JSON.stringify(['id']); +const columnsOrigin = JSON.stringify([ + { accessor: 'id', show: false }, + { Header: 'c_type', accessor: 'type' }, + { Header: 'c_process', accessor: 'process' }, + { Header: 'c_host', accessor: 'host' }, + { Header: 'c_rule', accessor: 'rule' }, + { Header: 'c_chains', accessor: 'chains' }, + { Header: 'c_time', accessor: 'start' }, + { Header: 'c_dl_speed', accessor: 'downloadSpeedCurr', sortDescFirst }, + { Header: 'c_ul_speed', accessor: 'uploadSpeedCurr', sortDescFirst }, + { Header: 'c_dl', accessor: 'download', sortDescFirst }, + { Header: 'c_ul', accessor: 'upload', sortDescFirst }, + { Header: 'c_source', accessor: 'source' }, + { Header: 'c_destination_ip', accessor: 'destinationIP' }, + { Header: 'c_sni', accessor: 'sniffHost' }, +]); + +const savedHiddenColumns = localStorage.getItem('hiddenColumns'); +const savedColumns = localStorage.getItem('columns'); + +const hiddenColumnsInit = savedHiddenColumns + ? JSON.parse(savedHiddenColumns) + : JSON.parse(hiddenColumnsOrigin); +const columnsInit = savedColumns ? JSON.parse(savedColumns) : JSON.parse(columnsOrigin); + function Conn({ apiConfig }) { + const [showModalColumn, setModalColumn] = useState(false); + const [hiddenColumns, setHiddenColumns] = useState(hiddenColumnsInit); + const [columns, setColumns] = useState(columnsInit); + + const closeModalColumn = () => { + setModalColumn(false); + }; + + const onShowChange = (column, val) => { + if (!val) { + hiddenColumns.push(column.accessor); + } else { + const idx = hiddenColumns.indexOf(column.accessor); + + hiddenColumns.splice(idx, 1); + } + setHiddenColumns(Array.from(hiddenColumns)); + localStorage.setItem('hiddenColumns', JSON.stringify(hiddenColumns)); + }; + + const resetColumns = () => { + hiddenColumns.splice(0, hiddenColumns.length); + hiddenColumns.push('id'); + setHiddenColumns(hiddenColumns); + setColumns(JSON.parse(columnsOrigin)); + localStorage.removeItem('hiddenColumns'); + localStorage.removeItem('columns'); + }; + + const onDragEnd = (result) => { + if (!result.destination) { + return; + } + + const items = Array.from(columns); + const [removed] = items.splice(result.source.index, 1); + items.splice(result.destination.index, 0, removed); + setColumns(items); + localStorage.setItem('columns', JSON.stringify(items)); + }; + const [sourceMapModal, setSourceMapModal] = useState(false); const [sourceMap, setSourceMap] = useState(sourceMapInit); const [refContainer, containerHeight] = useRemainingViewPortHeight(); @@ -293,6 +374,54 @@ function Conn({ apiConfig }) { return ( <div> + <BaseModal isOpen={showModalColumn} onRequestClose={closeModalColumn}> + <div> + <DragDropContext onDragEnd={onDragEnd}> + <Droppable droppableId="droppable-modal"> + {(provided) => ( + <div {...provided.droppableProps} ref={provided.innerRef}> + {columns + .filter((i) => i.accessor !== 'id') + .map((column) => { + const show = !hiddenColumns.includes(column.accessor); + + return ( + <Draggable + key={column.accessor} + draggableId={column.accessor} + index={columns.findIndex((a) => a.accessor === column.accessor)} + > + {(provided, snapshot) => ( + <div + ref={provided.innerRef} + {...provided.draggableProps} + {...provided.dragHandleProps} + className={s.columnManagerRow} + style={getItemStyle( + snapshot.isDragging, + provided.draggableProps.style + )} + > + <span>{t(column.Header)}</span> + <div style={{ transform: 'scale(0.7)', height: '20px' }}> + <Switch + size="mini" + checked={show} + onChange={(val) => onShowChange(column, val)} + /> + </div> + </div> + )} + </Draggable> + ); + })} + {provided.placeholder} + </div> + )} + </Droppable> + </DragDropContext> + </div> + </BaseModal> <BaseModal isOpen={sourceMapModal} onRequestClose={closeModalSource}> <table className={s.sourceipTable}> <thead> @@ -373,7 +502,6 @@ function Conn({ apiConfig }) { </TabList> <div className={s.sourceipContainer}> - <Button onClick={openModalSource}>{t('client_tag')}</Button> <Button onClick={() => setFilterSourceIpStr('')} kind="minimal"> {t('All')} </Button> @@ -397,7 +525,7 @@ function Conn({ apiConfig }) { }} > <TabPanel> - {renderTableOrPlaceholder(filteredConns)} + {renderTableOrPlaceholder(columns, hiddenColumns, filteredConns)} <Fab icon={isRefreshPaused ? <Play size={16} /> : <Pause size={16} />} mainButtonStyles={isRefreshPaused ? { background: '#e74c3c' } : {}} @@ -408,9 +536,33 @@ function Conn({ apiConfig }) { <Action text={t('close_all_connections')} onClick={openCloseAllModal}> <IconClose size={10} /> </Action> + <Action text={t('manage_column')} onClick={() => setModalColumn(true)}> + <Settings size={10} /> + </Action> + <Action text={t('reset_column')} onClick={resetColumns}> + <RefreshCcw size={10} /> + </Action> + <Action text={t('client_tag')} onClick={openModalSource}> + <Tag size={10} /> + </Action> + </Fab> + </TabPanel> + <TabPanel> + {renderTableOrPlaceholder(columns, hiddenColumns, filteredClosedConns)} + <Fab + icon={<Settings size={16} />} + style={fabPosition} + text={t('manage_column')} + onClick={() => setModalColumn(true)} + > + <Action text={t('reset_column')} onClick={resetColumns}> + <RefreshCcw size={10} /> + </Action> + <Action text={t('client_tag')} onClick={openModalSource}> + <Tag size={10} /> + </Action> </Fab> </TabPanel> - <TabPanel>{renderTableOrPlaceholder(filteredClosedConns)}</TabPanel> </div> </div> <ModalCloseAllConnections |
