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

likyh 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 7484573f8 feat(config-ui): add no-data status for some pages (#4482)
7484573f8 is described below

commit 7484573f87760de98232da96aa3228ca79245650
Author: 青湛 <[email protected]>
AuthorDate: Wed Feb 22 14:45:26 2023 +0800

    feat(config-ui): add no-data status for some pages (#4482)
    
    * refactor(config-ui): adjust the component table
    
    * feat(config-ui): add no-data status for some pages
---
 config-ui/src/components/table/styled.ts           | 24 ++++--
 config-ui/src/components/table/table.tsx           | 94 ++++++++++++++--------
 config-ui/src/pages/blueprint/home/index.tsx       | 14 +++-
 config-ui/src/pages/connection/list/connection.tsx | 12 ++-
 config-ui/src/pages/project/home/index.tsx         | 28 +++----
 config-ui/src/pages/transformation/home/index.tsx  |  9 ++-
 .../plugins/register/webook/connection/index.tsx   | 18 ++++-
 7 files changed, 132 insertions(+), 67 deletions(-)

diff --git a/config-ui/src/components/table/styled.ts 
b/config-ui/src/components/table/styled.ts
index ecfcfaf9b..fb1b97dc7 100644
--- a/config-ui/src/components/table/styled.ts
+++ b/config-ui/src/components/table/styled.ts
@@ -22,16 +22,24 @@ export const Container = styled.div`
   position: relative;
 `;
 
-export const TableWrapper = styled.ul<{ loading: number }>`
-  margin: 0;
-  padding: 0;
-  list-style: none;
-  transition: opacity 0.3s linear;
+export const Loading = styled.div`
+  text-align: center;
+`;
 
+export const NoData = styled.div`
+  text-align: center;
+
+  img {
+    display: inline-block;
+  }
+`;
+
+export const Table = styled.ul<{ loading: number }>`
+  transition: opacity 0.3s linear;
   ${({ loading }) => (loading ? 'opacity: 0.2; ' : '')}
 `;
 
-export const TableRow = styled.li`
+export const Row = styled.li`
   display: flex;
   align-items: center;
   padding: 12px 16px;
@@ -43,13 +51,13 @@ export const TableRow = styled.li`
   }
 `;
 
-export const TableHeader = styled(TableRow)`
+export const Header = styled(Row)`
   font-size: 14px;
   font-weight: 600;
   border-top: none;
 `;
 
-export const TableMask = styled.div`
+export const Mask = styled.div`
   position: absolute;
   top: 0;
   right: 0;
diff --git a/config-ui/src/components/table/table.tsx 
b/config-ui/src/components/table/table.tsx
index 3a11449e0..71021e739 100644
--- a/config-ui/src/components/table/table.tsx
+++ b/config-ui/src/components/table/table.tsx
@@ -17,7 +17,9 @@
  */
 
 import React from 'react';
+import { Button, Intent } from '@blueprintjs/core';
 
+import NoData from '@/images/no-data.svg';
 import { Loading, Card } from '@/components';
 
 import { ColumnType } from './types';
@@ -27,44 +29,66 @@ interface Props<T> {
   loading?: boolean;
   columns: ColumnType<T>;
   dataSource: T[];
+  noData?: {
+    text?: React.ReactNode;
+    btnText?: string;
+    onCreate?: () => void;
+  };
 }
 
-export const Table = <T extends Record<string, any>>({ loading, columns, 
dataSource }: Props<T>) => {
+export const Table = <T extends Record<string, any>>({ loading, columns, 
dataSource, noData = {} }: Props<T>) => {
+  const { text, btnText, onCreate } = noData;
+
   return (
-    <Card style={{ padding: 0 }}>
-      <S.Container>
-        <S.TableWrapper loading={loading ? 1 : 0}>
-          <S.TableHeader>
-            {columns.map(({ key, align = 'left', title }) => (
-              <span key={key} style={{ textAlign: align }}>
-                {title}
-              </span>
-            ))}
-          </S.TableHeader>
-          {dataSource.map((data, i) => (
-            <S.TableRow key={i}>
-              {columns.map(({ key, align = 'left', dataIndex, render }) => {
-                const value = Array.isArray(dataIndex)
-                  ? dataIndex.reduce((acc, cur) => {
-                      acc[cur] = data[cur];
-                      return acc;
-                    }, {} as any)
-                  : data[dataIndex];
-                return (
-                  <span key={key} style={{ textAlign: align }}>
-                    {render ? render(value, data) : value}
-                  </span>
-                );
-              })}
-            </S.TableRow>
-          ))}
-        </S.TableWrapper>
-        {loading && (
-          <S.TableMask>
+    <S.Container>
+      {loading ? (
+        <Card>
+          <S.Loading>
             <Loading />
-          </S.TableMask>
-        )}
-      </S.Container>
-    </Card>
+          </S.Loading>
+        </Card>
+      ) : !dataSource.length ? (
+        <Card>
+          <S.NoData>
+            <img src={NoData} alt="" />
+            <p>{text ?? 'No Data'}</p>
+            {onCreate && (
+              <Button intent={Intent.PRIMARY} icon="plus" onClick={onCreate}>
+                {btnText ?? 'Create'}
+              </Button>
+            )}
+          </S.NoData>
+        </Card>
+      ) : (
+        <Card style={{ padding: 0 }}>
+          <S.Table loading={loading ? 1 : 0}>
+            <S.Header>
+              {columns.map(({ key, align = 'left', title }) => (
+                <span key={key} style={{ textAlign: align }}>
+                  {title}
+                </span>
+              ))}
+            </S.Header>
+            {dataSource.map((data, i) => (
+              <S.Row key={i}>
+                {columns.map(({ key, align = 'left', dataIndex, render }) => {
+                  const value = Array.isArray(dataIndex)
+                    ? dataIndex.reduce((acc, cur) => {
+                        acc[cur] = data[cur];
+                        return acc;
+                      }, {} as any)
+                    : data[dataIndex];
+                  return (
+                    <span key={key} style={{ textAlign: align }}>
+                      {render ? render(value, data) : value}
+                    </span>
+                  );
+                })}
+              </S.Row>
+            ))}
+          </S.Table>
+        </Card>
+      )}
+    </S.Container>
   );
 };
diff --git a/config-ui/src/pages/blueprint/home/index.tsx 
b/config-ui/src/pages/blueprint/home/index.tsx
index 85cea6500..e5ee303e9 100644
--- a/config-ui/src/pages/blueprint/home/index.tsx
+++ b/config-ui/src/pages/blueprint/home/index.tsx
@@ -90,6 +90,8 @@ export const BlueprintHomePage = () => {
     [],
   );
 
+  const handleCreate = () => history.push('/blueprints/create');
+
   if (loading) {
     return <PageLoading />;
   }
@@ -113,9 +115,17 @@ export const BlueprintHomePage = () => {
               />
             ))}
           </ButtonGroup>
