You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by mi...@apache.org on 2023/11/27 03:45:31 UTC

(incubator-devlake) branch feat-6447 created (now d4d275942)

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

mintsweet pushed a change to branch feat-6447
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


      at d4d275942 feat(config-ui): improve connection management usability

This branch includes the following new commits:

     new d4d275942 feat(config-ui): improve connection management usability

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(incubator-devlake) 01/01: feat(config-ui): improve connection management usability

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d4d2759421ca4e63f7d8ef1a7728cfc46db7b7a2
Author: mintsweet <0x...@gmail.com>
AuthorDate: Mon Nov 27 16:45:18 2023 +1300

    feat(config-ui): improve connection management usability
---
 config-ui/src/app/routrer.tsx                      |   5 +-
 config-ui/src/pages/connection/detail/styled.ts    |  61 ---
 config-ui/src/pages/connection/index.ts            |  19 -
 config-ui/src/pages/index.ts                       |   1 -
 .../plugins/components/connection-list/index.tsx   |  92 ++++-
 .../index.tsx => routes/connection/connection.tsx} | 429 +++++++++++----------
 config-ui/src/routes/connection/index.ts           |   1 +
 config-ui/src/routes/connection/styled.ts          |   1 +
 8 files changed, 301 insertions(+), 308 deletions(-)

