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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
// 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}