This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new b3aa4b3f2 feat(config-ui): use new table component to replace old 
(#6405)
b3aa4b3f2 is described below

commit b3aa4b3f2571e6cdee1dd5705f962c0a29f61658
Author: 青湛 <[email protected]>
AuthorDate: Wed Nov 15 19:19:55 2023 +1300

    feat(config-ui): use new table component to replace old (#6405)
    
    * refactor(config-ui): remove component table
    
    * refactor(config-ui): use antd table component to replace old
    
    * fix(config-ui): adjust the table component
---
 config-ui/src/components/index.ts                  |   1 -
 .../src/components/table/components/content.tsx    |  95 -----------------
 config-ui/src/components/table/components/index.ts |  21 ----
 .../src/components/table/components/loading.tsx    |  27 -----
 .../src/components/table/components/no-data.tsx    |  42 --------
 config-ui/src/components/table/hooks/index.ts      |  19 ----
 .../components/table/hooks/use-row-selection.ts    |  93 -----------------
 config-ui/src/components/table/index.ts            |  20 ----
 config-ui/src/components/table/styled.ts           |  55 ----------
 config-ui/src/components/table/table.tsx           |  56 -----------
 config-ui/src/components/table/types.ts            |  27 -----
 .../pages/blueprint/connection-detail/index.tsx    |   8 +-
 .../pages/blueprint/detail/configuration-panel.tsx |   7 +-
 config-ui/src/pages/blueprint/home/index.tsx       |  32 ++----
 config-ui/src/pages/connection/detail/index.tsx    |  16 ++-
 config-ui/src/pages/project/home/index.tsx         |  23 ++---
 .../plugins/components/connection-list/index.tsx   |  12 +--
 .../components/scope-config-select/index.tsx       |   7 +-
 .../src/plugins/register/webhook/connection.tsx    |  77 +++++++-------
 config-ui/src/routes/api-keys/api-keys.tsx         |  10 +-
 config-ui/src/routes/layout/styled.ts              |   2 -
 config-ui/src/routes/pipeline/components/table.tsx | 112 ++++++++++-----------
 22 files changed, 141 insertions(+), 621 deletions(-)

diff --git a/config-ui/src/components/index.ts 
b/config-ui/src/components/index.ts
index f039fc6f9..e67e2ac14 100644
--- a/config-ui/src/components/index.ts
+++ b/config-ui/src/components/index.ts
@@ -31,6 +31,5 @@ export * from './no-data';
 export * from './page-header';
 export * from './pagination';
 export * from './selector';
-export * from './table';
 export * from './toast';
 export * from './tooltip';
diff --git a/config-ui/src/components/table/components/content.tsx 
b/config-ui/src/components/table/components/content.tsx
deleted file mode 100644
index a77a283cf..000000000
--- a/config-ui/src/components/table/components/content.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { Checkbox, Radio } from '@blueprintjs/core';
-
-import { TextTooltip } from '@/components';
-
-import { ColumnType } from '../types';
-import { useRowSelection, UseRowSelectionProps } from '../hooks';
-import * as S from '../styled';
-
-export interface TableContentProps<T> extends UseRowSelectionProps<T> {
-  columns: ColumnType<T>;
-  dataSource: T[];
-  noShadow?: boolean;
-}
-
-export const TableContent = <T extends Record<string, any>>({
-  columns,
-  dataSource,
-  noShadow,
-  rowSelection,
-}: TableContentProps<T>) => {
-  const { canSelection, selectionType, getCheckedAll, onCheckedAll, 
getChecked, onChecked } = useRowSelection<T>({
-    dataSource,
-    rowSelection,
-  });
-
-  return (
-    <S.Table
-      style={{
-        boxShadow: noShadow ? 'none' : '0px 2.4px 4.8px -0.8px rgba(0, 0, 0, 
0.1), 0px 1.6px 8px rgba(0, 0, 0, 0.07)',
-      }}
-    >
-      <S.THeader>
-        <S.TR>
-          {canSelection && (
-            <S.TH style={{ width: 40, textAlign: 'center' }}>
-              {selectionType === 'checkbox' && <Checkbox 
checked={getCheckedAll()} onChange={() => onCheckedAll()} />}
-            </S.TH>
-          )}
-          {columns.map(({ key, width, align = 'left', title }) => (
-            <S.TH key={key} style={{ width, textAlign: align }}>
-              {title}
-            </S.TH>
-          ))}
-        </S.TR>
-      </S.THeader>
-      <S.TBody>
-        {dataSource.map((data, i) => (
-          <S.TR key={i}>
-            {canSelection && (
-              <S.TD style={{ width: 40, textAlign: 'center' }}>
-                {selectionType === 'checkbox' && (
-                  <Checkbox checked={getChecked(data)} onChange={() => 
onChecked(data)} />
-                )}
-                {selectionType === 'radio' && <Radio 
checked={getChecked(data)} onChange={() => onChecked(data)} />}
-              </S.TD>
-            )}
-            {columns.map(({ key, width, align = 'left', ellipsis, dataIndex, 
render }) => {
-              const value = !dataIndex
-                ? null
-                : Array.isArray(dataIndex)
-                ? dataIndex.reduce((acc, cur) => {
-                    acc[cur] = data[cur];
-                    return acc;
-                  }, {} as any)
-                : data[dataIndex];
-              return (
-                <S.TD key={key} style={{ width, textAlign: align }}>
-                  {render ? render(value, data) : ellipsis ? <TextTooltip 
content={value}>{value}</TextTooltip> : value}
-                </S.TD>
-              );
-            })}
-          </S.TR>
-        ))}
-      </S.TBody>
-    </S.Table>
-  );
-};
diff --git a/config-ui/src/components/table/components/index.ts 
b/config-ui/src/components/table/components/index.ts
deleted file mode 100644
index df5950d7f..000000000
--- a/config-ui/src/components/table/components/index.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-export * from './loading';
-export * from './no-data';
-export * from './content';
diff --git a/config-ui/src/components/table/components/loading.tsx 
b/config-ui/src/components/table/components/loading.tsx
deleted file mode 100644
index c0d73a28b..000000000
--- a/config-ui/src/components/table/components/loading.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { Card, PageLoading } from '@/components';
-
-export const TableLoading = () => {
-  return (
-    <Card>
-      <PageLoading />
-    </Card>
-  );
-};
diff --git a/config-ui/src/components/table/components/no-data.tsx 
b/config-ui/src/components/table/components/no-data.tsx
deleted file mode 100644
index 6dbe94070..000000000
--- a/config-ui/src/components/table/components/no-data.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { Button, Intent } from '@blueprintjs/core';
-
-import { NoData } from '@/components';
-
-interface Props {
-  text?: React.ReactNode;
-  btnText?: string;
-  onCreate?: () => void;
-}
-
-export const TableNoData = ({ text, btnText, onCreate }: Props) => {
-  return (
-    <NoData
-      text={text}
-      action={
-        onCreate && (
-          <Button intent={Intent.PRIMARY} icon="plus" onClick={onCreate}>
-            {btnText ?? 'Create'}
-          </Button>
-        )
-      }
-    />
-  );
-};
diff --git a/config-ui/src/components/table/hooks/index.ts 
b/config-ui/src/components/table/hooks/index.ts
deleted file mode 100644
index 97fc28721..000000000
--- a/config-ui/src/components/table/hooks/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-export * from './use-row-selection';
diff --git a/config-ui/src/components/table/hooks/use-row-selection.ts 
b/config-ui/src/components/table/hooks/use-row-selection.ts
deleted file mode 100644
index 5342811f8..000000000
--- a/config-ui/src/components/table/hooks/use-row-selection.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { useState, useEffect, useMemo } from 'react';
-
-export interface UseRowSelectionProps<T> {
-  dataSource: T[];
-  rowSelection?: {
-    rowKey?: ID;
-    getRowKey?: (data: T) => ID;
-    type?: 'checkbox' | 'radio';
-    selectedRowKeys?: ID[];
-    onChange?: (selectedRowKeys: ID[]) => void;
-  };
-}
-
-export const useRowSelection = <T>({ dataSource, rowSelection }: 
UseRowSelectionProps<T>) => {
-  const [selectedKeys, setSelectedKeys] = useState<ID[]>([]);
-
-  const {
-    rowKey = 'id',
-    getRowKey = (data: T) => (data as any)[rowKey],
-    type = 'checkbox',
-    selectedRowKeys,
-    onChange,
-  } = {
-    rowKey: 'id',
-    type: 'checkbox',
-    ...rowSelection,
-  };
-
-  useEffect(() => {
-    setSelectedKeys(selectedRowKeys ?? []);
-  }, [selectedRowKeys]);
-
-  const handleChecked = (data: T) => {
-    const key = getRowKey(data);
-    let result: ID[] = selectedKeys;
-
-    switch (true) {
-      case !selectedKeys.includes(key) && type === 'radio':
-        result = [key];
-        break;
-      case !selectedKeys.includes(key) && type === 'checkbox':
-        result = [...selectedKeys, key];
-        break;
-      case selectedKeys.includes(key) && type === 'checkbox':
-        result = selectedKeys.filter((k) => k !== key);
-        break;
-    }
-
-    onChange ? onChange(result) : setSelectedKeys(result);
-  };
-
-  const handleCheckedAll = () => {
-    let result: string[] = [];
-
-    if (selectedKeys.length !== dataSource.length) {
-      result = dataSource.map(getRowKey);
-    }
-
-    onChange ? onChange(result) : setSelectedKeys(result);
-  };
-
-  return useMemo(
-    () => ({
-      canSelection: !!rowSelection,
-      selectionType: type,
-      getCheckedAll: () => dataSource.length === selectedKeys.length,
-      onCheckedAll: handleCheckedAll,
-      getChecked: (data: T) => {
-        return selectedKeys.includes(getRowKey(data));
-      },
-      onChecked: handleChecked,
-    }),
-    [selectedKeys],
-  );
-};
diff --git a/config-ui/src/components/table/index.ts 
b/config-ui/src/components/table/index.ts
deleted file mode 100644
index 9ede1edc4..000000000
--- a/config-ui/src/components/table/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-export * from './table';
-export * from './types';
diff --git a/config-ui/src/components/table/styled.ts 
b/config-ui/src/components/table/styled.ts
deleted file mode 100644
index 58d093623..000000000
--- a/config-ui/src/components/table/styled.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import styled from 'styled-components';
-
-export const Table = styled.table`
-  table-layout: fixed;
-  width: 100%;
-  background-color: #fff;
-  border-radius: 4px;
-  border-spacing: 0;
-`;
-
-export const THeader = styled.thead`
-  background-color: #f0f4fe;
-`;
-
-export const TBody = styled.tbody``;
-
-export const TR = styled.tr``;
-
-export const TH = styled.th`
-  padding: 12px 16px;
-  font-weight: 400;
-  border-bottom: 1px solid #dbdcdf;
-
-  label.bp5-control {
-    margin-bottom: 0;
-  }
-`;
-
-export const TD = styled.td`
-  padding: 12px 16px;
-  border-bottom: 1px solid #dbdcdf;
-  word-break: break-word;
-
-  label.bp5-control {
-    margin-bottom: 0;
-  }
-`;
diff --git a/config-ui/src/components/table/table.tsx 
b/config-ui/src/components/table/table.tsx
deleted file mode 100644
index b55b6021b..000000000
--- a/config-ui/src/components/table/table.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import type { PaginationProps } from '../pagination';
-import { Pagination } from '../pagination';
-
-import type { TableContentProps } from './components';
-import { TableLoading, TableNoData, TableContent } from './components';
-
-interface Props<T> extends TableContentProps<T> {
-  loading?: boolean;
-  noData?: {
-    text?: React.ReactNode;
-    btnText?: string;
-    onCreate?: () => void;
-  };
-  pagination?: PaginationProps;
-}
-
-export const Table = <T extends Record<string, any>>({
-  loading,
-  dataSource,
-  noData = {},
-  pagination,
-  ...props
-}: Props<T>) => {
-  if (loading) {
-    return <TableLoading />;
-  }
-
-  if (!dataSource.length) {
-    return <TableNoData {...noData} />;
-  }
-
-  return (
-    <>
-      <TableContent dataSource={dataSource} {...props} />
-      {pagination && <Pagination {...pagination} />}
-    </>
-  );
-};
diff --git a/config-ui/src/components/table/types.ts 
b/config-ui/src/components/table/types.ts
deleted file mode 100644
index 44d282912..000000000
--- a/config-ui/src/components/table/types.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-export type ColumnType<T> = Array<{
-  title: string;
-  dataIndex?: string | string[];
-  key: string;
-  width?: number;
-  align?: 'left' | 'center' | 'right';
-  ellipsis?: boolean;
-  render?: (value: any, row: T) => React.ReactNode;
-}>;
diff --git a/config-ui/src/pages/blueprint/connection-detail/index.tsx 
b/config-ui/src/pages/blueprint/connection-detail/index.tsx
index 478af373a..6b821702f 100644
--- a/config-ui/src/pages/blueprint/connection-detail/index.tsx
+++ b/config-ui/src/pages/blueprint/connection-detail/index.tsx
@@ -18,11 +18,12 @@
 
 import { useState } from 'react';
 import { useNavigate, useParams } from 'react-router-dom';
+import { Table } from 'antd';
 import { Button, Intent, Position } from '@blueprintjs/core';
 import { Popover2 } from '@blueprintjs/popover2';
 
 import API from '@/api';
-import { PageLoading, PageHeader, ExternalLink, Message, Buttons, Table, 
Dialog } from '@/components';
+import { PageLoading, PageHeader, ExternalLink, Message, Buttons, Dialog } 
from '@/components';
 import { useRefreshData, useTips } from '@/hooks';
 import { DataScopeSelect, getPluginConfig, getPluginScopeId } from '@/plugins';
 import { operator } from '@/utils';
@@ -215,6 +216,8 @@ export const BlueprintConnectionDetailPage = () => {
         )}
       </Buttons>
       <Table