diff --git a/config-ui/src/app/routrer.tsx b/config-ui/src/app/routrer.tsx
index f3bb7615a..587a83d9d 100644
--- a/config-ui/src/app/routrer.tsx
+++ b/config-ui/src/app/routrer.tsx
@@ -19,7 +19,6 @@
 import { createBrowserRouter, Navigate, json } from 'react-router-dom';
 
 import {
-  ConnectionDetailPage,
   ProjectHomePage,
   ProjectDetailPage,
   BlueprintHomePage,
@@ -28,7 +27,7 @@ import {
 } from '@/pages';
 import { Layout, loader as layoutLoader } from '@/routes/layout';
 import { Error, ErrorEnum } from '@/routes/error';
-import { Connections } from '@/routes/connection';
+import { Connections, Connection } from '@/routes/connection';
 import { Pipelines, Pipeline } from '@/routes/pipeline';
 import { ApiKeys } from '@/routes/api-keys';
 
@@ -57,7 +56,7 @@ export const router = createBrowserRouter([
       },
       {
         path: 'connections/:plugin/:id',
-        element: <ConnectionDetailPage />,
+        element: <Connection />,
       },
       {
         path: 'projects',
diff --git a/config-ui/src/pages/connection/detail/styled.ts b/config-ui/src/pages/connection/detail/styled.ts
deleted file mode 100644
index 92c580d12..000000000
--- a/config-ui/src/pages/connection/detail/styled.ts
+++ /dev/null
@@ -1,61 +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 PageHeaderExtra = styled.div`
-  display: flex;
-  align-items: center;
-`;
-
-export const Wrapper = styled.div`
-  .top {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    margin-bottom: 24px;
-  }
-
-  .authentication {
-    display: flex;
-    align-items: center;
-    justify-content: flex-end;
-  }
-`;
-
-export const DialogTitle = styled.div`
-  display: flex;
-  align-items: center;
-
-  img {
-    margin-right: 8px;
-    width: 24px;
-  }
-`;
-
-export const DialogBody = styled.div`
-  ul {
-    margin-top: 16px;
-    padding-left: 36px;
-
-    li {
-      margin-bottom: 4px;
-      color: #7497f7;
-    }
-  }
-`;
diff --git a/config-ui/src/pages/connection/index.ts b/config-ui/src/pages/connection/index.ts
deleted file mode 100644
index d30c832b9..000000000
--- a/config-ui/src/pages/connection/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 './detail';
diff --git a/config-ui/src/pages/index.ts b/config-ui/src/pages/index.ts
index 555e0869f..fe57695f0 100644
--- a/config-ui/src/pages/index.ts
+++ b/config-ui/src/pages/index.ts
@@ -17,5 +17,4 @@
  */
 
 export * from './blueprint';
-export * from './connection';
 export * from './project';
diff --git a/config-ui/src/plugins/components/connection-list/index.tsx b/config-ui/src/plugins/components/connection-list/index.tsx
index 65cb33c76..c1d1ecfd5 100644
--- a/config-ui/src/plugins/components/connection-list/index.tsx
+++ b/config-ui/src/plugins/components/connection-list/index.tsx
@@ -16,28 +16,66 @@
  *
  */
 
-import { Link } from 'react-router-dom';
-import { Table } from 'antd';
-import { Button, Intent } from '@blueprintjs/core';
+import { useState, useMemo } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { EyeOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
+import { theme, Table, Button, Modal } from 'antd';
+import styled from 'styled-components';
 
 import { useAppSelector } from '@/app/hook';
 import { selectConnections } from '@/features/connections';
-import { ConnectionStatus } from '@/plugins';
-
+import { getPluginConfig, ConnectionStatus, ConnectionForm } from '@/plugins';
 import { WebHookConnection } from '@/plugins/register/webhook';
 
+const ModalTitle = styled.div`
+  display: flex;
+  align-items: center;
+
+  .icon {
+    display: inline-flex;
+    margin-right: 8px;
+    width: 24px;
+
+    & > svg {
+      width: 100%;
+      height: 100%;
+    }
+  }
+`;
+
 interface Props {
   plugin: string;
   onCreate: () => void;
 }
 
 export const ConnectionList = ({ plugin, onCreate }: Props) => {
+  const [open, setOpen] = useState(false);
+  const [connectionId, setConnectionId] = useState<ID>();
+
+  const pluginConfig = useMemo(() => getPluginConfig(plugin), [plugin]);
+
+  const {
+    token: { colorPrimary },
+  } = theme.useToken();
+
   const connections = useAppSelector((state) => selectConnections(state, plugin));
 
+  const navigate = useNavigate();
+
   if (plugin === 'webhook') {
     return <WebHookConnection />;
   }
 
+  const handleShowForm = (id: ID) => {
+    setOpen(true);
+    setConnectionId(id);
+  };
+
+  const hanldeHideForm = () => {
+    setOpen(false);
+    setConnectionId(undefined);
+  };
+
   return (
     <>
       <Table
@@ -52,26 +90,50 @@ export const ConnectionList = ({ plugin, onCreate }: Props) => {
           {
             title: 'Status',
             key: 'status',
-            width: 150,
+            width: 200,
             render: (_, row) => <ConnectionStatus connection={row} />,
           },
           {
             title: '',
             key: 'link',
-            width: 100,
-            render: (_, { plugin, id }) => <Link to={`/connections/${plugin}/${id}`}>Details</Link>,
+            width: 200,
+            render: (_, { plugin, id }) => (
+              <>
+                <Button
+                  type="link"
+                  icon={<EyeOutlined rev={undefined} />}
+                  onClick={() => navigate(`/connections/${plugin}/${id}`)}
+                >
+                  Details
+                </Button>
+                <Button type="link" icon={<EditOutlined rev={undefined} />} onClick={() => handleShowForm(id)}>
+                  Edit
+                </Button>
+              </>
+            ),
           },
         ]}
         dataSource={connections}
         pagination={false}
       />
-      <Button
-        style={{ marginTop: 16 }}
-        intent={Intent.PRIMARY}
-        icon="add"
-        text="Create a New Connection"
-        onClick={onCreate}
-      />
+      <Button style={{ marginTop: 16 }} type="primary" icon={<PlusOutlined rev={undefined} />} onClick={onCreate}>
+        Create a New Connection
+      </Button>
+      <Modal
+        open={open}
+        width={820}
+        centered
+        title={
+          <ModalTitle>
+            <span className="icon">{pluginConfig.icon({ color: colorPrimary })}</span>
+            <span className="name">Manage Connections: {pluginConfig.name}</span>
+          </ModalTitle>
+        }
+        footer={null}
+        onCancel={hanldeHideForm}
+      >
+        <ConnectionForm plugin={plugin} connectionId={connectionId} onSuccess={hanldeHideForm} />
+      </Modal>
     </>
   );
 };
diff --git a/config-ui/src/pages/connection/detail/index.tsx b/config-ui/src/routes/connection/connection.tsx
similarity index 58%
rename from config-ui/src/pages/connection/detail/index.tsx
rename to config-ui/src/routes/connection/connection.tsx
index e96370d04..d04a20b00 100644
--- a/config-ui/src/pages/connection/detail/index.tsx
+++ b/config-ui/src/routes/connection/connection.tsx
@@ -18,17 +18,16 @@
 
 import { useState, useMemo } from 'react';
 import { useParams, useNavigate, Link } from 'react-router-dom';
-import { Table } from 'antd';
-import { Button, Intent } from '@blueprintjs/core';
+import { DeleteOutlined, PlusOutlined, NodeIndexOutlined } from '@ant-design/icons';
+import { theme, Table, Button, Modal, message } from 'antd';
 
 import API from '@/api';
 import { useAppDispatch, useAppSelector } from '@/app/hook';
-import { PageHeader, Buttons, Dialog, IconButton, Message, toast } from '@/components';
+import { PageHeader, IconButton, Message } from '@/components';
 import { selectConnection, removeConnection } from '@/features';
 import { useTips, useRefreshData } from '@/hooks';
 import ClearImg from '@/images/icons/clear.svg';
 import {
-  ConnectionForm,
   ConnectionStatus,
   DataScopeRemote,
   getPluginConfig,
@@ -41,10 +40,9 @@ import { operator } from '@/utils';
 
 import * as S from './styled';
 
-export const ConnectionDetailPage = () => {
+export const Connection = () => {
   const [type, setType] = useState<
     | 'deleteConnection'
-    | 'updateConnection'
     | 'createDataScope'
     | 'clearDataScope'
     | 'deleteDataScope'
@@ -65,6 +63,10 @@ export const ConnectionDetailPage = () => {
   const { plugin, id } = useParams() as { plugin: string; id: string };
   const connectionId = +id;
 
+  const {
+    token: { colorPrimary },
+  } = theme.useToken();
+
   const dispatch = useAppDispatch();
   const connection = useAppSelector((state) => selectConnection(state, `${plugin}-${connectionId}`)) as IConnection;
 
@@ -123,26 +125,18 @@ export const ConnectionDetailPage = () => {
     );
 
     if (res.status === 'success') {
-      toast.success('Delete Connection Successful.');
+      message.success('Delete Connection Successful.');
       navigate('/connections');
     } else if (res.status === 'conflict') {
       setType('deleteConnectionFailed');
       setConflict(res.conflict);
       setErrorMsg(res.message);
     } else {
-      toast.error('Operation failed.');
+      message.error('Operation failed.');
       handleHideDialog();
     }
   };
 
-  const handleShowUpdateDialog = () => {
-    setType('updateConnection');
-  };
-
-  const handleUpdate = () => {
-    handleHideDialog();
-  };
-
   const handleShowCreateDataScopeDialog = () => {
     setType('createDataScope');
   };
@@ -187,14 +181,14 @@ export const ConnectionDetailPage = () => {
 
     if (res.status === 'success') {
       setVersion((v) => v + 1);
-      toast.success(onlyData ? 'Clear historical data successful.' : 'Delete Data Scope successful.');
+      message.success(onlyData ? 'Clear historical data successful.' : 'Delete Data Scope successful.');
       handleHideDialog();
     } else if (res.status === 'conflict') {
       setType('deleteDataScopeFailed');
       setConflict(res.conflict);
       setErrorMsg(res.message);
     } else {
-      toast.error('Operation failed.');
+      message.error('Operation failed.');
       handleHideDialog();
     }
   };
@@ -241,121 +235,127 @@ export const ConnectionDetailPage = () => {
         { name, path: '' },
       ]}
       extra={
-        <S.PageHeaderExtra>
-          <span style={{ marginRight: 4 }}>Status:</span>
-          <ConnectionStatus connection={connection} />
-          <Buttons style={{ marginLeft: 8 }}>
-            <Button outlined intent={Intent.PRIMARY} icon="annotation" text="Edit" onClick={handleShowUpdateDialog} />
-            <Button intent={Intent.DANGER} icon="trash" text="Delete" onClick={handleShowDeleteDialog} />
-          </Buttons>
-        </S.PageHeaderExtra>
+        <Button type="primary" danger icon={<DeleteOutlined rev={undefined} />} onClick={handleShowDeleteDialog}>
+          Delete
+        </Button>
       }
     >
-      <S.Wrapper>
-        <div className="top">Please note: In order to view DORA metrics, you will need to add Scope Configs.</div>
-        <Buttons position="top">
-          <Button intent={Intent.PRIMARY} icon="add" text="Add Data Scope" onClick={handleShowCreateDataScopeDialog} />
-          {plugin !== 'tapd' && pluginConfig.scopeConfig && (
-            <Button
-              disabled={!scopeIds.length}
-              intent={Intent.PRIMARY}
-              icon="many-to-one"
-              text="Associate Scope Config"
-              onClick={() => handleShowScopeConfigSelectDialog(scopeIds)}
-            />
-          )}
-        </Buttons>
-        <Table
-          rowKey="id"
-          size="middle"
-          loading={!ready}
-          columns={[
-            {
-              title: 'Data Scope',
-              dataIndex: 'name',
-              key: 'name',
-            },
-            {
-              title: 'Project',
-              dataIndex: 'projects',
-              key: 'projects',
-              render: (projects) => (
-                <>
-                  {projects.length ? (
-                    <ul>
-                      {projects.map((it: string) => (
-                        <li key={it}>
-                          <Link to={`/projects/${it}`}>{it}</Link>
-                        </li>
-                      ))}
-                    </ul>
-                  ) : (
-                    '-'
-                  )}
-                </>
-              ),
-            },
-            {
-              title: 'Scope Config',
-              key: 'scopeConfig',
-              width: 400,
-              render: (_, { id, configId, configName }) => (
-                <>
-                  <span>{configId ? configName : 'N/A'}</span>
-                  {pluginConfig.scopeConfig && (
-                    <IconButton
-                      icon="link"
-                      tooltip="Associate Scope Config"
-                      onClick={() => {
-                        handleShowScopeConfigSelectDialog([id]);
-                        setScopeConfigId(configId);
-                      }}
-                    />
-                  )}
-                </>
-              ),
-            },
-            {
-              title: '',
-              dataIndex: 'id',
-              key: 'id',
-              width: 100,
-              render: (id) => (
-                <>
-                  <IconButton
-                    image={<img src={ClearImg} alt="clear" />}
-                    tooltip="Clear historical data"
-                    onClick={() => handleShowClearDataScopeDialog(id)}
-                  />
+      <div style={{ marginBottom: 36 }}>
+        <span>Status:</span>
+        <ConnectionStatus connection={connection} />
+      </div>
+      <div style={{ marginBottom: 36 }}>
+        Please note: In order to view DORA metrics, you will need to add Scope Configs.
+      </div>
+      <div style={{ marginBottom: 36 }}>
+        <Button type="primary" icon={<PlusOutlined rev={undefined} />} onClick={handleShowCreateDataScopeDialog}>
+          Add Data Scope
+        </Button>
+        {plugin !== 'tapd' && pluginConfig.scopeConfig && (
+          <Button
+            style={{ marginLeft: 8 }}
+            type="primary"
+            disabled={!scopeIds.length}
+            icon={<NodeIndexOutlined rev={undefined} />}
+            onClick={() => handleShowScopeConfigSelectDialog(scopeIds)}
+          >
+            Associate Scope Config
+          </Button>
+        )}
+      </div>
+      <Table
+        rowKey="id"
+        size="middle"
+        loading={!ready}
+        columns={[
+          {
+            title: 'Data Scope',
+            dataIndex: 'name',
+            key: 'name',
+          },
+          {
+            title: 'Project',
+            dataIndex: 'projects',
+            key: 'projects',
+            render: (projects) => (
+              <>
+                {projects.length ? (
+                  <ul>
+                    {projects.map((it: string) => (
+                      <li key={it}>
+                        <Link to={`/projects/${it}`}>{it}</Link>
+                      </li>
+                    ))}
+                  </ul>
+                ) : (
+                  '-'
+                )}
+              </>
+            ),
+          },
+          {
+            title: 'Scope Config',
+            key: 'scopeConfig',
+            width: 400,
+            render: (_, { id, configId, configName }) => (
+              <>
+                <span>{configId ? configName : 'N/A'}</span>
+                {pluginConfig.scopeConfig && (
                   <IconButton
-                    icon="trash"
-                    tooltip="Delete Data Scope"
-                    onClick={() => handleShowDeleteDataScopeDialog(id)}
+                    icon="link"
+                    tooltip="Associate Scope Config"
+                    onClick={() => {
+                      handleShowScopeConfigSelectDialog([id]);
+                      setScopeConfigId(configId);
+                    }}
                   />
-                </>
-              ),
-            },
-          ]}
-          dataSource={dataSource}
-          pagination={{
-            current: page,
-            pageSize,
-            total,
-            onChange: setPage,
-          }}
-          rowSelection={{
-            selectedRowKeys: scopeIds,
-            onChange: (selectedRowKeys) => setScopeIds(selectedRowKeys),
-          }}
-        />
-      </S.Wrapper>
+                )}
+              </>
+            ),
+          },
+          {
+            title: '',
+            dataIndex: 'id',
+            key: 'id',
+            width: 100,
+            render: (id) => (
+              <>
+                <IconButton
+                  image={<img src={ClearImg} alt="clear" />}
+                  tooltip="Clear historical data"
+                  onClick={() => handleShowClearDataScopeDialog(id)}
+                />
+                <IconButton
+                  icon="trash"
+                  tooltip="Delete Data Scope"
+                  onClick={() => handleShowDeleteDataScopeDialog(id)}
+                />
+              </>
+            ),
+          },
+        ]}
+        dataSource={dataSource}
+        pagination={{
+          current: page,
+          pageSize,
+          total,
+          onChange: setPage,
+        }}
+        rowSelection={{
+          selectedRowKeys: scopeIds,
+          onChange: (selectedRowKeys) => setScopeIds(selectedRowKeys),
+        }}
+      />
       {type === 'deleteConnection' && (
-        <Dialog
-          isOpen
-          style={{ width: 820 }}
+        <Modal
+          open
+          width={820}
+          centered
           title="Would you like to delete this Data Connection?"
           okText="Confirm"
-          okLoading={operating}
+          okButtonProps={{
+            loading: operating,
+          }}
           onCancel={handleHideDialog}
           onOk={handleDelete}
         >
@@ -363,34 +363,20 @@ export const ConnectionDetailPage = () => {
             content=" This operation cannot be undone. Deleting a Data Connection will delete all data that have been collected
               in this Connection."
           />
-        </Dialog>
-      )}
-      {type === 'updateConnection' && (
-        <Dialog
-          isOpen
-          style={{ width: 820 }}
-          footer={null}
-          title={
-            <S.DialogTitle>
-              {/* <img src={icon} alt="" /> */}
-              <span>Authentication</span>
-            </S.DialogTitle>
-          }
-          onCancel={handleHideDialog}
-        >
-          <ConnectionForm plugin={plugin} connectionId={connectionId} onSuccess={handleUpdate} />
-        </Dialog>
+        </Modal>
       )}
       {type === 'createDataScope' && (
-        <Dialog
-          isOpen
+        <Modal
+          open
+          width={820}
+          centered
           style={{ width: 820 }}
           footer={null}
           title={
-            <S.DialogTitle>
-              {/* <img src={icon} alt="" /> */}
-              <span>Add Data Scope: {name}</span>
-            </S.DialogTitle>
+            <S.ModalTitle>
+              <span className="icon">{pluginConfig.icon({ color: colorPrimary })}</span>
+              <span className="name">Add Data Scope: {name}</span>
+            </S.ModalTitle>
           }
           onCancel={handleHideDialog}
         >
@@ -401,28 +387,34 @@ export const ConnectionDetailPage = () => {
             onCancel={handleHideDialog}
             onSubmit={handleCreateDataScope}
           />
-        </Dialog>
+        </Modal>
       )}
       {type === 'clearDataScope' && (
-        <Dialog
-          isOpen
-          style={{ width: 820 }}
+        <Modal
+          open
+          width={820}
+          centered
           title="Would you like to clear the historical data of the selected Data Scope?"
           okText="Confirm"
-          okLoading={operating}
+          okButtonProps={{
+            loading: operating,
+          }}
           onCancel={handleHideDialog}
           onOk={() => handleDeleteDataScope(true)}
         >
           <Message content="This operation cannot be undone." />
-        </Dialog>
+        </Modal>
       )}
       {type === 'deleteDataScope' && (
-        <Dialog
-          isOpen
-          style={{ width: 820 }}
+        <Modal
+          open
+          width={820}
+          centered
           title="Would you like to delete the selected Data Scope?"
           okText="Confirm"
-          okLoading={operating}
+          okButtonProps={{
+            loading: operating,
+          }}
           onCancel={handleHideDialog}
           onOk={() => handleDeleteDataScope(false)}
         >
@@ -430,10 +422,22 @@ export const ConnectionDetailPage = () => {
             content="This operation cannot be undone. Deleting Data Scope will delete all data that have been collected in the
               past."
           />
-        </Dialog>
+        </Modal>
       )}
       {type === 'associateScopeConfig' && (
-        <Dialog isOpen style={{ width: 960 }} footer={null} title="Associate Scope Config" onCancel={handleHideDialog}>
+        <Modal
+          open
+          width={960}
+          centered
+          footer={null}
+          title={
+            <S.ModalTitle>
+              <span className="icon">{pluginConfig.icon({ color: colorPrimary })}</span>
+              <span>Associate Scope Config</span>
+            </S.ModalTitle>
+          }
+          onCancel={handleHideDialog}
+        >
           {plugin === 'tapd' ? (
             <ScopeConfigForm
               plugin={plugin}
@@ -452,63 +456,70 @@ export const ConnectionDetailPage = () => {
               onSubmit={handleAssociateScopeConfig}
             />
           )}
-        </Dialog>
+        </Modal>
       )}
       {type === 'deleteConnectionFailed' && (
-        <Dialog
-          isOpen
+        <Modal
+          open
+          width={820}
+          centered
           style={{ width: 820 }}
-          footer={null}
-          title={`This Data Connection can not be deleted.`}
+          title="This Data Connection can not be deleted."
+          cancelButtonProps={{
+            style: {
+              display: 'none',
+            },
+          }}
           onCancel={handleHideDialog}
+          onOk={handleHideDialog}
         >
-          <S.DialogBody>
-            {!conflict.length ? (
-              <Message content={errorMsg} />
-            ) : (
-              <>
-                <Message
-                  content={`This Data Connection can not be deleted because it has been used in the following projects/blueprints:`}
-                />
-                <ul>
-                  {conflict.map((it) => (
-                    <li key={it}>{it}</li>
-                  ))}
-                </ul>
-              </>
-            )}
-            <Buttons position="bottom" align="right">
-              <Button intent={Intent.PRIMARY} text="OK" onClick={handleHideDialog} />
-            </Buttons>
-          </S.DialogBody>
-        </Dialog>
+          {!conflict.length ? (
+            <Message content={errorMsg} />
+          ) : (
+            <>
+              <Message
+                content={`This Data Connection can not be deleted because it has been used in the following projects/blueprints:`}
+              />
+              <ul style={{ paddingLeft: 36 }}>
+                {conflict.map((it) => (
+                  <li key={it} style={{ color: colorPrimary }}>
+                    {it}
+                  </li>
+                ))}
+              </ul>
+            </>
+          )}
+        </Modal>
       )}
       {type === 'deleteDataScopeFailed' && (
-        <Dialog
-          isOpen
-          style={{ width: 820 }}
-          footer={null}
-          title={`This Data Scope can not be deleted.`}
+        <Modal
+          open
+          width={820}
+          centered
+          title="This Data Scope can not be deleted."
+          cancelButtonProps={{
+            style: {
+              display: 'none',
+            },
+          }}
           onCancel={handleHideDialog}
+          onOk={handleHideDialog}
         >
-          <S.DialogBody>
-            {!conflict.length ? (
-              <Message content={errorMsg} />
-            ) : (
-              <>
-                <Message content="This Data Scope can not be deleted because it has been used in the following projects/blueprints:" />
-                <ul>
-                  {conflict.map((it) => (
-                    <li key={it}>{it}</li>
-                  ))}
-                </ul>
-              </>
-            )}
-            <Buttons position="bottom" align="right">
-              <Button intent={Intent.PRIMARY} text="OK" onClick={handleHideDialog} />
-            </Buttons>
-          </S.DialogBody>
-        </Dialog>
+          {!conflict.length ? (
+            <Message content={errorMsg} />
+          ) : (
+            <>
+              <Message content="This Data Scope can not be deleted because it has been used in the following projects/blueprints:" />
+              <ul style={{ paddingLeft: 36 }}>
+                {conflict.map((it) => (
+                  <li key={it} style={{ color: colorPrimary }}>
+                    {it}
+                  </li>
+                ))}
+              </ul>
+            </>
+          )}
+        </Modal>
       )}
     </PageHeader>
   );
diff --git a/config-ui/src/routes/connection/index.ts b/config-ui/src/routes/connection/index.ts
index 4e6e8a4de..0d275a532 100644
--- a/config-ui/src/routes/connection/index.ts
+++ b/config-ui/src/routes/connection/index.ts
@@ -17,3 +17,4 @@
  */
 
 export * from './connections';
+export * from './connection';
diff --git a/config-ui/src/routes/connection/styled.ts b/config-ui/src/routes/connection/styled.ts
index 42aa8a6fb..a3bb3ccd8 100644
--- a/config-ui/src/routes/connection/styled.ts
+++ b/config-ui/src/routes/connection/styled.ts
@@ -106,6 +106,7 @@ export const ModalTitle = styled.div`
   align-items: center;
 
   .icon {
+    display: inline-flex;
     margin-right: 8px;
     width: 24px;