Add an initial organisation flow
This commit is contained in:
parent
3bd1a5007a
commit
ac733af3b5
12 changed files with 432 additions and 99 deletions
163
src/Bridges.tsx
Normal file
163
src/Bridges.tsx
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import { useRef, useState } from 'react';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import type { InputRef, TableColumnsType, TableColumnType } from 'antd';
|
||||
import { Button, Input, Space, Table } from 'antd';
|
||||
import type { FilterDropdownProps } from 'antd/es/table/interface';
|
||||
import Highlighter from 'react-highlight-words';
|
||||
import { QRCode, theme } from 'antd';
|
||||
const { useToken } = theme;
|
||||
interface BridgeDataType {
|
||||
fingerprint: string;
|
||||
bridgeline: string;
|
||||
qrCodeText: string;
|
||||
}
|
||||
|
||||
const Bridges = () => {
|
||||
|
||||
const bridgeLines: BridgeDataType[] = [
|
||||
{fingerprint: '0C6DDE3F9FC377A5E69DC044E81C857277148D71', bridgeline: "obfs4 62.224.107.157:443 0C6DDE3F9FC377A5E69DC044E81C857277148D71 cert=6vp+cyZmJOp+QFtytv9Ca+Z+ASF4l7r12MeEevvufl4OcDimBhjQlxctjfgdCmnT7iu7Lg iat-mode=0", qrCodeText: "" },
|
||||
{fingerprint:'8DFC222D2295A909B34B3AAAA584648EE6FAF14D', bridgeline: "obfs4 144.31.125.189:2063 8DFC222D2295A909B34B3AAAA584648EE6FAF14D cert=3BPE8q1dHF1AWoqsQEDGZHrRXPw/AaTwyM7YLGMOfFlxY6qRAlW1Jq0LlzKbe4Gh9+SacA iat-mode=0", qrCodeText: "" },
|
||||
{fingerprint: '0C6DDE3F9FC377A5E69DC044E81C857277148D71', bridgeline: "obfs4 62.224.107.157:443 0C6DDE3F9FC377A5E69DC044E81C857277148D71 cert=6vp+cyZmJOp+QFtytv9Ca+Z+ASF4l7r12MeEevvufl4OcDimBhjQlxctjfgdCmnT7iu7Lg iat-mode=0", qrCodeText: ""},
|
||||
{fingerprint:'8DFC222D2295A909B34B3AAAA584648EE6FAF14D', bridgeline: "obfs4 144.31.125.189:2063 8DFC222D2295A909B34B3AAAA584648EE6FAF14D cert=3BPE8q1dHF1AWoqsQEDGZHrRXPw/AaTwyM7YLGMOfFlxY6qRAlW1Jq0LlzKbe4Gh9+SacA iat-mode=0", qrCodeText: ""},
|
||||
];
|
||||
|
||||
|
||||
function makeQRCodeText(bridgeline: string) {
|
||||
return '["' + bridgeline + '"]';
|
||||
}
|
||||
|
||||
bridgeLines.forEach((line) => {line.qrCodeText = makeQRCodeText(line.bridgeline)});
|
||||
console.log(bridgeLines);
|
||||
const { token } = useToken();
|
||||
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [searchedColumn, setSearchedColumn] = useState('');
|
||||
const searchInput = useRef<InputRef>(null);
|
||||
|
||||
const handleSearch = (
|
||||
selectedKeys: string[],
|
||||
confirm: FilterDropdownProps['confirm'],
|
||||
dataIndex: DataIndex,
|
||||
) => {
|
||||
confirm();
|
||||
setSearchText(selectedKeys[0]);
|
||||
setSearchedColumn(dataIndex);
|
||||
};
|
||||
|
||||
const handleReset = (clearFilters: () => void) => {
|
||||
clearFilters();
|
||||
setSearchText('');
|
||||
};
|
||||
|
||||
type DataIndex = keyof BridgeDataType;
|
||||
const getColumnSearchProps = (dataIndex: DataIndex): TableColumnType<BridgeDataType> => ({
|
||||
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => (
|
||||
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
|
||||
<Input
|
||||
ref={searchInput}
|
||||
placeholder={`Search ${dataIndex}`}
|
||||
value={selectedKeys[0]}
|
||||
onChange={(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])}
|
||||
onPressEnter={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
|
||||
style={{ marginBottom: 8, display: 'block' }}
|
||||
/>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => handleSearch(selectedKeys as string[], confirm, dataIndex)}
|
||||
icon={<SearchOutlined />}
|
||||
size="small"
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => clearFilters && handleReset(clearFilters)}
|
||||
size="small"
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
confirm({ closeDropdown: false });
|
||||
setSearchText((selectedKeys as string[])[0]);
|
||||
setSearchedColumn(dataIndex);
|
||||
}}
|
||||
>
|
||||
Filter
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
close();
|
||||
}}
|
||||
>
|
||||
close
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
),
|
||||
filterIcon: (filtered: boolean) => (
|
||||
<SearchOutlined style={{ color: filtered ? '#1677ff' : undefined }} />
|
||||
),
|
||||
onFilter: (value, record) =>
|
||||
record[dataIndex]
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes((value as string).toLowerCase()),
|
||||
filterDropdownProps: {
|
||||
onOpenChange(open) {
|
||||
if (open) {
|
||||
setTimeout(() => searchInput.current?.select(), 100);
|
||||
}
|
||||
},
|
||||
},
|
||||
render: (text) =>
|
||||
searchedColumn === dataIndex ? (
|
||||
<Highlighter
|
||||
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
|
||||
searchWords={[searchText]}
|
||||
autoEscape
|
||||
textToHighlight={text ? text.toString() : ''}
|
||||
/>
|
||||
) : (
|
||||
text
|
||||
),
|
||||
});
|
||||
|
||||
const bridgesColumns: TableColumnsType<BridgeDataType> = [
|
||||
{title: 'Fingerprint',
|
||||
dataIndex: 'fingerprint',
|
||||
key: 'fingerprint',
|
||||
width: '30%',
|
||||
...getColumnSearchProps('fingerprint')},
|
||||
|
||||
{title: 'Bridgeline',
|
||||
dataIndex: 'bridgeline',
|
||||
key: 'bridgeline',
|
||||
width: '40%',
|
||||
...getColumnSearchProps('bridgeline')},
|
||||
|
||||
{title: 'QR Code',
|
||||
width: '40%',
|
||||
key: 'qrCodeText',
|
||||
dataIndex: 'qrCodeText',
|
||||
render: (text, record) => {return (<QRCode value={record.qrCodeText} />)}
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
|
||||
<Table<BridgeDataType> columns={bridgesColumns} dataSource={bridgeLines} />;
|
||||
</>);
|
||||
|
||||
}
|
||||
|
||||
export default Bridges;
|
||||
Loading…
Add table
Add a link
Reference in a new issue