+        rowKey="id"
+        size="middle"
         columns={[
           {
             title: 'Data Scope',
@@ -223,9 +226,8 @@ export const BlueprintConnectionDetailPage = () => {
           },
           {
             title: 'Scope Config',
-            dataIndex: ['scopeConfigId', 'scopeConfigName'],
             key: 'scopeConfig',
-            render: ({ scopeConfigId, scopeConfigName }) => (scopeConfigId ? 
scopeConfigName : 'N/A'),
+            render: (_, { scopeConfigId, scopeConfigName }) => (scopeConfigId 
? scopeConfigName : 'N/A'),
           },
         ]}
         dataSource={scopes}
diff --git a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx 
b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
index cd7848f4c..1dddb6069 100644
--- a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
+++ b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
@@ -18,10 +18,11 @@
 
 import { useState, useEffect, useMemo } from 'react';
 import { Link } from 'react-router-dom';
+import { Table } from 'antd';
 import { Button, Intent } from '@blueprintjs/core';
 
 import API from '@/api';
-import { IconButton, Table, NoData, Buttons } from '@/components';
+import { IconButton, NoData, Buttons } from '@/components';
 import { getCron } from '@/config';
 import { ConnectionName } from '@/features';
 import { getPluginConfig } from '@/plugins';
@@ -134,6 +135,8 @@ export const ConfigurationPanel = ({ from, blueprint, 
onRefresh, onChangeTab }:
           <IconButton icon="annotation" tooltip="Edit" 
onClick={handleShowPolicyDialog} />
         </h3>
         <Table
+          rowKey="id"
+          size="middle"
           columns={[
             {
               title: 'Data Time Range',
@@ -161,12 +164,14 @@ export const ConfigurationPanel = ({ from, blueprint, 
onRefresh, onChangeTab }:
           ]}
           dataSource={[
             {
+              id: blueprint.id,
               timeRange: blueprint.timeAfter,
               frequency: blueprint.cronConfig,
               isManual: blueprint.isManual,
               skipFailed: blueprint.skipOnFail,
             },
           ]}
+          pagination={false}
         />
       </div>
       {blueprint.mode === IBPMode.NORMAL && (
diff --git a/config-ui/src/pages/blueprint/home/index.tsx 
b/config-ui/src/pages/blueprint/home/index.tsx
index 8f65246f0..5d8fb0b37 100644
--- a/config-ui/src/pages/blueprint/home/index.tsx
+++ b/config-ui/src/pages/blueprint/home/index.tsx
@@ -18,11 +18,12 @@
 
 import { useState, useMemo } from 'react';
 import { Link } from 'react-router-dom';
+import { Table } from 'antd';
 import { ButtonGroup, Button, Tag, Intent, FormGroup, InputGroup, RadioGroup, 
Radio } from '@blueprintjs/core';
 import dayjs from 'dayjs';
 
 import API from '@/api';
-import { PageHeader, Table, IconButton, TextTooltip, Dialog } from 
'@/components';
+import { PageHeader, IconButton, TextTooltip, Dialog } from '@/components';
 import { getCronOptions, cronPresets, getCron } from '@/config';
 import { ConnectionName } from '@/features';
 import { useRefreshData } from '@/hooks';
@@ -111,13 +112,14 @@ export const BlueprintHomePage = () => {
           <Button icon="plus" intent={Intent.PRIMARY} text="New Blueprint" 
onClick={handleShowDialog} />
         </div>
         <Table
+          rowKey="id"
+          size="middle"
           loading={!ready}
           columns={[
             {
               title: 'Blueprint Name',
-              dataIndex: ['id', 'name'],
               key: 'name',
-              render: ({ id, name }) => (
+              render: (_, { id, name }) => (
                 <Link to={`/blueprints/${id}?tab=configuration`} style={{ 
color: '#292b3f' }}>
                   <TextTooltip content={name}>{name}</TextTooltip>
                 </Link>
@@ -125,21 +127,16 @@ export const BlueprintHomePage = () => {
             },
             {
               title: 'Data Connections',
-              dataIndex: ['mode', 'connections'],
               key: 'connections',
-              render: ({ mode, connections }: Pick<IBlueprint, 'mode' | 
'connections'>) => {
+              render: (_, { mode, connections }: Pick<IBlueprint, 'mode' | 
'connections'>) => {
                 if (mode === IBPMode.ADVANCED) {
                   return 'Advanced Mode';
                 }
                 return (
                   <S.ConnectionList>
                     {connections.map((it) => (
-                      <li>
-                        <ConnectionName
-                          key={`${it.pluginName}-${it.connectionId}`}
-                          plugin={it.pluginName}
-                          connectionId={it.connectionId}
-                        />
+                      <li key={`${it.pluginName}-${it.connectionId}`}>
+                        <ConnectionName plugin={it.pluginName} 
connectionId={it.connectionId} />
                       </li>
                     ))}
                   </S.ConnectionList>
@@ -148,20 +145,18 @@ export const BlueprintHomePage = () => {
             },
             {
               title: 'Frequency',
-              dataIndex: ['isManual', 'cronConfig'],
               key: 'frequency',
               width: 100,
-              render: ({ isManual, cronConfig }) => {
+              render: (_, { isManual, cronConfig }) => {
                 const cron = getCron(isManual, cronConfig);
                 return cron.label;
               },
             },
             {
               title: 'Next Run Time',
-              dataIndex: ['isManual', 'cronConfig'],
               key: 'nextRunTime',
               width: 200,
-              render: ({ isManual, cronConfig }) => {
+              render: (_, { isManual, cronConfig }) => {
                 const cron = getCron(isManual, cronConfig);
                 return formatTime(cron.nextTime);
               },
@@ -206,16 +201,11 @@ export const BlueprintHomePage = () => {
           ]}
           dataSource={dataSource}
           pagination={{
-            page,
+            current: page,
             pageSize,
             total,
             onChange: setPage,
           }}
-          noData={{
-            text: 'There is no Blueprint yet. Please add a new Blueprint here 
or from a Project.',
-            btnText: 'New Blueprint',
-            onCreate: handleShowDialog,
-          }}
         />
       </S.Wrapper>
       <Dialog
diff --git a/config-ui/src/pages/connection/detail/index.tsx 
b/config-ui/src/pages/connection/detail/index.tsx
index da9d7c56c..3a25e18ec 100644
--- a/config-ui/src/pages/connection/detail/index.tsx
+++ b/config-ui/src/pages/connection/detail/index.tsx
@@ -18,11 +18,12 @@
 
 import { useState, useMemo } from 'react';
 import { useParams, useNavigate, Link } from 'react-router-dom';
+import { Table } from 'antd';
 import { Button, Intent } from '@blueprintjs/core';
 
 import API from '@/api';
 import { useAppDispatch, useAppSelector } from '@/app/hook';
-import { PageHeader, Buttons, Dialog, IconButton, Table, Message, toast } from 
'@/components';
+import { PageHeader, Buttons, Dialog, IconButton, Message, toast } from 
'@/components';
 import { selectConnection, removeConnection } from '@/features';
 import { useTips, useRefreshData } from '@/hooks';
 import ClearImg from '@/images/icons/clear.svg';
@@ -265,6 +266,8 @@ export const ConnectionDetailPage = () => {
           )}
         </Buttons>
         <Table
+          rowKey="id"
+          size="middle"
           loading={!ready}
           columns={[
             {
@@ -294,10 +297,9 @@ export const ConnectionDetailPage = () => {
             },
             {
               title: 'Scope Config',
-              dataIndex: ['id', 'configId', 'configName'],
               key: 'scopeConfig',
               width: 400,
-              render: ({ id, configId, configName }) => (
+              render: (_, { id, configId, configName }) => (
                 <>
                   <span>{configId ? configName : 'N/A'}</span>
                   {pluginConfig.scopeConfig && (
@@ -336,18 +338,12 @@ export const ConnectionDetailPage = () => {
           ]}
           dataSource={dataSource}
           pagination={{
-            page,
+            current: page,
             pageSize,
             total,
             onChange: setPage,
           }}
-          noData={{
-            text: 'Add data to this connection.',
-            btnText: 'Add Data Scope',
-            onCreate: handleShowCreateDataScopeDialog,
-          }}
           rowSelection={{
-            getRowKey: (row) => row.id,
             selectedRowKeys: scopeIds,
             onChange: (selectedRowKeys) => setScopeIds(selectedRowKeys),
           }}
diff --git a/config-ui/src/pages/project/home/index.tsx 
b/config-ui/src/pages/project/home/index.tsx
index 5f1e2f06a..81ffa6b65 100644
--- a/config-ui/src/pages/project/home/index.tsx
+++ b/config-ui/src/pages/project/home/index.tsx
@@ -18,11 +18,12 @@
 
 import { useState, useMemo } from 'react';
 import { Link, useNavigate } from 'react-router-dom';
+import { Table } from 'antd';
 import { Button, InputGroup, Checkbox, Intent, FormGroup } from 
'@blueprintjs/core';
 import dayjs from 'dayjs';
 
 import API from '@/api';
-import { PageHeader, Table, Dialog, ExternalLink, IconButton, toast } from 
'@/components';
+import { PageHeader, Dialog, ExternalLink, IconButton, toast } from 
'@/components';
 import { getCron, cronPresets } from '@/config';
 import { ConnectionName } from '@/features';
 import { useRefreshData } from '@/hooks';
@@ -122,6 +123,8 @@ export const ProjectHomePage = () => {
       extra={<Button intent={Intent.PRIMARY} icon="plus" text="New Project" 
onClick={handleShowDialog} />}
     >
       <Table
+        rowKey="name"
+        size="middle"
         loading={!ready}
         columns={[
           {
@@ -144,12 +147,8 @@ export const ProjectHomePage = () => {
               ) : (
                 <S.ConnectionList>
                   {val.map((it) => (
-                    <li>
-                      <ConnectionName
-                        key={`${it.pluginName}-${it.connectionId}`}
-                        plugin={it.pluginName}
-                        connectionId={it.connectionId}
-                      />
+                    <li key={`${it.pluginName}-${it.connectionId}`}>
+                      <ConnectionName plugin={it.pluginName} 
connectionId={it.connectionId} />
                     </li>
                   ))}
                 </S.ConnectionList>
@@ -157,9 +156,8 @@ export const ProjectHomePage = () => {
           },
           {
             title: 'Sync Frequency',
-            dataIndex: ['isManual', 'cronConfig'],
             key: 'frequency',
-            render: ({ isManual, cronConfig }) => {
+            render: (_, { isManual, cronConfig }) => {
               const cron = getCron(isManual, cronConfig);
               return cron.label;
             },
@@ -199,16 +197,11 @@ export const ProjectHomePage = () => {
         ]}
         dataSource={dataSource}
         pagination={{
-          page,
+          current: page,
           pageSize,
           total,
           onChange: setPage,
         }}
-        noData={{
-          text: 'Add new projects to see engineering metrics based on 
projects.',
-          btnText: 'New Project',
-          onCreate: handleShowDialog,
-        }}
       />
       <Dialog
         isOpen={isOpen}
diff --git a/config-ui/src/plugins/components/connection-list/index.tsx 
b/config-ui/src/plugins/components/connection-list/index.tsx
index d113c1788..65cb33c76 100644
--- a/config-ui/src/plugins/components/connection-list/index.tsx
+++ b/config-ui/src/plugins/components/connection-list/index.tsx
@@ -17,10 +17,10 @@
  */
 
 import { Link } from 'react-router-dom';
+import { Table } from 'antd';
 import { Button, Intent } from '@blueprintjs/core';
 
 import { useAppSelector } from '@/app/hook';
-import { Table } from '@/components';
 import { selectConnections } from '@/features/connections';
 import { ConnectionStatus } from '@/plugins';
 
@@ -41,7 +41,8 @@ export const ConnectionList = ({ plugin, onCreate }: Props) 
=> {
   return (
     <>
       <Table
-        noShadow
+        rowKey="id"
+        size="small"
         columns={[
           {
             title: 'Connection Name',
@@ -56,16 +57,13 @@ export const ConnectionList = ({ plugin, onCreate }: Props) 
=> {
           },
           {
             title: '',
-            dataIndex: ['plugin', 'id'],
             key: 'link',
             width: 100,
-            render: ({ plugin, id }) => <Link 
to={`/connections/${plugin}/${id}`}>Details</Link>,
+            render: (_, { plugin, id }) => <Link 
to={`/connections/${plugin}/${id}`}>Details</Link>,
           },
         ]}
         dataSource={connections}
-        noData={{
-          text: 'There is no data connection yet. Please add a new 
connection.',
-        }}
+        pagination={false}
       />
       <Button
         style={{ marginTop: 16 }}
diff --git a/config-ui/src/plugins/components/scope-config-select/index.tsx 
b/config-ui/src/plugins/components/scope-config-select/index.tsx
index 9329aa0bb..88492e4d4 100644
--- a/config-ui/src/plugins/components/scope-config-select/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-select/index.tsx
@@ -17,10 +17,11 @@
  */
 
 import { useState, useEffect, useMemo } from 'react';
+import { Table } from 'antd';
 import { Button, Intent } from '@blueprintjs/core';
 
 import API from '@/api';
-import { Buttons, Table, IconButton, Dialog } from '@/components';
+import { Buttons, IconButton, Dialog } from '@/components';
 import { useRefreshData } from '@/hooks';
 
 import { ScopeConfigForm } from '../scope-config-form';
@@ -75,6 +76,8 @@ export const ScopeConfigSelect = ({ plugin, connectionId, 
scopeConfigId, onCance
         <Button icon="add" intent={Intent.PRIMARY} text="Add New Scope Config" 
onClick={handleShowDialog} />
       </Buttons>
       <Table
+        rowKey="id"
+        size="small"
         loading={!ready}
         columns={[
           { title: 'Name', dataIndex: 'name', key: 'name' },
@@ -92,7 +95,7 @@ export const ScopeConfigSelect = ({ plugin, connectionId, 
scopeConfigId, onCance
           selectedRowKeys: trId ? [trId] : [],
           onChange: (selectedRowKeys) => setTrId(selectedRowKeys[0]),
         }}
-        noShadow
+        pagination={false}
       />
       <Buttons position="bottom" align="right">
         <Button outlined intent={Intent.PRIMARY} text="Cancel" 
onClick={onCancel} />
diff --git a/config-ui/src/plugins/register/webhook/connection.tsx 
b/config-ui/src/plugins/register/webhook/connection.tsx
index cdb8660e4..0a7d83352 100644
--- a/config-ui/src/plugins/register/webhook/connection.tsx
+++ b/config-ui/src/plugins/register/webhook/connection.tsx
@@ -17,12 +17,12 @@
  */
 
 import { useState } from 'react';
+import { Table } from 'antd';
 import { Button, Intent } from '@blueprintjs/core';
 
 import { useAppSelector } from '@/app/hook';
-import { Buttons, Table, ColumnType, ExternalLink, IconButton } from 
'@/components';
+import { Buttons, IconButton } from '@/components';
 import { selectWebhooks } from '@/features/connections';
-import { DOC_URL } from '@/release';
 import { IWebhook } from '@/types';
 
 import { CreateDialog, ViewDialog, EditDialog, DeleteDialog } from 
'./components';
@@ -53,52 +53,43 @@ export const WebHookConnection = ({ filterIds, 
onCreateAfter, onDeleteAfter }: P
     setCurrentID(r?.id);
   };
 
-  const columns: ColumnType<IWebhook> = [
-    {
-      title: 'ID',
-      dataIndex: 'id',
-      key: 'id',
-    },
-    {
-      title: 'Webhook Name',
-      dataIndex: 'name',
-      key: 'name',
-      render: (name, row) => <span onClick={() => handleShowDialog('show', 
row)}>{name}</span>,
-    },
-    {
-      title: '',
-      dataIndex: '',
-      key: 'action',
-      align: 'center',
-      render: (_, row) => (
-        <S.Action>
-          <IconButton icon="eye-open" tooltip="View" onClick={() => 
handleShowDialog('show', row)} />
-          <IconButton icon="annotation" tooltip="Edit" onClick={() => 
handleShowDialog('edit', row)} />
-          <IconButton icon="trash" tooltip="Delete" onClick={() => 
handleShowDialog('delete', row)} />
-        </S.Action>
-      ),
-    },
-  ];
-
   return (
     <S.Wrapper>
-      <Buttons position="top">
-        <Button icon="plus" text="Add a Webhook" intent={Intent.PRIMARY} 
onClick={() => handleShowDialog('add')} />
-      </Buttons>
       <Table
-        columns={columns}
+        rowKey="id"
+        size="middle"
+        columns={[
+          {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+          },
+          {
+            title: 'Webhook Name',
+            dataIndex: 'name',
+            key: 'name',
+            render: (name, row) => <span onClick={() => 
handleShowDialog('show', row)}>{name}</span>,
+          },
+          {
+            title: '',
+            dataIndex: '',
+            key: 'action',
+            align: 'center',
+            render: (_, row) => (
+              <S.Action>
+                <IconButton icon="eye-open" tooltip="View" onClick={() => 
handleShowDialog('show', row)} />
+                <IconButton icon="annotation" tooltip="Edit" onClick={() => 
handleShowDialog('edit', row)} />
+                <IconButton icon="trash" tooltip="Delete" onClick={() => 
handleShowDialog('delete', row)} />
+              </S.Action>
+            ),
+          },
+        ]}
         dataSource={webhooks.filter((cs) => (filterIds ? 
filterIds.includes(cs.id) : true))}
-        noData={{
-          text: (
-            <>
-              There is no Webhook yet. Please add a new Webhook.{' '}
-              <ExternalLink link={DOC_URL.PLUGIN.WEBHOOK.BASIS}>Learn 
more</ExternalLink>
-            </>
-          ),
-          btnText: 'Add a Webhook',
-          onCreate: () => handleShowDialog('add'),
-        }}
+        pagination={false}
       />
+      <Buttons position="bottom">
+        <Button icon="plus" text="Add a Webhook" intent={Intent.PRIMARY} 
onClick={() => handleShowDialog('add')} />
+      </Buttons>
       {type === 'add' && (
         <CreateDialog isOpen onCancel={handleHideDialog} onSubmitAfter={(id) 
=> onCreateAfter?.(id)} />
       )}
diff --git a/config-ui/src/routes/api-keys/api-keys.tsx 
b/config-ui/src/routes/api-keys/api-keys.tsx
index f2f9a4c4f..ef3acdcef 100644
--- a/config-ui/src/routes/api-keys/api-keys.tsx
+++ b/config-ui/src/routes/api-keys/api-keys.tsx
@@ -17,11 +17,12 @@
  */
 
 import { useState, useMemo } from 'react';
+import { Table } from 'antd';
 import { Button, Tag, Intent, InputGroup } from '@blueprintjs/core';
 import dayjs from 'dayjs';
 
 import API from '@/api';
-import { PageHeader, Table, Dialog, FormItem, Selector, ExternalLink, 
CopyText, Message } from '@/components';
+import { PageHeader, Dialog, FormItem, Selector, ExternalLink, CopyText, 
Message } from '@/components';
 import { useRefreshData } from '@/hooks';
 import { operator, formatTime } from '@/utils';
 
@@ -96,6 +97,8 @@ export const ApiKeys = () => {
     >
       <p>You can generate and manage your API keys to access the DevLake 
API.</p>
       <Table
+        rowKey="id"
+        size="middle"
         loading={!ready}
         columns={[
           {
@@ -142,14 +145,11 @@ export const ApiKeys = () => {
         ]}
         dataSource={dataSource}
         pagination={{
-          page,
+          current: page,
           pageSize,
           total,
           onChange: setPage,
         }}
-        noData={{
-          text: 'There is no API key yet.',
-        }}
       />
       {modal === 'create' && (
         <Dialog
diff --git a/config-ui/src/routes/layout/styled.ts 
b/config-ui/src/routes/layout/styled.ts
index b6726a7ad..e253d49be 100644
--- a/config-ui/src/routes/layout/styled.ts
+++ b/config-ui/src/routes/layout/styled.ts
@@ -22,7 +22,6 @@ import { Navbar } from '@blueprintjs/core';
 export const Wrapper = styled.div`
   display: flex;
   height: 100vh;
-  background-color: #f9f9fa;
   overflow: hidden;
 `;
 
@@ -89,7 +88,6 @@ export const Sider = styled.div`
 
 export const Header = styled(Navbar)`
   flex: 0 0 50px;
-  background-color: #f9f9fa;
   box-shadow: none;
 
   a {
diff --git a/config-ui/src/routes/pipeline/components/table.tsx 
b/config-ui/src/routes/pipeline/components/table.tsx
index 5ed8334d2..eb6c31233 100644
--- a/config-ui/src/routes/pipeline/components/table.tsx
+++ b/config-ui/src/routes/pipeline/components/table.tsx
@@ -16,14 +16,15 @@
  *
  */
 
-import { useState, useMemo } from 'react';
+import { useState } from 'react';
+import { Table } from 'antd';
 import { ButtonGroup } from '@blueprintjs/core';
 import { pick } from 'lodash';
 import { saveAs } from 'file-saver';
 
 import API from '@/api';
 import { DEVLAKE_ENDPOINT } from '@/config';
-import { Table, ColumnType, IconButton, Inspector, Dialog } from 
'@/components';
+import { IconButton, Inspector, Dialog } from '@/components';
 import { IPipeline } from '@/types';
 import { formatTime } from '@/utils';
 
@@ -66,62 +67,61 @@ export const PipelineTable = ({ dataSource, pagination, 
noData }: Props) => {
     setId(id);
   };
 
-  const columns = useMemo(
-    () =>
-      [
-        {
-          title: 'ID',
-          dataIndex: 'id',
-          key: 'id',
-        },
-        {
-          title: 'Status',
-          dataIndex: 'status',
-          key: 'status',
-          render: (val) => <PipelineStatus status={val} />,
-        },
-        {
-          title: 'Started at',
-          dataIndex: 'beganAt',
-          key: 'beganAt',
-          align: 'center',
-          render: (val) => formatTime(val),
-        },
-        {
-          title: 'Completed at',
-          dataIndex: 'finishedAt',
-          key: 'finishedAt',
-          align: 'center',
-          render: (val) => formatTime(val),
-        },
-        {
-          title: 'Duration',
-          dataIndex: ['status', 'beganAt', 'finishedAt'],
-          key: 'duration',
-          render: ({ status, beganAt, finishedAt }) => (
-            <PipelineDuration status={status} beganAt={beganAt} 
finishedAt={finishedAt} />
-          ),
-        },
-        {
-          title: '',
-          dataIndex: 'id',
-          key: 'action',
-          align: 'center',
-          render: (id: ID, row) => (
-            <ButtonGroup>
-              <IconButton icon="code" tooltip="View JSON" onClick={() => 
handleShowJSON(row)} />
-              <IconButton icon="document" tooltip="Download Logs" onClick={() 
=> handleDownloadLog(id)} />
-              <IconButton icon="chevron-right" tooltip="View Details" 
onClick={() => handleShowDetails(id)} />
-            </ButtonGroup>
-          ),
-        },
-      ] as ColumnType<IPipeline>,
-    [],
-  );
-
   return (
     <>
-      <Table columns={columns} dataSource={dataSource} pagination={pagination} 
noData={noData} />
+      <Table
+        rowKey="id"
+        size="middle"
+        columns={[
+          {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+          },
+          {
+            title: 'Status',
+            dataIndex: 'status',
+            key: 'status',
+            render: (val) => <PipelineStatus status={val} />,
+          },
+          {
+            title: 'Started at',
+            dataIndex: 'beganAt',
+            key: 'beganAt',
+            align: 'center',
+            render: (val) => formatTime(val),
+          },
+          {
+            title: 'Completed at',
+            dataIndex: 'finishedAt',
+            key: 'finishedAt',
+            align: 'center',
+            render: (val) => formatTime(val),
+          },
+          {
+            title: 'Duration',
+            key: 'duration',
+            render: (_, { status, beganAt, finishedAt }) => (
+              <PipelineDuration status={status} beganAt={beganAt} 
finishedAt={finishedAt} />
+            ),
+          },
+          {
+            title: '',
+            dataIndex: 'id',
+            key: 'action',
+            align: 'center',
+            render: (id: ID, row) => (
+              <ButtonGroup>
+                <IconButton icon="code" tooltip="View JSON" onClick={() => 
handleShowJSON(row)} />
+                <IconButton icon="document" tooltip="Download Logs" 
onClick={() => handleDownloadLog(id)} />
+                <IconButton icon="chevron-right" tooltip="View Details" 
onClick={() => handleShowDetails(id)} />
+              </ButtonGroup>
+            ),
+          },
+        ]}
+        dataSource={dataSource}
+        pagination={pagination}
+      />
       {JSON && <Inspector isOpen title={`Pipeline ${JSON?.id}`} data={JSON} 
onClose={() => setJSON(null)} />}
       {id && (
         <Dialog style={{ width: 820 }} isOpen title={`Pipeline ${id}`} 
footer={null} onCancel={() => setId(null)}>


Reply via email to