-          <Button intent={Intent.PRIMARY} text="Create Blueprint" onClick={() 
=> history.push('/blueprints/create')} />
+          <Button icon="plus" intent={Intent.PRIMARY} text="New Blueprint" 
onClick={handleCreate} />
         </div>
-        <Table columns={columns} dataSource={dataSource} />
+        <Table
+          columns={columns}
+          dataSource={dataSource}
+          noData={{
+            text: 'There is no Blueprint yet. Please add a new Blueprint here 
or from a Project.',
+            btnText: 'New Blueprint',
+            onCreate: handleCreate,
+          }}
+        />
       </S.Wrapper>
     </PageHeader>
   );
diff --git a/config-ui/src/pages/connection/list/connection.tsx 
b/config-ui/src/pages/connection/list/connection.tsx
index 49387335a..a32909612 100644
--- a/config-ui/src/pages/connection/list/connection.tsx
+++ b/config-ui/src/pages/connection/list/connection.tsx
@@ -121,10 +121,18 @@ export const Connection = ({ plugin }: Props) => {
   return (
     <S.Wrapper>
       <ButtonGroup className="action">
-        <Button intent={Intent.PRIMARY} icon="plus" text="Add Connection" 
onClick={handleCreate} />
+        <Button intent={Intent.PRIMARY} icon="plus" text="New Connection" 
onClick={handleCreate} />
         <Button icon="refresh" text="Refresh Connections" 
onClick={handleRefresh} />
       </ButtonGroup>
-      <Table columns={columns} dataSource={connections} />
+      <Table
+        columns={columns}
+        dataSource={connections}
+        noData={{
+          text: 'There is no data connection yet. Please add a new 
connection.',
+          btnText: 'New Connection',
+          onCreate: handleCreate,
+        }}
+      />
     </S.Wrapper>
   );
 };
