You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by li...@apache.org on 2023/05/30 01:59:59 UTC

[incubator-devlake] branch main updated: feat(config-ui): add clear and delete data scope (#5304)

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 b67dacafc feat(config-ui): add clear and delete data scope (#5304)
b67dacafc is described below

commit b67dacafc2a656662fdd10dfff79ad747a620080
Author: 青湛 <0x...@gmail.com>
AuthorDate: Tue May 30 09:59:53 2023 +0800

    feat(config-ui): add clear and delete data scope (#5304)
    
    * refactor(config-ui): rename data-scope-form-2 to data-scope-select-remote
    
    * feat(config-ui): add clear and delete data scope
---
 config-ui/src/pages/connection/detail/api.ts       |   8 ++
 config-ui/src/pages/connection/detail/index.tsx    | 116 ++++++++++++++++-----
 config-ui/src/pages/connection/detail/styled.ts    |  15 +--
 .../api.ts                                         |   0
 .../index.tsx                                      |  28 +----
 .../styled.ts                                      |   0
 config-ui/src/plugins/components/index.ts          |   2 +-
 7 files changed, 109 insertions(+), 60 deletions(-)

diff --git a/config-ui/src/pages/connection/detail/api.ts b/config-ui/src/pages/connection/detail/api.ts
index c86588cc4..055719883 100644
--- a/config-ui/src/pages/connection/detail/api.ts
+++ b/config-ui/src/pages/connection/detail/api.ts
@@ -22,3 +22,11 @@ export const deleteConnection = (plugin: string, id: ID) =>
   request(`/plugins/${plugin}/connections/${id}`, { method: 'delete' });
 
 export const getDataScope = (plugin: string, id: ID) => request(`/plugins/${plugin}/connections/${id}/scopes`);
+
+export const deleteDataScope = (plugin: string, id: ID, scopeId: ID, onlyData: boolean) =>
+  request(`/plugins/${plugin}/connections/${id}/scopes/${scopeId}`, {
+    method: 'delete',
+    data: {
+      delete_data_only: onlyData,
+    },
+  });
diff --git a/config-ui/src/pages/connection/detail/index.tsx b/config-ui/src/pages/connection/detail/index.tsx
index 7e3d3e9fe..a82eba8c4 100644
--- a/config-ui/src/pages/connection/detail/index.tsx
+++ b/config-ui/src/pages/connection/detail/index.tsx
@@ -21,9 +21,8 @@ import { useParams, useHistory } from 'react-router-dom';
 import { Button, Icon, Intent } from '@blueprintjs/core';
 
 import { PageHeader, Dialog, IconButton, Table } from '@/components';
-import { transformEntities } from '@/config';
 import { useTips, useConnections, useRefreshData } from '@/hooks';
-import { ConnectionForm, ConnectionStatus, DataScopeForm2 } from '@/plugins';
+import { ConnectionForm, ConnectionStatus, DataScopeSelectRemote, getPluginId } from '@/plugins';
 import { operator } from '@/utils';
 
 import * as API from './api';
@@ -35,16 +34,19 @@ interface Props {
 }
 
 const ConnectionDetail = ({ plugin, id }: Props) => {
-  const [type, setType] = useState<'deleteConnection' | 'updateConnection' | 'createDataScope'>();
+  const [type, setType] = useState<
+    'deleteConnection' | 'updateConnection' | 'createDataScope' | 'clearDataScope' | 'deleteDataScope'
+  >();
   const [operating, setOperating] = useState(false);
   const [version, setVersion] = useState(1);
+  const [scopeId, setScopeId] = useState<ID>();
 
   const history = useHistory();
   const { onGet, onTest, onRefresh } = useConnections();
   const { setTips } = useTips();
   const { ready, data } = useRefreshData(() => API.getDataScope(plugin, id), [version]);
 
-  const { unique, status, name, icon, entities } = onGet(`${plugin}-${id}`);
+  const { unique, status, name, icon } = onGet(`${plugin}-${id}`);
 
   const handleHideDialog = () => {
     setType(undefined);
@@ -96,6 +98,31 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
     handleHideDialog();
   };
 
+  const handleShowClearDataScopeDialog = (scopeId: ID) => {
+    setType('clearDataScope');
+    setScopeId(scopeId);
+  };
+
+  const handleShowDeleteDataScopeDialog = (scopeId: ID) => {
+    setType('deleteDataScope');
+    setScopeId(scopeId);
+  };
+
+  const handleDeleteDataScope = async (onlyData: boolean) => {
+    if (!scopeId) return;
+
+    const [success] = await operator(() => API.deleteDataScope(plugin, id, scopeId, onlyData), {
+      setOperating,
+      formatMessage: () => (onlyData ? 'Clear historical data successful.' : 'Delete Data Scope successful.'),
+    });
+
+    if (success) {
+      setVersion((v) => v + 1);
+      handleShowTips();
+      handleHideDialog();
+    }
+  };
+
   return (
     <PageHeader
       breadcrumbs={[
@@ -105,25 +132,10 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
       extra={<Button intent={Intent.DANGER} icon="trash" text="Delete Connection" onClick={handleShowDeleteDialog} />}
     >
       <S.Wrapper>
-        <div className="top">
-          <div className="entities">
-            <h3>Data Entities</h3>
-            <span>
-              {transformEntities(entities)
-                .map((it) => it.label)
-                .join(',')}
-            </span>
-          </div>
-          <div className="authentication">
-            <h3>
-              <span>Authentication</span>
-              <IconButton icon="annotation" tooltip="Edit Connection" onClick={handleShowUpdateDialog} />
-            </h3>
-            <span>Status: </span>
-            <span>
-              Status: <ConnectionStatus status={status} unique={unique} onTest={onTest} />
-            </span>
-          </div>
+        <div className="authentication">
+          <span style={{ marginRight: 4 }}>Authentication Status:</span>
+          <ConnectionStatus status={status} unique={unique} onTest={onTest} />
+          <IconButton icon="annotation" tooltip="Edit Connection" onClick={handleShowUpdateDialog} />
         </div>
         <div className="action">
           <Button intent={Intent.PRIMARY} icon="add" text="Add Data Scope" onClick={handleShowCreateDataScopeDialog} />
@@ -136,6 +148,26 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
               dataIndex: 'name',
               key: 'name',
             },
+            {
+              title: '',
+              dataIndex: getPluginId(plugin),
+              key: 'id',
+              width: 100,
+              render: (id) => (
+                <>
+                  <IconButton
+                    icon="unarchive"
+                    tooltip="Clear historical data"
+                    onClick={() => handleShowClearDataScopeDialog(id)}
+                  />
+                  <IconButton
+                    icon="trash"
+                    tooltip="Delete Data Scope"
+                    onClick={() => handleShowDeleteDataScopeDialog(id)}
+                  />
+                </>
+              ),
+            },
           ]}
           dataSource={data}
           noData={{
@@ -148,6 +180,7 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
       {type === 'deleteConnection' && (
         <Dialog
           isOpen
+          style={{ width: 820 }}
           title="Would you like to delete this Data Connection?"
           okText="Confirm"
           okLoading={operating}
@@ -192,7 +225,7 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
           }
           onCancel={handleHideDialog}
         >
-          <DataScopeForm2
+          <DataScopeSelectRemote
             plugin={plugin}
             connectionId={id}
             disabledScope={data}
@@ -201,6 +234,41 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
           />
         </Dialog>
       )}
+      {type === 'clearDataScope' && (
+        <Dialog
+          isOpen
+          style={{ width: 820 }}
+          title="Would you like to clear the historical data of the selected Data Scope?"
+          okText="Confirm"
+          okLoading={operating}
+          onCancel={handleHideDialog}
+          onOk={() => handleDeleteDataScope(true)}
+        >
+          <S.DialogBody>
+            <Icon icon="warning-sign" />
+            <span>This operation cannot be undone.</span>
+          </S.DialogBody>
+        </Dialog>
+      )}
+      {type === 'deleteDataScope' && (
+        <Dialog
+          isOpen
+          style={{ width: 820 }}
+          title="Would you like to delete the selected Data Scope?"
+          okText="Confirm"
+          okLoading={operating}
+          onCancel={handleHideDialog}
+          onOk={() => handleDeleteDataScope(false)}
+        >
+          <S.DialogBody>
+            <Icon icon="warning-sign" />
+            <span>
+              This operation cannot be undone. Deleting Data Scope will delete all data that have been collected in the
+              past.
+            </span>
+          </S.DialogBody>
+        </Dialog>
+      )}
     </PageHeader>
   );
 };
diff --git a/config-ui/src/pages/connection/detail/styled.ts b/config-ui/src/pages/connection/detail/styled.ts
index 4a9225132..ce2815f10 100644
--- a/config-ui/src/pages/connection/detail/styled.ts
+++ b/config-ui/src/pages/connection/detail/styled.ts
@@ -19,18 +19,13 @@
 import styled from 'styled-components';
 
 export const Wrapper = styled.div`
-  .top {
+  .authentication {
     display: flex;
-    justify-content: space-between;
+    align-items: center;
+    justify-content: flex-end;
 
-    h3 {
-      margin-bottom: 16px;
-    }
-  }
-
-  .authentication {
-    h3 {
-      span 
+    & > .bp4-popover2-target {
+      margin-left: 8px;
     }
   }
 
diff --git a/config-ui/src/plugins/components/data-scope-form-2/api.ts b/config-ui/src/plugins/components/data-scope-select-remote/api.ts
similarity index 100%
rename from config-ui/src/plugins/components/data-scope-form-2/api.ts
rename to config-ui/src/plugins/components/data-scope-select-remote/api.ts
diff --git a/config-ui/src/plugins/components/data-scope-form-2/index.tsx b/config-ui/src/plugins/components/data-scope-select-remote/index.tsx
similarity index 92%
rename from config-ui/src/plugins/components/data-scope-form-2/index.tsx
rename to config-ui/src/plugins/components/data-scope-select-remote/index.tsx
index 4d64dc8df..b9954f010 100644
--- a/config-ui/src/plugins/components/data-scope-form-2/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select-remote/index.tsx
@@ -29,35 +29,21 @@ import { BitbucketDataScope } from '@/plugins/register/bitbucket';
 import { AzureDataScope } from '@/plugins/register/azure';
 import { SonarQubeDataScope } from '@/plugins/register/sonarqube';
 import { PagerDutyDataScope } from '@/plugins/register/pagerduty';
+import { TapdDataScope } from '@/plugins/register/tapd';
 import { ZentaoDataScope } from '@/plugins/register/zentao';
 
 import * as API from './api';
 import * as S from './styled';
-import { TapdDataScope } from '@/plugins/register/tapd';
 
 interface Props {
   plugin: string;
   connectionId: ID;
   disabledScope?: any[];
-  cancelBtnProps?: {
-    text?: string;
-  };
-  submitBtnProps?: {
-    text?: string;
-  };
   onCancel?: () => void;
   onSubmit?: (origin: any) => void;
 }
 
-export const DataScopeForm2 = ({
-  plugin,
-  connectionId,
-  disabledScope,
-  onSubmit,
-  onCancel,
-  cancelBtnProps,
-  submitBtnProps,
-}: Props) => {
+export const DataScopeSelectRemote = ({ plugin, connectionId, disabledScope, onSubmit, onCancel }: Props) => {
   const [operating, setOperating] = useState(false);
   const [scope, setScope] = useState<any>([]);
 
@@ -192,19 +178,11 @@ export const DataScopeForm2 = ({
       )}
 
       <div className="action">
-        <Button
-          outlined
-          intent={Intent.PRIMARY}
-          text="Cancel"
-          {...cancelBtnProps}
-          disabled={operating}
-          onClick={onCancel}
-        />
+        <Button outlined intent={Intent.PRIMARY} text="Cancel" disabled={operating} onClick={onCancel} />
         <Button
           outlined
           intent={Intent.PRIMARY}
           text="Save"
-          {...submitBtnProps}
           loading={operating}
           disabled={!!error}
           onClick={handleSubmit}
diff --git a/config-ui/src/plugins/components/data-scope-form-2/styled.ts b/config-ui/src/plugins/components/data-scope-select-remote/styled.ts
similarity index 100%
rename from config-ui/src/plugins/components/data-scope-form-2/styled.ts
rename to config-ui/src/plugins/components/data-scope-select-remote/styled.ts
diff --git a/config-ui/src/plugins/components/index.ts b/config-ui/src/plugins/components/index.ts
index 6a81da1a4..b7fc05447 100644
--- a/config-ui/src/plugins/components/index.ts
+++ b/config-ui/src/plugins/components/index.ts
@@ -19,10 +19,10 @@
 export * from './connection-form';
 export * from './connection-list';
 export * from './connection-status';
-export * from './data-scope-form-2';
 export * from './data-scope-miller-columns';
 export * from './data-scope-search';
 export * from './data-scope-select';
+export * from './data-scope-select-remote';
 export * from './transformation';
 export * from './transformation-form';
 export * from './transformation-select';