antd#Table TypeScript Examples
The following examples show how to use
antd#Table.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: TableContainer.tsx From generator-earth with MIT License | 6 votes |
render() {
// expandedRowRender={this.getExpandedRowRender}
const Items: React.ReactNode | null = this.getSearchItems();
return (
<React.Fragment>
{Items && (
<div className="ui-background">
<Form {...this.formProps()} onSubmit={this.submitForm}>
{Items}
</Form>
</div>
)}
<div className="ui-background clearfix">
{this.getTableExtraContent()}
<Table
bordered
title={this.getTitle()}
rowKey={this.getRowKey}
dataSource={this.getDataSource()}
columns={this.getColumns()}
onChange={this.handleTableChange}
pagination={this.getPagination()}
scroll={this.getScroll()}
rowSelection={this.rowSelection()}
/>
</div>
</React.Fragment>
)
}
Example #2
Source File: DebugCHQueries.tsx From posthog-foss with MIT License | 6 votes |
export async function debugCHQueries(): Promise<void> {
const results = await api.get('api/debug_ch_queries/')
Modal.info({
visible: true,
width: '80%',
title: 'ClickHouse queries recently executed for this user',
icon: null,
content: (
<>
<Table
columns={[
{ title: 'Timestamp', render: (item) => dayjs(item.timestamp).fromNow() },
{
title: 'Query',
render: function query(item) {
return (
<pre className="code" style={{ maxWidth: 600, fontSize: 12 }}>
{item.query}
</pre>
)
},
},
{
title: 'Execution duration (seconds)',
render: function exec(item) {
return <>{Math.round((item.execution_time + Number.EPSILON) * 100) / 100}</>
},
},
]}
dataSource={results}
size="small"
pagination={false}
/>
</>
),
})
}
Example #3
Source File: default.tsx From useTable with MIT License | 6 votes |
Component = () => {
const { formProps, tableProps, paginationProps } = useAntdFormTable(list);
return (
<Fragment>
<SchemaForm {...formProps} components={{ Input }} style={{ marginBottom: 20 }} inline>
<Field name="name" title="name" x-component={'Input'} />
<FormButtonGroup>
<Submit>查询</Submit>
<Reset>重置</Reset>
</FormButtonGroup>
</SchemaForm>
<Table scroll={{ y: 300 }} {...tableProps}>
<Table.Column title="email" dataIndex="email" />
<Table.Column title="phone" dataIndex="phone" />
<Table.Column title="gender" dataIndex="gender" />
</Table>
<Pagination style={{ marginTop: 16 }} {...paginationProps} />
</Fragment>
);
}
Example #4
Source File: custom-manual-palette.tsx From S2 with MIT License | 6 votes |
function ColorTable({ palette, onChange }) {
const columns = [
{
title: '#',
render(r, v, idx) {
return idx + 1;
},
},
{
title: '色值',
dataIndex: 'color',
},
{
title: '点击调整',
dataIndex: 'color',
render(val, _, idx) {
return (
<Popover
trigger="click"
content={
<SketchPicker
disableAlpha
presetColors={[]}
color={val}
onChangeComplete={(evt) => {
const nextBasicColors = [...palette.basicColors];
nextBasicColors.splice(idx, 1, evt.hex);
onChange({
...palette,
basicColors: nextBasicColors,
});
}}
/>
}
>
<Row justify="center">
<div
style={{
width: 30,
height: 30,
boxShadow: `0 0 8px rgba(0, 0, 0, 0.2)`,
cursor: 'pointer',
backgroundColor: val,
}}
/>
</Row>
</Popover>
);
},
},
{
title: '说明',
dataIndex: 'desc',
},
];
const dataSource = palette.basicColors.map((color, idx) => ({
color,
desc: paletteDesc[idx],
}));
return (
<Table
size="small"
rowKey="desc"
bordered
columns={columns}
pagination={false}
dataSource={dataSource}
/>
);
}
Example #5
Source File: index.tsx From umi-micro-apps with MIT License | 6 votes |
UserList = (props: any) => {
const { shopId } = props;
const { data = [] } = useRequest(() => request(`/api/user/list?shopId=${shopId}`));
const columns = [
{
dataIndex: 'id',
title: 'ID',
},
{
dataIndex: 'name',
title: '姓名',
},
{
dataIndex: 'address',
title: '住址',
},
{
dataIndex: 'id',
title: '操作',
render: (id: string) => (
<Link to={`/${id}`}>详情</Link>
)
},
];
return (
<div>
<h1 style={{ marginBottom: 24 }}>用户列表</h1>
<Table rowKey="id" columns={columns} dataSource={data} />
</div>
);
}
Example #6
Source File: BrickWrapper.spec.tsx From next-core with GNU General Public License v3.0 | 6 votes |
describe("brick wrapper", () => {
it("should work", () => {
const wrapper = shallow(
<BrickWrapper>
<div>hello, brick-wrapper</div>
</BrickWrapper>
);
expect(wrapper).toMatchSnapshot();
});
it("should work", () => {
const wrapper = mount(
<BrickWrapper>
<Table />
</BrickWrapper>
);
expect(wrapper.find(Empty).length).toBe(1);
});
});
Example #7
Source File: topTable.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
topTable = ({ data, valueTitle, unitType, unit, query: { filter_host_ip, timestamp } }: IProps) => {
const columns = [
{
title: `${i18n.t('cmp:process')} ID`,
dataIndex: 'id',
},
{
title: i18n.t('cmp:process name'),
dataIndex: 'name',
},
{
title: valueTitle,
dataIndex: 'value',
render: (value: number) => getFormatter(unitType, unit).format(value),
},
];
const handleRowClick = ({ id, name }: any) => {
const queryMap = {
ip: filter_host_ip,
timestamp,
name,
};
goTo(`./${id}?${qs.stringify(queryMap)}`);
};
return (
<Table
rowKey="id"
columns={columns}
dataSource={get(data, 'list')}
rowClassName={() => 'cursor-pointer'}
onRowClick={handleRowClick}
scroll={{ x: '100%' }}
/>
);
}
Example #8
Source File: Test.tsx From use-antd-resizable-header with MIT License | 6 votes |
ResizableTable = (props) => {
const { components, resizableColumns, tableWidth } = useARH({ columns });
return (
<Table
columns={resizableColumns}
dataSource={data}
bordered
size="middle"
components={components}
scroll={{ x: "calc(700px + 50%)", y: tableWidth }}
/>
);
}
Example #9
Source File: index.tsx From jetlinks-ui-antd with MIT License | 6 votes |
render() {
return (
<PageHeaderWrapper title="数据字典">
<Card bordered={false}>
{/* <div className={styles.tableListForm}></div> */}
<Table columns={this.columns} rowKey={item => item.id} />
</Card>
</PageHeaderWrapper>
);
}
Example #10
Source File: index.tsx From covid_dashboard with MIT License | 5 votes |
public render() {
const { chartOptions, tableData, tableColumn } = this.state;
const { epData, onClose, lang, isMobile } = this.props;
return (
<div className="forcast">
<div className="forcast_inner">
<div className="forcast_title">
<FormattedMessage id="forecast.title" />
<Tooltip title={lang == 'zh' ? "疫情严重国家确诊数据预测" : "Forecast of confirmed data in severely affected countries"}>
<span className='tip'><Tip_Svg /></span>
</Tooltip>
</div>
<div className="forcast_forcast">
{chartOptions && (
<ReactEcharts option={chartOptions} lazyUpdate={true} style={{height: '260px'}}/>
)}
</div>
<div className="forcast_title">
<FormattedMessage id="forecast.realtime" />
<Tooltip title={lang == 'zh' ? "世界及地区疫情数据实时更新" : "Real-time updates of world and regional epidemic data"}>
<span className='tip'><Tip_Svg /></span>
</Tooltip>
</div>
{ this.realData() }
{isMobile && (
<div className="forcast_close" onClick={() => onClose && onClose()}>
<Close_Svg />
</div>
)}
{
tableData && tableColumn && (
<div className="forcast_table">{epData && (
<Table
className="forcast_table_table"
columns={tableColumn}
dataSource={tableData}
pagination={false}
size="small"
/>
)}</div>
)
}
</div>
</div>
);
}
Example #11
Source File: edit-policy-access-drawe.tsx From shippo with MIT License | 5 votes |
Component: React.ForwardRefRenderFunction<
EditPolicyAccessDrawerRef,
EditPolicyAccessDrawerProps
> = (props, ref) => {
const { onClose } = props
const [policy, setPolicy] = useState<IPermissionPolicy>(__defaultPolicy)
const [dataSource, setDataSource] = useState<IPermissionAccess[]>([])
const [visible, setVisible] = useState(false)
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([])
// ref
useImperativeHandle(ref, () => {
return {
// 打开抽屉
open: (policy: IPermissionPolicy) => {
services.permissionAccess.find_all_ext_status({ id: policy.id }).then((hr) => {
setDataSource(hr.data.resource)
setSelectedRowKeys(hr.data.resource.filter((item) => item.status).map((item) => item.id))
})
setPolicy(policy)
setVisible(true)
},
}
})
// 关闭抽屉
const closeDrawer = useCallback(() => {
onClose && onClose()
setVisible(false)
}, [onClose])
const handleSave = useCallback(async () => {
console.log(policy)
services.permissionPolicy.update_access({ id: policy.id, access: selectedRowKeys })
closeDrawer()
}, [policy, selectedRowKeys, closeDrawer])
return (
<Drawer
title="访问规则配置"
width={720}
onClose={closeDrawer}
visible={visible}
bodyStyle={{ paddingBottom: 80 }}
>
<Form layout="vertical" requiredMark={false}>
<Form.Item>
<Table
rowKey="id"
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys as number[]),
}}
columns={columns}
dataSource={dataSource}
size="small"
/>
</Form.Item>
<Form.Item>
<Space>
<Button onClick={closeDrawer}>关闭</Button>
<Button onClick={handleSave} type="primary">
保存
</Button>
</Space>
</Form.Item>
</Form>
</Drawer>
)
}
Example #12
Source File: table.tsx From generator-earth with MIT License | 5 votes |
export default function (props: ITableProps4List) {
const { CONTAINER_ROUTE_PREFIX } = useContext(BaseContext);
const pagination = useTablePagination(props);
const columns: ColumnProps<ITableRecord>[] = [
{
title: '编号',
dataIndex: 'assetCode',
key: 'assetCode'
}, {
title: '名称',
dataIndex: 'assetName',
key: 'assetName'
}, {
title: '主体',
dataIndex: 'contract',
key: 'contract'
}, {
title: '时间',
dataIndex: 'contractDate',
key: 'contractDate'
}, {
title: '创建时间',
dataIndex: 'createDate',
key: 'createDate'
}, {
title: '操作',
key: 'action',
render: (text, record) => (
<Link to={`${CONTAINER_ROUTE_PREFIX}/item/${record.id}`}>查看/修改</Link>
)
}, {
title: '操作',
key: 'action',
render: (text, record) => {
return <a onClick={()=>{onDelete(record.id)}} >删除</a> ;
}
},
];
const onDelete = (id) => {
Modal.confirm({
title: '确定要删除吗?',
onOk: async () => {
// 换成真实删除请求
// await this.props.deleteRecord(id)
console.log('deleting...', id);
// 重新刷新table
await props.updateTable();
},
onCancel() {},
});
};
return (
<Table className="ui-background clearfix"
title={()=>''}
rowKey={record=>record.id}
dataSource={props.tableData.dataSource}
columns={columns}
{...pagination}
/>
);
}
Example #13
Source File: DataTable.tsx From jmix-frontend with Apache License 2.0 | 5 votes |
render() {
const { loading, mainStore } = this.props;
if (mainStore?.isEntityDataLoaded() !== true) {
return (
<div className={styles.loader}>
<Spin size='large'/>
</div>
);
}
let defaultTableProps: TableProps<TEntity> = {
loading,
columns: this.generateColumnProps,
dataSource: this.items,
onChange: this.onChange,
pagination: this.paginationConfig,
rowKey: record => this.constructRowKey(record),
scroll: {x: true}
};
if (this.isRowSelectionEnabled) {
defaultTableProps = {
...defaultTableProps,
rowSelection: {
type: this.rowSelectionType,
selectedRowKeys: toJS(this.selectedRowKeys),
onChange: this.onRowSelectionColumnClicked,
},
};
if (this.props.canSelectRowByClick) {
defaultTableProps = {
...defaultTableProps,
onRow: this.onRow,
};
}
if (this.props.hideSelectionColumn) {
defaultTableProps.rowSelection = {
...defaultTableProps.rowSelection,
renderCell: () => '',
columnWidth: 0
};
}
}
if (this.props.enableFieldSettings) {
defaultTableProps = {
...defaultTableProps,
components: {
header: {
row: this.renderHeaderOnlyVisible
},
body: {
row: this.renderBodyOnlyVisible
},
}
};
}
const tableProps = { ...defaultTableProps, ...this.props.tableProps };
return (
<div className={`${styles.dataTable} ${this.props.hideSelectionColumn ? styles.hideSelectionColumn : ''}`}>
<div className={styles.buttons}>
{this.props.buttons}
{!!this.props.enableFieldSettings && <DataTableSettings
columns = {defaultTableProps.columns}
fieldsVisibility={this.fieldsVisibility}
onChange={this.changeFieldVisibility}
/>}
{this.props.hideClearFilters ? null : this.clearFiltersButton}
</div>
<Table { ...tableProps } />
</div>
);
}
Example #14
Source File: PersonalAPIKeys.tsx From posthog-foss with MIT License | 5 votes |
function PersonalAPIKeysTable(): JSX.Element {
const { keys } = useValues(personalAPIKeysLogic) as { keys: PersonalAPIKeyType[] }
const { deleteKey } = useActions(personalAPIKeysLogic)
const columns: ColumnsType<Record<string, any>> = [
{
title: 'Label',
dataIndex: 'label',
key: 'label',
},
{
title: 'Value',
dataIndex: 'value',
key: 'value',
className: 'ph-no-capture',
render: RowValue,
},
{
title: 'Last Used',
dataIndex: 'last_used_at',
key: 'lastUsedAt',
render: (lastUsedAt: string | null) => humanFriendlyDetailedTime(lastUsedAt),
},
{
title: 'Created',
dataIndex: 'created_at',
key: 'createdAt',
render: (createdAt: string | null) => humanFriendlyDetailedTime(createdAt),
},
{
title: '',
key: 'actions',
align: 'center',
render: RowActionsCreator(deleteKey),
},
]
return (
<Table
dataSource={keys}
columns={columns}
rowKey="id"
pagination={{ pageSize: 50, hideOnSinglePage: true }}
style={{ marginTop: '1rem' }}
/>
)
}
Example #15
Source File: GeneralStructsFormItem.spec.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
describe("GeneralStructsFormItem", () => {
it("should work", () => {
const props = {
dataSource: [
{
name: "param1",
type: "string",
description: "参数说明1",
},
{
name: "param2",
type: "int",
description: "参数说明2",
},
],
fieldsMap: {
name: "参数名",
type: "参数类型",
description: "参数说明",
},
};
const wrapper = shallow(<GeneralStructsFormItem {...props} />);
expect(wrapper.find(Table).prop("columns")[0]?.title).toEqual("参数名");
});
it("structItemShowRenderFN should work", () => {
const props = {
dataSource: [
{
name: "param1",
type: "string",
description: "参数说明1",
},
{
name: "param2",
type: "int",
description: "参数说明2",
},
],
fieldsMap: {
name: "参数名",
type: "参数类型",
description: "参数说明",
},
structItemShowRenderFN: (text: string) => text + "***",
};
const wrapper = mount(<GeneralStructsFormItem {...props} />);
expect(wrapper.find(Table).prop("columns")[0]?.render("test")).toEqual(
"test***"
);
});
it("structInnerTableColumnsOrder should work", () => {
const props = {
dataSource: [
{
name: "param1",
type: "string",
description: "参数说明1",
},
{
name: "param2",
type: "int",
description: "参数说明2",
},
],
fieldsMap: {
name: "参数名",
type: "参数类型",
description: "参数说明",
},
structInnerTableColumnsOrder: ["type", "name", "description"],
};
const wrapper = mount(<GeneralStructsFormItem {...props} />);
expect(wrapper.find(Table).prop("columns")[0].key).toEqual("type");
});
});
Example #16
Source File: sla-select.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
SLASelect = ({ dataSource, onChange, defaultSelectKey }: IProps) => {
const [activeKey, setActiveKey] = React.useState<number | undefined>(undefined);
const [filter, setFilter] = React.useState<string>('');
React.useEffect(() => {
setActiveKey(defaultSelectKey);
}, [defaultSelectKey]);
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
setFilter(e.target.value);
};
const handleChange = (key: string) => {
if (key) {
setActiveKey(+key);
onChange && onChange(+key);
}
};
const filterData = React.useMemo(() => {
return dataSource.filter((item) => item.name.toLowerCase().includes(filter.toLocaleLowerCase()));
}, [filter, dataSource]);
return (
<>
<Input.Search
onChange={handleSearch}
className="mb-3"
allowClear
placeholder={i18n.t('filter by {name}', { name: i18n.t('SLA name') })}
/>
{filterData.length ? (
<Collapse
className="sla-select"
accordion
expandIcon={({ panelKey }) => <Radio className="pt-1.5" checked={+panelKey === activeKey} />}
onChange={handleChange}
activeKey={activeKey}
>
{filterData.map((item) => {
const limits = item.limits || [];
const header = (
<Row>
<Col span={12}>
{i18n.t('SLA name')}: {item.name}
</Col>
<Col span={12}>
{i18n.t('Authorization method')}: {slaAuthorizationMap[item.approval]?.name}
</Col>
</Row>
);
return (
<Panel header={header} key={item.id}>
<Table
pagination={false}
dataSource={limits}
scroll={limits.length > 4 ? { y: 150, x: 800 } : { x: 800 }}
columns={[
{
title: i18n.t('times'),
dataIndex: 'limit',
width: 320,
},
{
title: i18n.t('unit'),
dataIndex: 'unit',
render: (unit) => slaUnitMap[unit],
},
]}
/>
</Panel>
);
})}
</Collapse>
) : (
<div className="sla-select">
<Empty />
</div>
)}
</>
);
}
Example #17
Source File: Home.tsx From react-ts-antd with MIT License | 5 votes |
render () {
const {
total,
pageNo,
pageSize,
loading,
dataSource,
columns,
visible,
title,
textBtn,
currentRowData
} = this.state;
const { Option } = Select;
return (
<DocumentTitle title={'首页'}>
<div className="home-container">
<Header curActive={'active'} />
<div className="content clearfix">
<div className="list">
<h2>任务列表</h2>
<div className="list-right">
<Space size="middle">
<Select size="large" onChange={ this.handleChange } style={{ width: 160 }} allowClear placeholder="请筛选任务状态">
<Option value=''>全部</Option>
<Option value={ 0 }>待办</Option>
<Option value={ 1 }>完成</Option>
<Option value={ 2 }>删除</Option>
</Select>
<Button type="primary" size="large" onClick={ this.addTask }><PlusOutlined /> 添加任务</Button>
</Space>
</div>
</div>
<Table
bordered
rowKey={ record => record.id }
dataSource={ dataSource }
columns={ columns }
loading={ loading }
pagination={ false }
/>
<Pagination
className="pagination"
total={ total }
style={{ display: loading && total === 0 ? 'none' : '' }}
showTotal={total => `共 ${total} 条数据`}
onChange={ this.changePage }
current={ pageNo }
showSizeChanger={ false }
defaultPageSize={ pageSize }
hideOnSinglePage={ false }
/>
</div>
<Footer />
<AddEditTaskForm
title={ title }
textBtn={ textBtn }
visible={ visible }
currentRowData={ currentRowData }
onSubmitDrawer={ this.onSubmit }
onCloseDrawer={ this.onClose }
/>
</div>
</DocumentTitle>
)
}
Example #18
Source File: EditableTable.tsx From jetlinks-ui-antd with MIT License | 5 votes |
render() {
const components = {
body: {
cell: EditableCell,
},
};
const columns = this.columns.map((col: any) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: any) => ({
record,
inputType: 'text',
dataIndex: col.dataIndex,
title: col.title,
editing: this.isEditing(record),
}),
};
});
const { data } = this.state;
const { closeVisible, handleSaveConfig } = this.props;
return (
<EditableContext.Provider value={this.props.form}>
<Modal
visible
title="数据转换"
width={840}
onOk={this.saveTableData}
onCancel={closeVisible}
okText='保存'
cancelText='关闭'
>
<Button onClick={this.handleAdd} type="primary" style={{ marginBottom: 16 }}>
添加
</Button>
<Divider type="vertical" />
保留原字段:
<Switch
onChange={this.changeKeepSource}
unCheckedChildren="否"
checkedChildren="是"
checked={data.keepSourceData} />
<Table
components={components}
bordered
dataSource={data.mappings}
columns={columns}
rowClassName={() => "editable-row"}
pagination={{
onChange: this.cancel,
}}
/>
</Modal>
</EditableContext.Provider>
);
}
Example #19
Source File: index.tsx From react_admin with MIT License | 4 votes |
FormTable: React.FC<{}> = () => {
const { loading, getColumnSearchProps, data } = useFrom({
url: formDataStirng,
})
const columns = [
{
title: '举办时间',
dataIndex: 'time',
sorter: (a: Itype, b: Itype) =>
new Date(a.time).getTime() - new Date(b.time).getTime(),
},
{
title: '赛事名称',
dataIndex: 'title',
...getColumnSearchProps('title'),
},
{
title: '级别',
dataIndex: 'ji',
filters: [
{
text: '省级',
value: true,
},
{
text: '校级',
value: false,
},
],
onFilter: (value: any, record: Itype) =>
record.ji === value ? true : false,
render(ji: boolean) {
if (ji === true) {
return '省级'
} else {
return '校级'
}
},
},
{
title: '年度',
dataIndex: 'level',
sorter: (a: Itype, b: Itype) => a.level - b.level,
},
{
title: '主办方',
dataIndex: 'school',
...getColumnSearchProps('school'),
},
{
title: '地点',
dataIndex: 'address',
...getColumnSearchProps('address'),
},
{
title: '描述',
dataIndex: 'desc',
...getColumnSearchProps('desc'),
},
{
title: '操作',
dataIndex: 'cao',
render: (text: string, record: Itype) => (
<Space size="middle">
<Tooltip title="查看详情">
<span>
<Icon type="iconicon-chakanxq" />
</span>
</Tooltip>
<Tooltip title="删除">
<span>
<Icon type="iconshanchu" />
</span>
</Tooltip>
<Tooltip title="修改">
<span>
<Icon type="iconxiugai" />
</span>
</Tooltip>
</Space>
),
},
]
return (
<>
<FromAdd />
<Spin spinning={loading}>
<Table bordered columns={columns} dataSource={data} />
</Spin>
</>
)
}
Example #20
Source File: access.tsx From shippo with MIT License | 4 votes |
Page_permission_access: React.FC = () => {
const [data, setData] = useState<IPermissionAccess[]>()
const editAccessDrawerRef = useRef<EditAccessDrawerRef>(null)
const handleDle = useCallback((id: number) => {
confirm({
title: '确认删除?',
icon: <ExclamationCircleOutlined />,
content: '此操作不可逆',
onOk() {
console.log('OK')
services.permissionAccess.del({ id }).then((hr) => {
if (hr.data.success) {
message.success('成功')
} else {
message.success('失败')
}
})
},
onCancel() {
console.log('Cancel')
},
})
}, [])
const [columns, setColumns] = useState<ColumnsType<IPermissionAccess>>([
{
title: '访问规则ID',
dataIndex: 'id',
key: 'id',
},
{
title: '访问规则表达式',
dataIndex: 'accessRule',
key: 'accessRule',
},
{
title: '描述',
dataIndex: 'remark',
key: 'remark',
},
{
title: '访问规则类型',
dataIndex: 'accessType',
key: 'accessType',
},
{
title: '被引用次数',
dataIndex: 'permissionAssociationCount',
key: 'permissionAssociationCount',
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
},
{
title: '操作',
key: 'action',
render: (_, record) => (
<Space size="middle">
<Button
type="link"
onClick={() => {
editAccessDrawerRef.current?.open(record)
}}
>
修改
</Button>
<Button
type="link"
onClick={() => {
handleDle(record.id)
}}
>
删除
</Button>
</Space>
),
},
])
const updateTable = useCallback(async () => {
const hr = await services.permissionAccess.find_all()
setData(
hr.data.resource.map((item) => {
return { ...item, createdAt: formatTimeStr(item.createdAt) }
})
)
}, [])
useMount(() => {
updateTable()
})
return (
<div>
<EditAccessDrawer ref={editAccessDrawerRef} onClose={() => updateTable()} />
<Space size="middle">
<Button type="primary" onClick={() => editAccessDrawerRef.current?.open()}>
新增访问规则
</Button>
</Space>
<Table
rowKey="id"
columns={columns}
dataSource={data}
pagination={{ position: ['bottomCenter'] }}
size="small"
/>
</div>
)
}
Example #21
Source File: index.tsx From vite-react-ts with MIT License | 4 votes |
Home: React.FC = () => {
const [form] = Form.useForm();
const list = useStore((state) => state.list);
const loading = useStore((state) => state.loading);
const editItem = useStore((state) => state.editItem);
const { getList, removeList, editList, addList, setEditItem } = useStore.getState();
const [visible, setVisible] = useState<boolean>(false);
useEffect(() => {
getList();
}, []);
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
{
title: 'Tags',
key: 'tags',
dataIndex: 'tags',
// eslint-disable-next-line react/display-name
render: (tags: any[]) => (
<>
{tags?.map((tag) => {
let color = tag.length > 5 ? 'geekblue' : 'green';
if (tag === 'loser') {
color = 'volcano';
}
return (
<Tag color={color} key={tag}>
{tag.toUpperCase()}
</Tag>
);
})}
</>
),
},
{
title: 'Action',
key: 'action',
// eslint-disable-next-line react/display-name
render: (_: any, record: { key: string }) => (
<Space size="middle">
<Button
type="primary"
onClick={() => {
setEditItem(record);
setVisible(true);
form.setFieldsValue(record);
}}>
修改
</Button>
<Button danger onClick={() => removeList(record.key)}>
删除
</Button>
</Space>
),
},
];
const handleCancle = () => {
setVisible(false);
};
const hanldeOk = () => {
handleCancle();
form.validateFields().then((res) => {
console.log(res);
editItem ? editList(res) : addList(res);
});
};
console.log('list', list);
return (
<div>
<h2>Home</h2>
<Space>
{/* <Button type="primary" onClick={() => setVisible(true)}>
新增
</Button>
<Button onClick={() => getList()}>refresh</Button> */}
</Space>
<Card loading={loading}>
<Table dataSource={list} columns={columns} />
</Card>
{/* transitionName=""和maskTransitionName=""是去除弹框动画属性 */}
<Modal
// transitionName=""
// maskTransitionName=""
title={editItem ? '修改信息' : '新增信息'}
visible={visible}
onOk={hanldeOk}
onCancel={handleCancle}
afterClose={() => {
form.resetFields();
setEditItem(undefined);
}}>
<Form form={form}>
<Form.Item required label="姓名" name="name">
<Input />
</Form.Item>
<Form.Item label="年龄" name="age">
<InputNumber />
</Form.Item>
<Form.Item name="tags" label="Tags">
<Select allowClear>
<Option key="nice" value="nice">
nice
</Option>
<Option key="developer" value="developer">
developer
</Option>
<Option value="loser">loser</Option>
<Option value="cool">cool</Option>
<Option value="teacher">teacher</Option>
</Select>
</Form.Item>
</Form>
</Modal>
</div>
);
}
Example #22
Source File: CartTable.tsx From Shopping-Cart with MIT License | 4 votes |
CartTable: FC<PropTypes> = props => {
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const { onClick, onChange, dataSource, onSelectChange } = props;
// 장바구니 비우기 버튼 클릭 핸들러
const handleCleanCartClick = useCallback(() => {
ConfirmModal('장바구니에 있는 모든 상품을 삭제하시겠습니까?', onClick);
}, [onClick]);
const handleSelectChange = useCallback(
(selectedRowKeys: any, selectedRows) => {
setSelectedRowKeys(selectedRowKeys);
onSelectChange(selectedRowKeys, selectedRows);
},
[setSelectedRowKeys, selectedRowKeys, onSelectChange],
);
const rowSelection = {
selectedRowKeys,
onChange: handleSelectChange,
};
const handleInputNumberChange = useCallback(
(id: ProductModel['id'], quantity: number | undefined) => {
onChange(id, quantity as number);
},
[onChange],
);
const columns = [
{
title: '상품 제목',
dataIndex: 'title',
align: 'center' as 'center', // NOTE: 멍충한 antd 때문에 assertion을 통해 한번 더 타입을 확정해 준다
width: '50%',
},
{
title: '수량',
dataIndex: 'quantity',
align: 'center' as 'center',
value: InputNumber,
render: (quantity: Quantity) => (
<InputNumber
style={{ width: '65px' }}
min={1}
defaultValue={quantity.quantity}
onChange={num => handleInputNumberChange(quantity.id, num)}
/>
),
},
{
title: '가격',
dataIndex: 'displayPrice',
align: 'center' as 'center',
render: (displayPrice: number) => (
<PriceLabel value={displayPrice} strong={true} />
),
},
{
title: '쿠폰 적용',
dataIndex: 'availableCoupon',
align: 'center' as 'center',
render: (availableCoupon: boolean) =>
availableCoupon === undefined ? (
<CouponTag
label="가능"
tooltip="아래 쿠폰 선택시 자동 적용됩니다"
color="#108ee9"
/>
) : (
<Tag>불가능</Tag>
),
},
];
return (
<>
<div style={{ marginBottom: 16, textAlign: 'right' }}>
<span style={{ marginRight: 10 }}>
{selectedRowKeys.length > 0
? `선택 상품(${selectedRowKeys.length}개)`
: ' '}
</span>
<Button onClick={handleCleanCartClick} disabled={!dataSource.length}>
장바구니 비우기
</Button>
</div>
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={dataSource}
pagination={false}
/>
</>
);
}
Example #23
Source File: index.tsx From posthog-foss with MIT License | 4 votes |
// Type matches antd.Table
export function ResizableTable<RecordType extends Record<any, any> = any>({
columns: initialColumns = [],
components,
...props
}: ResizableTableProps<RecordType>): JSX.Element {
const breakpoint = useBreakpoint()
const minColumnWidth = getMinColumnWidth(breakpoint)
const [columns, setColumns] = useState(() => {
const lastIndex = initialColumns.length
return initialColumns.map((col, index) => ({
...col,
width: index === lastIndex ? undefined : minColumnWidth,
})) as InternalColumnType<RecordType>[]
})
const [headerColumns, setHeaderColumns] = useState(columns)
const [headerShouldRender, setHeaderShouldRender] = useState(false)
const scrollWrapperRef = useRef<HTMLDivElement>(null)
const overlayRef = useRef<HTMLDivElement>(null)
const timeout: any = useRef()
function setScrollableRight(value: boolean): void {
if (value) {
return overlayRef?.current?.classList.add('scrollable-right')
}
return overlayRef?.current?.classList.remove('scrollable-right')
}
function updateScrollGradient(): void {
if (overlayRef.current) {
const overlay = overlayRef.current
if (overlay.offsetWidth + overlay.scrollLeft < overlay.scrollWidth) {
setScrollableRight(true)
} else {
setScrollableRight(false)
}
}
}
function getColumnCSSWidths(): Array<number | undefined> {
const columnNodes = scrollWrapperRef.current?.querySelectorAll<HTMLElement>('.ant-table-content colgroup col')
if (columnNodes) {
const cols = Array.from(columnNodes)
return cols.map((col) => (col.style.width ? parsePixelValue(col.style.width) : undefined))
}
return []
}
function updateColumnWidth(index: number, width: number): void {
const col = scrollWrapperRef.current?.querySelector(
// nth-child is 1-indexed. first column is fixed. last column width must be uncontrolled.
`.ant-table-content colgroup col:nth-child(${index + 1 + Number(!!props.expandable)}):not(:last-child)`
)
col?.setAttribute('style', `width: ${width}px;`)
}
function unsetLastColumnStyle(): void {
// last column width must be uncontrolled.
const col = scrollWrapperRef.current?.querySelector('.ant-table-content colgroup col:last-child')
col?.removeAttribute('style')
}
function updateTableWidth(): void {
// <table> elements have super strange auto-sizing: (https://css-tricks.com/fixing-tables-long-strings/)
// We control the width of the <table> based on the width of the virtual header.
const header = scrollWrapperRef.current?.querySelector('.resizable-virtual-table-header')
if (header?.childNodes) {
const children = Array.from(header?.childNodes) as HTMLElement[]
const headerWidth = children.reduce((total, { offsetWidth }) => total + (offsetWidth ?? 0), 0)
if (headerWidth) {
const table = scrollWrapperRef.current?.querySelector('.ant-table table')
table?.setAttribute('style', `width: ${headerWidth}px;`)
}
}
unsetLastColumnStyle()
}
const handleColumnResize =
(index: number): ResizeHandler =>
(_, { size: { width } }) => {
if (timeout.current) {
cancelAnimationFrame(timeout.current)
}
timeout.current = requestAnimationFrame(function () {
updateColumnWidth(index, width)
updateTableWidth()
})
updateScrollGradient()
}
function handleWrapperResize(newWidth: number): void {
// Recalculate column widths if the wrapper changes size.
const table = scrollWrapperRef.current?.querySelector('.ant-table table')
const oldWidth = table?.clientWidth
if (!oldWidth || oldWidth === newWidth) {
return
}
if (timeout.current) {
cancelAnimationFrame(timeout.current)
}
const resizeRatio = newWidth / oldWidth
const columnWidths = getColumnCSSWidths()
timeout.current = requestAnimationFrame(function () {
setHeaderShouldRender(false)
setHeaderColumns((cols) => {
const lastIndex = initialColumns.length - 1
const nextColumns = cols.map((column, index) =>
index === lastIndex
? column
: {
...column,
width: Math.max(
(columnWidths[index + Number(!!props.expandable)] ?? 0) * resizeRatio,
minColumnWidth
),
}
)
nextColumns.slice(0, lastIndex).forEach((col, index) => {
updateColumnWidth(index, col.width ?? minColumnWidth)
})
updateTableWidth()
return nextColumns
})
setHeaderShouldRender(true)
})
}
const resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {
entries.forEach(({ contentRect: { width } }) => handleWrapperResize(width))
})
useEffect(() => {
// Update render prop when parent columns change
setColumns((cols) => {
const lastIndex = cols.length
return cols.map((column, index) =>
index === lastIndex
? column
: {
...column,
render: initialColumns[index].render,
}
)
})
}, [initialColumns])
useLayoutEffect(() => {
// Calculate relative column widths (px) once the wrapper is mounted.
if (scrollWrapperRef.current) {
resizeObserver.observe(scrollWrapperRef.current)
const wrapperWidth = scrollWrapperRef.current.clientWidth
const gridBasis = columns.reduce((total, { span }) => total + span, 0)
const columnSpanWidth = getFullwidthColumnSize(wrapperWidth, gridBasis)
setColumns((cols) => {
const lastIndex = cols.length
const nextColumns = cols.map((column, index) =>
index === lastIndex
? column
: {
...column,
width: Math.max(column.defaultWidth || columnSpanWidth * column.span, minColumnWidth),
}
)
setHeaderColumns(nextColumns)
return nextColumns
})
updateScrollGradient()
setHeaderShouldRender(true)
}
}, [])
return (
<div ref={scrollWrapperRef} className="resizable-table-scroll-container" onScroll={updateScrollGradient}>
<div ref={overlayRef} className="table-gradient-overlay">
{headerShouldRender && (
<VirtualTableHeader
columns={headerColumns}
handleResize={handleColumnResize}
layoutEffect={updateTableWidth}
minColumnWidth={minColumnWidth}
expandable={props.expandable}
/>
)}
<Table
columns={columns}
components={{
...components,
header: { cell: () => null }, // Nix that header row
}}
tableLayout="fixed"
{...props}
/>
</div>
</div>
)
}
Example #24
Source File: index.tsx From antdp with MIT License | 4 votes |
EditableTable = (
props: EditableTableProps,
ref: React.ForwardedRef<RefEditTableProps>,
) => {
const {
columns,
dataSource = [],
onBeforeSave,
onSave,
rowKey = 'id',
optIsFirst = false,
optConfig = {},
isOptDelete = false,
initValue = {},
onValuesChange,
isAdd,
onErr,
multiple = false,
onBeforeAdd,
isOpt = true,
addBtnProps = {},
store,
...rest
} = props;
const [formsRef] = useStore(store)
const [editingKey, setEditingKey] = useState<string[]>([]);
const [newAdd, setNewAdd] = React.useState<string[]>([]);
/** editingKey 和 newAdd 移出 id */
const removeKey = (id: string | number) => {
setEditingKey((arr) => arr.filter((k) => `${k}` !== `${id}`));
setNewAdd((arr) => arr.filter((k) => `${k}` !== `${id}`));
};
/** 获取行 所有编辑字段 */
const fields: string[] = React.useMemo(() => {
return columns
.filter((item) => {
return item.editable;
})
.map((item) => item.dataIndex as string);
}, [columns]);
/** 重置 某个表单 */
const restForm = (key: string | number, obj = {}) => {
const stores = formsRef.getStore();
if (stores[`${key}`]) {
stores[`${key}`].setFieldsValue(obj);
}
};
/** 获取某个表单 */
const getForm = (id: string | number) => {
const stores = formsRef.getStore();
return stores[`${id}`];
};
/** 判断是否编辑 */
const isEditing = (record: any) => editingKey.includes(`${record[rowKey]}`);
/** 判断是否是新增的 */
const isAddEdit = (record: any) => newAdd.includes(`${record[rowKey]}`);
/** 新增 */
const add = () => {
// 新增之前的调用方法
if (onBeforeAdd && !onBeforeAdd()) {
return;
}
if (newAdd.length === 1 && !multiple) {
message.warn('只能新增一行');
return;
}
if (editingKey.length === 1 && !multiple) {
message.warn('只能编辑一行');
return;
}
const id = (new Date().getTime() * Math.round(10)).toString();
const newItem = { ...(initValue || {}), [rowKey]: id };
const list = dataSource.concat([newItem]);
setEditingKey((arr) => arr.concat([id]));
setNewAdd((arr) => arr.concat([id]));
onSave && onSave(list, newItem);
};
/** 编辑 */
const edit = (record: any) => {
let obj = { ...record };
restForm(record[rowKey], obj);
setEditingKey((arr) => arr.concat([`${record[rowKey]}`]));
};
/** 取消编辑 */
const cancel = (id: string | number) => {
removeKey(id);
restForm(id, {});
};
/** 删除行 */
const onDelete = (id: string | number, rowItem: object, index: number) => {
const list = dataSource.filter((item) => `${item[rowKey]}` !== `${id}`);
removeKey(id);
onSave && onSave(list, rowItem, rowItem, index);
};
/** 保存 */
const save = async (key: string | number, record: object, indx: number) => {
try {
const row = await getForm(key).validateFields();
if (onBeforeSave && !onBeforeSave(row, record, indx)) {
return;
}
const newData = [...dataSource];
const index = newData.findIndex((item) => `${key}` === `${item[rowKey]}`);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
} else {
newData.push(row);
}
onSave && onSave(newData, row, record, indx);
removeKey(key);
getForm(key).resetFields(fields);
} catch (errInfo) {
onErr && onErr(errInfo as ValidateErrorEntity<any>);
}
};
/** 操作列配置 */
const operation: ColumnsProps[] =
(isOpt &&
Operation({
optConfig,
isEditing,
isAddEdit,
save,
isOptDelete,
cancel,
onDelete,
edit,
newAdd,
editingKey,
rowKey,
multiple,
})) ||
[];
const optColumns = optIsFirst
? operation.concat(columns)
: columns.concat(operation);
const mergedColumns = optColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: any) => ({
record,
multiple,
rowKey,
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
inputNode: col.inputNode,
rules: col.rules || [],
itemAttr: col.itemAttr,
type: col.type,
attr: col.attr,
tip: col.tip,
tipAttr: col.tipAttr,
isList: col.isList,
listAttr: col.listAttr,
}),
};
}) as ColumnsType<any>;
// 表单值更新 表单更新值适用单个 不使用多个
const onChange = (
id: string | number,
form: FormInstance,
value: any,
allValue: any,
) => {
if (onValuesChange) {
const list = dataSource.map((item) => {
if (`${id}` === `${item[rowKey]}`) {
return { ...item, ...allValue };
}
return { ...item };
});
onValuesChange(list, value, allValue, id, form);
}
};
React.useImperativeHandle(
ref,
(): RefEditTableProps => ({
save,
onDelete,
edit,
cancel,
add,
isEditing,
editingKey,
newAdd,
forms: formsRef,
}),
);
return (
<React.Fragment>
<EditForms.Provider
value={{
formsRef,
onValuesChange: onChange,
dataSource,
rowKey,
}}
>
<Table
size="small"
bordered
{...rest}
components={{
body: {
row: Tr,
cell: Td,
},
}}
rowKey={rowKey}
dataSource={dataSource}
columns={mergedColumns}
rowClassName="editable-row"
pagination={false}
/>
{isAdd && (
<Button
type="dashed"
block
children="添加一行数据"
{...(addBtnProps || {})}
style={{ marginTop: 10, ...((addBtnProps || {}).style || {}) }}
onClick={add}
/>
)}
</EditForms.Provider>
</React.Fragment>
);
}
Example #25
Source File: index.tsx From GWebGPUEngine with MIT License | 4 votes |
App = React.memo(function BellmanFord() {
const [timeElapsed, setTimeElapsed] = useState(0);
const [datasource, setDatasource] = useState<
Array<{
destination: string;
weight: number;
prevPoint: string;
}>
>([]);
const renderFruchterman = () => {
const graph = new G6.Graph({
container: 'container',
width: 300,
height: 300,
modes: {
default: ['drag-canvas', 'drag-node'],
},
layout: {
type: 'fruchterman',
gravity: 5,
speed: 5,
},
animate: true,
defaultNode: {
size: 30,
style: {
lineWidth: 2,
stroke: '#5B8FF9',
fill: '#C6E5FF',
},
},
defaultEdge: {
size: 1,
color: '#e2e2e2',
style: {
endArrow: {
path: 'M 0,0 L 8,4 L 8,-4 Z',
fill: '#e2e2e2',
},
},
},
});
graph.data(data);
graph.render();
};
const buildAdjacencyList = (
nodes: Array<{
id: string;
label: string;
}>,
edges: Array<{
source: string;
target: string;
value: number;
}>,
sourceNodeIdx: number,
) => {
const adjacencyList = [];
const nodeDict = [];
const mapIdPos = {};
let i = 0;
for (i = 0; i < nodes.length; i++) {
const n = nodes[i];
mapIdPos[n.id] = i;
if (i === sourceNodeIdx) {
adjacencyList.push(0); // distance
} else {
adjacencyList.push(MAX_DISTANCE); // Infinity
}
adjacencyList.push(-1); // predecessor
adjacencyList.push(0); // offset
adjacencyList.push(0); // outputing edge length
nodeDict.push([]);
}
for (i = 0; i < edges.length; i++) {
const e = edges[i];
nodeDict[mapIdPos[e.source]].push({
target: mapIdPos[e.target],
weight: e.value,
});
}
let maxEdgePerVertex = 0;
for (i = 0; i < nodes.length; i++) {
const offset = adjacencyList.length;
const dests = nodeDict[i];
adjacencyList[i * 4 + 2] = offset;
adjacencyList[i * 4 + 3] = dests.length;
maxEdgePerVertex = Math.max(maxEdgePerVertex, dests.length);
for (const dest of dests) {
const { target, weight } = dest;
adjacencyList.push(target); // dest vertex index
adjacencyList.push(weight); // edge weight
}
}
while (adjacencyList.length % 4 !== 0) {
adjacencyList.push(0);
}
return [new Float32Array(adjacencyList), maxEdgePerVertex];
};
const calcShortestPath = async (source: string) => {
const [adjacencyList, maxEdgePerVertex] = buildAdjacencyList(
data.nodes,
data.edges,
data.nodes.findIndex((n) => n.id === source),
);
const vertexNum = data.nodes.length;
if (kernel) {
const timeStart = window.performance.now();
kernel.setBinding({
gData: adjacencyList,
MAX_EDGE_PER_VERTEX: maxEdgePerVertex,
VERTEX_COUNT: data.nodes.length,
MAX_DISTANCE,
});
// relax all edges |V|-1 times
await kernel.execute(vertexNum - 1);
const output = await kernel.getOutput();
setTimeElapsed(window.performance.now() - timeStart);
setDatasource(
new Array(data.nodes.length).fill(0).map((_, i) => {
const prevPoint = data.nodes[output[i * 4 + 1]];
const weight = output[i * 4];
return {
destination: data.nodes[i].id,
weight: weight === MAX_DISTANCE ? 'MAX' : weight,
prevPoint: (prevPoint && prevPoint.id) || '-',
};
}),
);
}
};
useEffect(() => {
(async () => {
renderFruchterman();
// compile our kernel code
const compiler = new Compiler();
const precompiledBundle = compiler.compileBundle(gCode);
// create world
const world = World.create({
engineOptions: {
supportCompute: true,
},
});
const vertexNum = data.nodes.length;
kernel = world
.createKernel(precompiledBundle)
.setDispatch([Math.ceil(vertexNum / 16), 1, 1]);
await calcShortestPath('A');
})();
}, []);
return (
<>
<div id="container" />
<div>Elapsed time: {Math.round(timeElapsed)} ms</div>
<div>
Shortest path from
<Select
defaultValue="A"
options={data.nodes.map((node) => ({
value: node.id,
label: node.label,
}))}
onChange={calcShortestPath}
/>
</div>
<Table
rowKey="destination"
columns={[
{
dataIndex: 'destination',
title: 'destination',
},
{
dataIndex: 'weight',
title: 'weight',
},
{
dataIndex: 'prevPoint',
title: 'previous point',
},
]}
dataSource={datasource}
pagination={false}
/>
</>
);
})
Example #26
Source File: DevicesPage.tsx From iot-center-v2 with MIT License | 4 votes |
DevicesPage: FunctionComponent<Props> = ({helpCollapsed}) => {
const [loading, setLoading] = useState(true)
const [message, setMessage] = useState<Message | undefined>(undefined)
const [data, setData] = useState(NO_DEVICES)
const [dataStamp, setDataStamp] = useState(0)
const [lastEntries, setLastEntries] = useState(NO_ENTRIES)
useEffect(() => {
setLoading(true)
const fetchDevices = async () => {
try {
const response = await fetch('/api/devices')
if (response.status >= 300) {
const text = await response.text()
throw new Error(`${response.status} ${text}`)
}
const data = (await response.json()) as Array<DeviceInfo>
setData(data)
setLastEntries(
await Promise.all(
data.map(({deviceId}) => fetchLastEntryTime(deviceId))
)
)
} catch (e) {
setMessage({
title: 'Cannot fetch data',
description: String(e),
type: 'error',
})
} finally {
setLoading(false)
}
}
fetchDevices()
}, [dataStamp])
const removeAuthorization = async (device: DeviceInfo) => {
try {
setLoading(true)
const response = await fetch(`/api/devices/${device.deviceId}`, {
method: 'DELETE',
})
if (response.status >= 300) {
const text = await response.text()
throw new Error(`${response.status} ${text}`)
}
setLoading(false)
antdMessage.success(`Device ${device.deviceId} was unregistered`, 2)
} catch (e) {
setLoading(false)
setMessage({
title: 'Cannot remove device',
description: String(e),
type: 'error',
})
} finally {
setDataStamp(dataStamp + 1)
}
}
const addAuthorization = async (deviceId: string, deviceType: string) => {
try {
setLoading(true)
const response = await fetch(`/api/env/${deviceId}`)
if (response.status >= 300) {
const text = await response.text()
throw new Error(`${response.status} ${text}`)
}
const {newlyRegistered} = await response.json()
if (newlyRegistered && deviceType !== '') {
const setTypeResponse = await fetch(
`/api/devices/${deviceId}/type/${deviceType}`,
{
method: 'POST',
}
)
if (setTypeResponse.status >= 300) {
const text = await setTypeResponse.text()
throw new Error(`${setTypeResponse.status} ${text}`)
}
}
setLoading(false)
if (newlyRegistered) {
antdMessage.success(`Device '${deviceId}' was registered`, 2)
} else {
antdMessage.success(`Device '${deviceId}' is already registered`, 2)
}
} catch (e) {
setLoading(false)
setMessage({
title: 'Cannot register device',
description: String(e),
type: 'error',
})
} finally {
setDataStamp(dataStamp + 1)
}
}
// define table columns
const columnDefinitions: ColumnsType<DeviceInfo> = [
{
title: 'Device ID',
dataIndex: 'deviceId',
defaultSortOrder: 'ascend',
render: (deviceId: string) => (
<Link to={`/devices/${deviceId}`}>{deviceId}</Link>
),
},
{
title: 'Registration Time',
dataIndex: 'createdAt',
responsive: helpCollapsed ? ['lg'] : ['xxl'],
},
{
title: 'Last Entry',
dataIndex: 'deviceId',
render: (id: string) => {
const lastEntry = lastEntries.find(
({deviceId}) => deviceId === id
)?.lastEntry
if (lastEntry != null && lastEntry !== 0)
return timeFormatter({
timeZone: 'UTC',
format: 'YYYY-MM-DD HH:mm:ss ZZ',
})(lastEntry)
},
responsive: helpCollapsed ? ['xl'] : [],
},
{
title: '',
key: 'action',
align: 'right',
render: (_: string, device: DeviceInfo) => (
<>
<Tooltip title="Go to device settings" placement="topRight">
<Button
type="text"
icon={<IconSettings />}
href={`/devices/${device.deviceId}`}
/>
</Tooltip>
<Tooltip title="Go to device dashboard" placement="topRight">
<Button
type="text"
icon={<IconDashboard />}
href={`/dashboard/${device.deviceId}`}
/>
</Tooltip>
<Popconfirm
icon={<ExclamationCircleFilled style={{color: 'red'}} />}
title={`Are you sure to remove '${device.deviceId}' ?`}
onConfirm={() => removeAuthorization(device)}
okText="Yes"
okType="danger"
cancelText="No"
>
<Tooltip title="Remove device" placement="topRight" color="red">
<Button type="text" icon={<IconDelete />} />
</Tooltip>
</Popconfirm>
</>
),
},
]
return (
<PageContent
title="Device Registrations"
spin={loading}
message={message}
titleExtra={
<>
<Tooltip title="Register a new Device">
<Button
onClick={() => {
let deviceId = ''
let deviceType = ''
Modal.confirm({
title: 'Register Device',
icon: '',
content: (
<Form
name="registerDevice"
initialValues={{deviceId, deviceType}}
>
<Form.Item
name="deviceId"
rules={[
{required: true, message: 'Please input device ID !'},
]}
>
<Input
placeholder="Device ID"
onChange={(e) => {
deviceId = e.target.value
}}
/>
<Input
placeholder="Device type"
onChange={(e) => {
deviceType = e.target.value
}}
/>
</Form.Item>
</Form>
),
onOk: () => {
addAuthorization(deviceId, deviceType)
},
okText: 'Register',
})
}}
>
Register
</Button>
</Tooltip>
<Tooltip title="Reload Table">
<Button
type="primary"
onClick={() => setDataStamp(dataStamp + 1)}
style={{marginRight: '8px'}}
>
Reload
</Button>
</Tooltip>
</>
}
>
<Table
dataSource={data}
columns={columnDefinitions}
rowKey={deviceTableRowKey}
/>
</PageContent>
)
}
Example #27
Source File: Dashboard.tsx From nodestatus with MIT License | 4 votes |
Dashboard: FC = () => {
const { servers, timeSince } = useContext(StatusContext);
const [count, setCount] = useState({ online: 0, record: {} });
useEffect(() => {
let online = 0;
const record: Record<string, number> = {};
const add = (key: string) => {
if (typeof record[key] === 'undefined') {
record[key] = 0;
}
record[key]++;
};
for (const item of servers) {
if (item.status) online++;
add(item.region);
}
setCount({
online, record
});
}, [servers]);
const columns: ColumnsType<ITable> = useMemo(() => [
{
title: 'SERVER',
dataIndex: 'server',
render(_, record) {
return (
<div className="flex items-center text-sm">
<svg viewBox="0 0 100 100" className="mr-3 block h-12 w-12">
<use xlinkHref={`#${record.region}`} />
</svg>
<div className="whitespace-nowrap">
<p className="font-semibold">{record.name}</p>
<p className="text-left text-xs text-gray-600">{record.location}</p>
</div>
</div>
);
}
},
{
title: 'STATUS',
dataIndex: 'status',
align: 'center',
render: status => (
status
? <Tag color="success">Online</Tag>
: <Tag color="error">Offline</Tag>
)
},
{
title: 'UPTIME',
dataIndex: 'uptime',
align: 'center',
render(uptime) {
return uptime === '-' ? '-' : parseUptime(uptime);
}
},
{
title: 'LOAD',
dataIndex: 'load',
align: 'center'
}
], []);
const TableFooter = useCallback(() => (
<span className="text-xs">
最后更新:
{timeSince}
</span>
), [timeSince]);
return (
<>
<Title level={2} className="my-6 text-3xl">Dashboard</Title>
<Row gutter={32} className="mb-4">
<Col xs={{ span: 24 }} lg={{ span: 12 }} className="flex items-center mb-4 xs:mb-0">
<MapChart count={count.record} />
</Col>
<Col xs={{ span: 24 }} lg={{ span: 12 }}>
<Row>
<Col xs={{ span: 24 }} className="mb-4">
<StateCard
title="Servers Total"
count={servers.length}
icon={(
<RoundIcon
icon={BiServer}
iconColorClass="text-yellow-500"
bgColorClass="bg-yellow-100"
/>
)}
/>
</Col>
<Col xs={{ span: 24 }} className="mb-4">
<StateCard
title="Servers Online"
count={count.online}
icon={(
<RoundIcon
icon={HiOutlineStatusOnline}
iconColorClass="text-green-500"
bgColorClass="bg-green-100"
/>
)}
/>
</Col>
<Col xs={{ span: 24 }}>
<StateCard
title="Servers Offline"
count={servers.length - count.online}
icon={(
<RoundIcon
icon={AiFillWarning}
iconColorClass="text-blue-500"
bgColorClass="bg-blue-100"
/>
)}
/>
</Col>
</Row>
</Col>
</Row>
<Table
className="rounded-lg max-w-full"
dataSource={servers}
columns={columns}
footer={TableFooter}
rowKey="id"
/>
</>
);
}
Example #28
Source File: user-configuration.tsx From utopia with MIT License | 4 votes |
export function UserConfiguration() {
const { dispatch, shortcutConfig } = useEditorState((store) => {
return {
dispatch: store.dispatch,
shortcutConfig: store.userState.shortcutConfig,
}
}, 'UserConfiguration')
const [editingIndex, setEditingIndex] = React.useState<number | null>(null)
const dataSource: Array<DataSourceEntry> = React.useMemo(() => {
const detailsMap = getShortcutDetails(shortcutConfig)
let detailsArray: Array<ShortcutWithName> = mapToArray((shortcut, name) => {
return {
...shortcut,
name: name,
}
}, detailsMap)
detailsArray.sort((first, second) => comparePrimitive(first.description, second.description))
return detailsArray.map((shortcut) => {
return {
description: shortcut.description,
shortcut: shortcut.shortcutKeys,
// TODO: Possibly this needs including the shortcut column somehow.
keydown: shortcut.shortcutKeys.every((key) => key.keyDownOrUp === 'keydown'),
name: shortcut.name,
}
})
}, [shortcutConfig])
const renderKeyDownField = React.useCallback(
(value: boolean, record: DataSourceEntry, index: number) => {
function onChange() {
const newKeys: Array<Key> = record.shortcut.map((key) => {
return {
...key,
keyDownOrUp: key.keyDownOrUp === 'keydown' ? 'keyup' : 'keydown',
}
})
const actions = newKeys.map((key) => setShortcut(record.name, key))
dispatch(actions, 'everyone')
}
return <Checkbox checked={value} onChange={onChange} />
},
[dispatch],
)
const setEditingShortcut = React.useCallback(
(event: React.KeyboardEvent) => {
event.stopPropagation()
event.preventDefault()
if (editingIndex != null) {
const nativeEvent = event.nativeEvent
const newShortcut = Keyboard.keyFromEvent(nativeEvent)
switch (newShortcut.character) {
case 'shift':
case 'ctrl':
case 'alt':
case 'cmd':
// Need to ignore modifiers.
break
default:
if (editingIndex in dataSource) {
const dataEntry = dataSource[editingIndex]
dispatch([setShortcut(dataEntry.name, newShortcut)], 'everyone')
setEditingIndex(null)
}
}
}
},
[editingIndex, setEditingIndex, dispatch, dataSource],
)
const renderKeyAndModifiers = React.useCallback(
(
value: [Key],
record: DataSourceEntry,
index: number,
): React.ReactNode | RenderedCell<DataSourceEntry> => {
if (index === editingIndex) {
return (
<input
type='text'
autoFocus={true}
style={{
padding: '0px',
border: '0px',
caretColor: 'transparent',
}}
onKeyDown={setEditingShortcut}
value='<Press New Shortcut>'
/>
)
} else {
const renderedKeys = value.map((key) => {
if (key.modifiers.length === 0) {
return capitalize(key.character)
} else {
return `${key.modifiers.map(capitalize).join('+')}+${capitalize(key.character)}`
}
})
return renderedKeys.join(', ')
}
},
[setEditingShortcut, editingIndex],
)
const onRow: GetComponentProps<DataSourceEntry> = React.useCallback(
(data: DataSourceEntry, index?: number) => {
return {
onDoubleClick: (event: React.MouseEvent) => {
setEditingIndex(index ?? null)
},
}
},
[setEditingIndex],
)
return (
<Table dataSource={dataSource} pagination={false} onRow={onRow}>
<Column title='Description' key='description' dataIndex='description' />
<Column title='Shortcut' key='shortcut' dataIndex='shortcut' render={renderKeyAndModifiers} />
<Column title='Key Down' key='keydown' dataIndex='keydown' render={renderKeyDownField} />
</Table>
)
}
Example #29
Source File: index.tsx From ql with MIT License | 4 votes |
Config = () => {
const columns = [
{
title: '序号',
align: 'center' as const,
render: (text: string, record: any, index: number) => {
return <span style={{ cursor: 'text' }}>{index + 1} </span>;
},
},
{
title: '昵称',
dataIndex: 'nickname',
key: 'nickname',
align: 'center' as const,
width: '15%',
render: (text: string, record: any, index: number) => {
const match = record.value.match(/pt_pin=([^; ]+)(?=;?)/);
const val = (match && match[1]) || '未匹配用户名';
return (
<span style={{ cursor: 'text' }}>{record.nickname || val} </span>
);
},
},
{
title: '值',
dataIndex: 'value',
key: 'value',
align: 'center' as const,
width: '50%',
render: (text: string, record: any) => {
return (
<span
style={{
textAlign: 'left',
display: 'inline-block',
wordBreak: 'break-all',
cursor: 'text',
}}
>
{text}
</span>
);
},
},
{
title: '状态',
key: 'status',
dataIndex: 'status',
align: 'center' as const,
width: '15%',
render: (text: string, record: any, index: number) => {
return (
<Space size="middle" style={{ cursor: 'text' }}>
<Tag
color={StatusColor[record.status] || StatusColor[3]}
style={{ marginRight: 0 }}
>
{Status[record.status]}
</Tag>
{record.status !== Status.已禁用 && (
<Tooltip title="刷新">
<a onClick={() => refreshStatus(record, index)}>
<SyncOutlined />
</a>
</Tooltip>
)}
</Space>
);
},
},
{
title: '操作',
key: 'action',
align: 'center' as const,
render: (text: string, record: any, index: number) => (
<Space size="middle">
<Tooltip title="编辑">
<a onClick={() => editCookie(record, index)}>
<EditOutlined />
</a>
</Tooltip>
<Tooltip title={record.status === Status.已禁用 ? '启用' : '禁用'}>
<a onClick={() => enabledOrDisabledCookie(record, index)}>
{record.status === Status.已禁用 ? (
<CheckCircleOutlined />
) : (
<StopOutlined />
)}
</a>
</Tooltip>
<Tooltip title="删除">
<a onClick={() => deleteCookie(record, index)}>
<DeleteOutlined />
</a>
</Tooltip>
</Space>
),
},
];
const [width, setWidth] = useState('100%');
const [marginLeft, setMarginLeft] = useState(0);
const [marginTop, setMarginTop] = useState(-72);
const [value, setValue] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [isModalVisible, setIsModalVisible] = useState(false);
const [editedCookie, setEditedCookie] = useState();
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
const getCookies = () => {
setLoading(true);
request
.get(`${config.apiPrefix}cookies`)
.then((data: any) => {
setValue(data.data);
})
.finally(() => setLoading(false));
};
const refreshStatus = (record: any, index: number) => {
request
.get(`${config.apiPrefix}cookies/${record._id}/refresh`)
.then(async (data: any) => {
if (data.data && data.data.value) {
(value as any).splice(index, 1, data.data);
setValue([...(value as any)] as any);
} else {
message.error('更新状态失败');
}
});
};
const enabledOrDisabledCookie = (record: any, index: number) => {
Modal.confirm({
title: `确认${record.status === Status.已禁用 ? '启用' : '禁用'}`,
content: (
<>
确认{record.status === Status.已禁用 ? '启用' : '禁用'}
Cookie{' '}
<Text style={{ wordBreak: 'break-all' }} type="warning">
{record.value}
</Text>{' '}
吗
</>
),
onOk() {
request
.put(
`${config.apiPrefix}cookies/${
record.status === Status.已禁用 ? 'enable' : 'disable'
}`,
{
data: [record._id],
},
)
.then((data: any) => {
if (data.code === 200) {
message.success(
`${record.status === Status.已禁用 ? '启用' : '禁用'}成功`,
);
const newStatus =
record.status === Status.已禁用 ? Status.未获取 : Status.已禁用;
const result = [...value];
result.splice(index, 1, {
...record,
status: newStatus,
});
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const addCookie = () => {
setEditedCookie(null as any);
setIsModalVisible(true);
};
const editCookie = (record: any, index: number) => {
setEditedCookie(record);
setIsModalVisible(true);
};
const deleteCookie = (record: any, index: number) => {
Modal.confirm({
title: '确认删除',
content: (
<>
确认删除Cookie{' '}
<Text style={{ wordBreak: 'break-all' }} type="warning">
{record.value}
</Text>{' '}
吗
</>
),
onOk() {
request
.delete(`${config.apiPrefix}cookies`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
message.success('删除成功');
const result = [...value];
result.splice(index, 1);
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const handleCancel = (cookies?: any[]) => {
setIsModalVisible(false);
if (cookies && cookies.length > 0) {
handleCookies(cookies);
}
};
const handleCookies = (cookies: any[]) => {
const result = [...value];
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const index = value.findIndex((x) => x._id === cookie._id);
if (index === -1) {
result.push(cookie);
} else {
result.splice(index, 1, {
...cookie,
});
}
}
setValue(result);
};
const components = {
body: {
row: DragableBodyRow,
},
};
const moveRow = useCallback(
(dragIndex, hoverIndex) => {
if (dragIndex === hoverIndex) {
return;
}
const dragRow = value[dragIndex];
const newData = [...value];
newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, dragRow);
setValue([...newData]);
request
.put(`${config.apiPrefix}cookies/${dragRow._id}/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex },
})
.then((data: any) => {
if (data.code !== 200) {
message.error(data);
}
});
},
[value],
);
const onSelectChange = (selectedIds: any[]) => {
setSelectedRowIds(selectedIds);
};
const rowSelection = {
selectedRowIds,
onChange: onSelectChange,
};
const delCookies = () => {
Modal.confirm({
title: '确认删除',
content: <>确认删除选中的Cookie吗</>,
onOk() {
request
.delete(`${config.apiPrefix}cookies`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
message.success('批量删除成功');
setSelectedRowIds([]);
getCookies();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const operateCookies = (operationStatus: number) => {
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>确认{OperationName[operationStatus]}选中的Cookie吗</>,
onOk() {
request
.put(`${config.apiPrefix}cookies/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
getCookies();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
useEffect(() => {
if (document.body.clientWidth < 768) {
setWidth('auto');
setMarginLeft(0);
setMarginTop(0);
} else {
setWidth('100%');
setMarginLeft(0);
setMarginTop(-72);
}
getCookies();
}, []);
return (
<PageContainer
className="session-wrapper"
title="Session管理"
extra={[
<Button key="2" type="primary" onClick={() => addCookie()}>
添加Cookie
</Button>,
]}
header={{
style: {
padding: '4px 16px 4px 15px',
position: 'sticky',
top: 0,
left: 0,
zIndex: 20,
marginTop,
width,
marginLeft,
},
}}
>
{selectedRowIds.length > 0 && (
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
style={{ marginBottom: 5 }}
onClick={delCookies}
>
批量删除
</Button>
<Button
type="primary"
onClick={() => operateCookies(0)}
style={{ marginLeft: 8, marginBottom: 5 }}
>
批量启用
</Button>
<Button
type="primary"
onClick={() => operateCookies(1)}
style={{ marginLeft: 8, marginRight: 8 }}
>
批量禁用
</Button>
<span style={{ marginLeft: 8 }}>
已选择
<a>{selectedRowIds?.length}</a>项
</span>
</div>
)}
<DndProvider backend={HTML5Backend}>
<Table
columns={columns}
rowSelection={rowSelection}
pagination={false}
dataSource={value}
rowKey="_id"
size="middle"
scroll={{ x: 768 }}
components={components}
loading={loading}
onRow={(record, index) => {
return {
index,
moveRow,
} as any;
}}
/>
</DndProvider>
<CookieModal
visible={isModalVisible}
handleCancel={handleCancel}
cookie={editedCookie}
/>
</PageContainer>
);
}