diff --git a/config-ui/src/pages/project/home/index.tsx 
b/config-ui/src/pages/project/home/index.tsx
index 4cd3c5e31..2941b8e3e 100644
--- a/config-ui/src/pages/project/home/index.tsx
+++ b/config-ui/src/pages/project/home/index.tsx
@@ -20,8 +20,7 @@ import React, { useMemo, useState } from 'react';
 import { Link, useHistory } from 'react-router-dom';
 import { Button, InputGroup, Checkbox, Intent } from '@blueprintjs/core';
 
-import NoData from '@/images/no-data.svg';
-import { PageHeader, Card, Table, ColumnType, Dialog } from '@/components';
+import { PageHeader, Table, ColumnType, Dialog } from '@/components';
 
 import { useProject } from './use-project';
 import * as S from './styled';
@@ -87,21 +86,16 @@ export const ProjectHomePage = () => {
       }
     >
       <S.Container>
-        {!projects.length ? (
-          <Card className="card">
-            <div className="logo">
-              <img src={NoData} alt="" />
-            </div>
-            <div className="desc">
-              <p>Add new projects to see engineering metrics based on 
projects.</p>
-            </div>
-            <div className="action">
-              <Button intent={Intent.PRIMARY} icon="plus" text="New Project" 
onClick={handleShowDialog} />
-            </div>
-          </Card>
-        ) : (
-          <Table loading={loading} columns={columns} dataSource={projects} />
-        )}
+        <Table
+          loading={loading}
+          columns={columns}
+          dataSource={projects}
+          noData={{
+            text: 'Add new projects to see engineering metrics based on 
projects.',
+            btnText: 'New Project',
+            onCreate: handleShowDialog,
+          }}
+        />
         <Dialog
           isOpen={isOpen}
           title="Create a New Project"
diff --git a/config-ui/src/pages/transformation/home/index.tsx 
b/config-ui/src/pages/transformation/home/index.tsx
index f660bb84d..840af9e9e 100644
--- a/config-ui/src/pages/transformation/home/index.tsx
+++ b/config-ui/src/pages/transformation/home/index.tsx
@@ -33,6 +33,8 @@ export const TransformationHomePage = () => {
 
   const history = useHistory();
 
+  const handleCreate = () => setIsOpen(true);
+
   const columns = useMemo(
     () =>
       [
@@ -86,11 +88,16 @@ export const TransformationHomePage = () => {
                     />
                   ))}
                 </ButtonGroup>
-                <Button intent={Intent.PRIMARY} text="Create Transformation" 
onClick={() => setIsOpen(true)} />
+                <Button icon="plus" intent={Intent.PRIMARY} text="New 
Transformation" onClick={handleCreate} />
               </div>
               <Table
                 columns={columns}
                 dataSource={transformations.filter((ts) => (active === 'All' ? 
true : ts.plugin === active))}
+                noData={{
+                  text: 'There is no transformation yet. Please add a new 
transformation.',
+                  btnText: 'New Transformation',
+                  onCreate: handleCreate,
+                }}
               />
               <Dialog
                 isOpen={isOpen}
diff --git a/config-ui/src/plugins/register/webook/connection/index.tsx 
b/config-ui/src/plugins/register/webook/connection/index.tsx
index 602011409..c2bc368c9 100644
--- a/config-ui/src/plugins/register/webook/connection/index.tsx
+++ b/config-ui/src/plugins/register/webook/connection/index.tsx
@@ -19,7 +19,7 @@
 import React, { useState } from 'react';
 import { ButtonGroup, Button, Icon, Intent } from '@blueprintjs/core';
 
-import { Table, ColumnType } from '@/components';
+import { Table, ColumnType, ExternalLink } from '@/components';
 
 import type { WebhookItemType } from '../types';
 import { WebhookCreateDialog } from '../create-dialog';
@@ -83,7 +83,21 @@ export const WebHookConnection = ({ onCreateAfter, ...props 
}: Props) => {
       <ButtonGroup>
         <Button icon="plus" text="Add a Webhook" intent={Intent.PRIMARY} 
onClick={() => handleShowDialog('add')} />
       </ButtonGroup>
-      <Table loading={loading} columns={columns} dataSource={connections} />
+      <Table
+        loading={loading}
+        columns={columns}
+        dataSource={connections}
+        noData={{
+          text: (
+            <>
+              There is no Webhook yet. Please add a new Webhook.{' '}
+              <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/webhook";>Learn 
more</ExternalLink>
+            </>
+          ),
+          btnText: 'Add a Webhook',
+          onCreate: () => handleShowDialog('add'),
+        }}
+      />
       {type === 'add' && (
         <WebhookCreateDialog
           isOpen

Reply via email to