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 44c9247a5 feat(config-ui): improve the content for the new design 
(#5341)
44c9247a5 is described below

commit 44c9247a520d538c15e16066c942b87c912e26a0
Author: 青湛 <[email protected]>
AuthorDate: Fri Jun 2 09:27:05 2023 +0800

    feat(config-ui): improve the content for the new design (#5341)
    
    * feat(config-ui): default select all plugin entities
    
    * feat(config-ui): link data entities and transformation
    
    * feat(config-ui): add new component message
    
    * feat(config-ui): add warning message for data scopo form
    
    * feat(config-ui): disabled button when no scope selected
    
    * feat(config-ui): support params disabled in icon-button
    
    * feat(config-ui): distinguish between project and blueprint details
    
    * feat(config-ui): improve the connection detail
    
    * feat(config-ui): adjust the connection detail page
    
    * feat(config-ui): improve the content for connection
    
    * refactor(config-ui): adjust the wording and style
---
 config-ui/src/App.tsx                              |   1 +
 .../src/components/action/icon-button/index.tsx    |   6 +-
 config-ui/src/components/index.ts                  |   1 +
 .../styled.ts => components/message/index.tsx}     |  35 +-
 config-ui/src/config/cron.ts                       |   4 +-
 .../src/pages/blueprint/connection-detail/api.ts   |   2 +
 .../pages/blueprint/connection-detail/index.tsx    |  43 +-
 .../blueprint/detail/blueprint-detail-page.tsx     |   7 +-
 .../pages/blueprint/detail/blueprint-detail.tsx    | 103 +---
 .../pages/blueprint/detail/configuration-panel.tsx |  58 ++-
 .../src/pages/blueprint/detail/status-panel.tsx    | 149 +++++-
 config-ui/src/pages/blueprint/detail/styled.ts     |  28 +-
 config-ui/src/pages/blueprint/types.ts             |   6 +
 config-ui/src/pages/connection/detail/index.tsx    |  35 +-
 config-ui/src/pages/connection/detail/styled.ts    |   7 +
 config-ui/src/pages/connection/home/index.tsx      |  22 +-
 config-ui/src/pages/project/detail/api.ts          |   5 +-
 config-ui/src/pages/project/detail/index.tsx       |   8 +-
 .../plugins/components/connection-form/index.tsx   |   6 +-
 .../plugins/components/connection-list/index.tsx   |   1 +
 .../plugins/components/data-scope-select/index.tsx |  37 +-
 .../plugins/components/scope-config-form/index.tsx |  76 ++-
 .../components/scope-config-select/index.tsx       |  10 +-
 .../src/plugins/register/azure/transformation.tsx  | 123 ++---
 .../plugins/register/bitbucket/transformation.tsx  | 257 +++++-----
 .../src/plugins/register/github/transformation.tsx | 556 +++++++++++----------
 .../src/plugins/register/gitlab/transformation.tsx | 126 ++---
 .../plugins/register/jenkins/transformation.tsx    | 123 ++---
 .../jira/transformation-fields/cross-domain.tsx    |   2 +-
 .../src/plugins/register/jira/transformation.tsx   | 253 +++++-----
 .../src/plugins/register/tapd/transformation.tsx   | 324 ++++++------
 31 files changed, 1318 insertions(+), 1096 deletions(-)

diff --git a/config-ui/src/App.tsx b/config-ui/src/App.tsx
index cc4b18aeb..1e723a1e6 100644
--- a/config-ui/src/App.tsx
+++ b/config-ui/src/App.tsx
@@ -68,6 +68,7 @@ function App() {
                 <Route exact path="/connections/:plugin/:id" component={() => 
<ConnectionDetailPage />} />
                 <Route exact path="/projects" component={() => 
<ProjectHomePage />} />
                 <Route exact path="/projects/:pname" component={() => 
<ProjectDetailPage />} />
+                <Route exact path="/projects/:pname/:unique" component={() => 
<BlueprintConnectionDetailPage />} />
                 <Route exact path="/blueprints" component={() => 
<BlueprintHomePage />} />
                 <Route exact path="/blueprints/:id" component={() => 
<BlueprintDetailPage />} />
                 <Route exact path="/blueprints/:bid/:unique" component={() => 
<BlueprintConnectionDetailPage />} />
diff --git a/config-ui/src/components/action/icon-button/index.tsx 
b/config-ui/src/components/action/icon-button/index.tsx
index 7a40dc80d..45441018a 100644
--- a/config-ui/src/components/action/icon-button/index.tsx
+++ b/config-ui/src/components/action/icon-button/index.tsx
@@ -16,7 +16,6 @@
  *
  */
 
-import React from 'react';
 import { Button, Intent, Position, IconName } from '@blueprintjs/core';
 import { Tooltip2 } from '@blueprintjs/popover2';
 
@@ -24,13 +23,14 @@ interface Props {
   icon: IconName;
   tooltip: string;
   loading?: boolean;
+  disabled?: boolean;
   onClick?: () => void;
 }
 
-export const IconButton = ({ icon, tooltip, loading, onClick }: Props) => {
+export const IconButton = ({ icon, tooltip, loading, disabled, onClick }: 
Props) => {
   return (
     <Tooltip2 intent={Intent.PRIMARY} position={Position.TOP} 
content={tooltip}>
-      <Button loading={loading} minimal intent={Intent.PRIMARY} icon={icon} 
onClick={onClick} />
+      <Button loading={loading} disabled={disabled} minimal 
intent={Intent.PRIMARY} icon={icon} onClick={onClick} />
     </Tooltip2>
   );
 };
diff --git a/config-ui/src/components/index.ts 
b/config-ui/src/components/index.ts
index b7582018b..bad168aef 100644
--- a/config-ui/src/components/index.ts
+++ b/config-ui/src/components/index.ts
@@ -27,6 +27,7 @@ export * from './form-item';
 export * from './inspector';
 export * from './loading';
 export * from './logo';
+export * from './message';
 export * from './no-data';
 export * from './page-header';
 export * from './selector';
diff --git a/config-ui/src/pages/connection/detail/styled.ts 
b/config-ui/src/components/message/index.tsx
similarity index 70%
copy from config-ui/src/pages/connection/detail/styled.ts
copy to config-ui/src/components/message/index.tsx
index 8a166f523..bc803d9d6 100644
--- a/config-ui/src/pages/connection/detail/styled.ts
+++ b/config-ui/src/components/message/index.tsx
@@ -16,32 +16,29 @@
  *
  */
 
+import { Icon } from '@blueprintjs/core';
 import styled from 'styled-components';
 
-export const Wrapper = styled.div`
-  .authentication {
-    display: flex;
-    align-items: center;
-    justify-content: flex-end;
-  }
-`;
-
-export const DialogTitle = styled.div`
+const Wrapper = styled.div`
   display: flex;
   align-items: center;
+  font-size: 12px;
 
-  img {
+  & > .bp4-icon {
     margin-right: 8px;
-    width: 24px;
   }
 `;
 
-export const DialogBody = styled.div`
-  display: flex;
-  align-items: center;
+interface Props {
+  style?: React.CSSProperties;
+  content: React.ReactNode;
+}
 
-  .bp4-icon {
-    margin-right: 8px;
-    color: #f4be55;
-  }
-`;
+export const Message = ({ style, content }: Props) => {
+  return (
+    <Wrapper style={style}>
+      <Icon icon="warning-sign" size={24} color="#f4be55" />
+      <span>{content}</span>
+    </Wrapper>
+  );
+};
diff --git a/config-ui/src/config/cron.ts b/config-ui/src/config/cron.ts
index 3b5f5f0b9..ddcdbdd8c 100644
--- a/config-ui/src/config/cron.ts
+++ b/config-ui/src/config/cron.ts
@@ -49,7 +49,7 @@ export const getCron = (isManual: boolean, config: string) => 
{
     return {
       label: 'Manual',
       value: 'manual',
-      description: 'Manual',
+      description: '',
       config: '',
       nextTime: '',
     };
@@ -65,7 +65,7 @@ export const getCron = (isManual: boolean, config: string) => 
{
       }
     : {
         label: 'Custom',
-        value: 'custom',
+        value: '',
         description: 'Custom',
         config,
         nextTime: getNextTime(config),
diff --git a/config-ui/src/pages/blueprint/connection-detail/api.ts 
b/config-ui/src/pages/blueprint/connection-detail/api.ts
index dac107063..6e6109e21 100644
--- a/config-ui/src/pages/blueprint/connection-detail/api.ts
+++ b/config-ui/src/pages/blueprint/connection-detail/api.ts
@@ -18,6 +18,8 @@
 
 import { request } from '@/utils';
 
+export const getProject = (pname: string) => request(`/projects/${pname}`);
+
 export const getBlueprint = (id: ID) => request(`/blueprints/${id}`);
 
 export const updateBlueprint = (id: ID, payload: any) =>
diff --git a/config-ui/src/pages/blueprint/connection-detail/index.tsx 
b/config-ui/src/pages/blueprint/connection-detail/index.tsx
index 39dc7cf44..6ab122f9e 100644
--- a/config-ui/src/pages/blueprint/connection-detail/index.tsx
+++ b/config-ui/src/pages/blueprint/connection-detail/index.tsx
@@ -33,13 +33,22 @@ export const BlueprintConnectionDetailPage = () => {
   const [version, setVersion] = useState(1);
   const [isOpen, setIsOpen] = useState(false);
 
-  const { bid, unique } = useParams<{ bid: string; unique: string }>();
+  const { pname, bid, unique } = useParams<{ pname?: string; bid?: string; 
unique: string }>();
   const history = useHistory();
 
+  const getBlueprint = async (pname?: string, bid?: string) => {
+    if (pname) {
+      const res = await API.getProject(pname);
+      return res.blueprint;
+    }
+
+    return API.getBlueprint(bid as any);
+  };
+
   const { ready, data } = useRefreshData(async () => {
     const [plugin, connectionId] = unique.split('-');
     const [blueprint, connection, scopes] = await Promise.all([
-      API.getBlueprint(bid),
+      getBlueprint(pname, bid),
       API.getConnection(plugin, connectionId),
       API.getDataScopes(plugin, connectionId),
     ]);
@@ -58,7 +67,7 @@ export const BlueprintConnectionDetailPage = () => {
       },
       scopes: scopes.filter((sc: any) => 
scopeIds.includes(sc[getPluginId(plugin)])),
     };
-  }, [version]);
+  }, [version, pname, bid]);
 
   if (!ready || !data) {
     return <PageLoading />;
@@ -83,7 +92,7 @@ export const BlueprintConnectionDetailPage = () => {
     );
 
     if (success) {
-      history.push(`/blueprints/${blueprint.id}`);
+      history.push(pname ? `/projects/${pname}` : 
`/blueprints/${blueprint.id}`);
     }
   };
 
@@ -118,14 +127,24 @@ export const BlueprintConnectionDetailPage = () => {
 
   return (
     <PageHeader
-      breadcrumbs={[
-        { name: blueprint.name, path: `/blueprints/${bid}` },
-        { name: `Connection - ${connection.name}`, path: '' },
-      ]}
+      breadcrumbs={
+        pname
+          ? [
+              { name: 'Projects', path: '/projects' },
+              { name: pname, path: `/projects/${pname}` },
+              { name: `Connection - ${connection.name}`, path: '' },
+            ]
+          : [
+              { name: 'Advanced', path: '/blueprints' },
+              { name: 'Blueprints', path: '/blueprints' },
+              { name: bid as any, path: `/blueprints/${bid}` },
+              { name: `Connection - ${connection.name}`, path: '' },
+            ]
+      }
     >
       <S.Top>
         <span>
-          If you would like to manage Data Entities and Data Scope of this 
Connection, please{' '}
+          If you would like to edit the Data Scope or Scope Config of this 
Connection, please{' '}
           <ExternalLink 
link={`/connections/${connection.plugin}/${connection.id}`}>
             go to the Connection detail page
           </ExternalLink>
@@ -149,11 +168,14 @@ export const BlueprintConnectionDetailPage = () => {
       </S.Top>
       <Buttons position="top" align="left">
         <Button intent={Intent.PRIMARY} icon="annotation" text="Manage Data 
Scope" onClick={handleShowDataScope} />
+        <ExternalLink style={{ marginLeft: 8 }} 
link={`/connections/${connection.plugin}/${connection.id}`}>
+          <Button intent={Intent.PRIMARY} icon="annotation" text="Edit Scope 
Config" />
+        </ExternalLink>
       </Buttons>
       <Table columns={[{ title: 'Data Scope', dataIndex: 'name', key: 'name' 
}]} dataSource={scopes} />
       <Dialog
         isOpen={isOpen}
-        title="Change Data Scope"
+        title="Manage Data Scope"
         footer={null}
         style={{ width: 820 }}
         onCancel={handleHideDataScope}
@@ -161,6 +183,7 @@ export const BlueprintConnectionDetailPage = () => {
         <DataScopeSelect
           plugin={connection.plugin}
           connectionId={connection.id}
+          showWarning
           initialScope={scopes}
           onCancel={handleHideDataScope}
           onSubmit={handleChangeDataScope}
diff --git a/config-ui/src/pages/blueprint/detail/blueprint-detail-page.tsx 
b/config-ui/src/pages/blueprint/detail/blueprint-detail-page.tsx
index 997fa3e66..67a439d35 100644
--- a/config-ui/src/pages/blueprint/detail/blueprint-detail-page.tsx
+++ b/config-ui/src/pages/blueprint/detail/blueprint-detail-page.tsx
@@ -20,6 +20,8 @@ import { useParams } from 'react-router-dom';
 
 import { PageHeader } from '@/components';
 
+import { FromEnum } from '../types';
+
 import { BlueprintDetail } from './blueprint-detail';
 
 export const BlueprintDetailPage = () => {
@@ -28,11 +30,12 @@ export const BlueprintDetailPage = () => {
   return (
     <PageHeader
       breadcrumbs={[
+        { name: 'Advanced', path: '/blueprints' },
         { name: 'Blueprints', path: '/blueprints' },
-        // { name: blueprint.name, path: `/blueprints/${id}` },
+        { name: id, path: `/blueprints/${id}` },
       ]}
     >
-      <BlueprintDetail id={id} />
+      <BlueprintDetail id={id} from={FromEnum.blueprint} />
     </PageHeader>
   );
 };
diff --git a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx 
b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
index f3daee155..eb975bd67 100644
--- a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
+++ b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
@@ -17,13 +17,13 @@
  */
 
 import { useState } from 'react';
-import { useHistory } from 'react-router-dom';
 import type { TabId } from '@blueprintjs/core';
-import { Tabs, Tab, Switch, Button, Icon, Intent } from '@blueprintjs/core';
+import { Tabs, Tab } from '@blueprintjs/core';
 
-import { PageLoading, Dialog } from '@/components';
+import { PageLoading } from '@/components';
 import { useRefreshData } from '@/hooks';
-import { operator } from '@/utils';
+
+import { FromEnum } from '../types';
 
 import { ConfigurationPanel } from './configuration-panel';
 import { StatusPanel } from './status-panel';
@@ -32,76 +32,26 @@ import * as S from './styled';
 
 interface Props {
   id: ID;
+  from: FromEnum;
 }
 
-export const BlueprintDetail = ({ id }: Props) => {
-  const [activeTab, setActiveTab] = useState<TabId>('configuration');
+export const BlueprintDetail = ({ id, from }: Props) => {
+  const [activeTab, setActiveTab] = useState<TabId>(from === FromEnum.project 
? 'configuration' : 'status');
   const [version, setVersion] = useState(1);
-  const [operating, setOperating] = useState(false);
-  const [isOpen, setIsOpen] = useState(false);
-
-  const history = useHistory();
 
   const { ready, data } = useRefreshData(
     async () => Promise.all([API.getBlueprint(id), 
API.getBlueprintPipelines(id)]),
     [version],
   );
 
+  const handleRefresh = () => setVersion((v) => v + 1);
+
   if (!ready || !data) {
     return <PageLoading />;
   }
 
   const [blueprint, pipelines] = data;
 
-  const handleUpdate = async (payload: any, callback?: () => void) => {
-    const [success] = await operator(
-      () =>
-        API.updateBlueprint(id, {
-          ...blueprint,
-          ...payload,
-        }),
-      {
-        setOperating,
-        formatMessage: () => 'Update blueprint successful.',
-      },
-    );
-
-    if (success) {
-      setVersion((v) => v + 1);
-      callback?.();
-    }
-  };
-
-  const handleRun = async (skipCollectors: boolean) => {
-    const [success] = await operator(() => API.runBlueprint(id, 
skipCollectors), {
-      setOperating,
-      formatMessage: () => 'Trigger blueprint successful.',
-    });
-
-    if (success) {
-      setVersion((v) => v + 1);
-    }
-  };
-
-  const handleShowDeleteDialog = () => {
-    setIsOpen(true);
-  };
-
-  const handleHideDeleteDialog = () => {
-    setIsOpen(false);
-  };
-
-  const handleDelete = async () => {
-    const [success] = await operator(() => API.deleteBluprint(id), {
-      setOperating,
-      formatMessage: () => 'Delete blueprint successful.',
-    });
-
-    if (success) {
-      history.push('/blueprints');
-    }
-  };
-
   return (
     <S.Wrapper>
       <Tabs selectedTabId={activeTab} onChange={(at) => setActiveTab(at)}>
@@ -109,46 +59,15 @@ export const BlueprintDetail = ({ id }: Props) => {
           id="status"
           title="Status"
           panel={
-            <StatusPanel
-              blueprint={blueprint}
-              pipelineId={pipelines?.[0]?.id}
-              operating={operating}
-              onRun={handleRun}
-            />
+            <StatusPanel from={from} blueprint={blueprint} 
pipelineId={pipelines?.[0]?.id} onRefresh={handleRefresh} />
           }
         />
         <Tab
           id="configuration"
           title="Configuration"
-          panel={<ConfigurationPanel blueprint={blueprint} 
operating={operating} onUpdate={handleUpdate} />}
-        />
-        <Tabs.Expander />
-        <Switch
-          style={{ marginBottom: 0 }}
-          label="Blueprint Enabled"
-          checked={blueprint.enable}
-          onChange={(e) => handleUpdate({ enable: (e.target as 
HTMLInputElement).checked })}
+          panel={<ConfigurationPanel from={from} blueprint={blueprint} 
onRefresh={handleRefresh} />}
         />
-        <Button intent={Intent.DANGER} text="Delete Blueprint" 
onClick={handleShowDeleteDialog} />
       </Tabs>
-      <Dialog
-        isOpen={isOpen}
-        style={{ width: 820 }}
-        title="Are you sure you want to delete this Blueprint?"
-        okText="Confirm"
-        okLoading={operating}
-        onCancel={handleHideDeleteDialog}
-        onOk={handleDelete}
-      >
-        <S.DialogBody>
-          <Icon icon="warning-sign" />
-          <span>
-            Please note: deleting the Blueprint will not delete the historical 
data of the Data Scopes in this
-            Blueprint. If you would like to delete the historical data of Data 
Scopes, please visit the Connection page
-            and do so.
-          </span>
-        </S.DialogBody>
-      </Dialog>
     </S.Wrapper>
   );
 };
diff --git a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx 
b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
index a76f95655..ef15ae14a 100644
--- a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
+++ b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
@@ -21,25 +21,29 @@ import { Link } from 'react-router-dom';
 import { Button, Intent } from '@blueprintjs/core';
 
 import { IconButton, Table, NoData, Buttons } from '@/components';
+import { getCron } from '@/config';
 import { useConnections } from '@/hooks';
 import { getPluginConfig } from '@/plugins';
+import { formatTime, operator } from '@/utils';
 
-import type { BlueprintType } from '../types';
+import { BlueprintType, FromEnum } from '../types';
 import { ModeEnum } from '../types';
 import { validRawPlan } from '../utils';
 
 import { AdvancedEditor, UpdateNameDialog, UpdatePolicyDialog, 
AddConnectionDialog } from './components';
+import * as API from './api';
 import * as S from './styled';
 
 interface Props {
+  from: FromEnum;
   blueprint: BlueprintType;
-  operating: boolean;
-  onUpdate: (payload: any, callback?: () => void) => void;
+  onRefresh: () => void;
 }
 
-export const ConfigurationPanel = ({ blueprint, operating, onUpdate }: Props) 
=> {
+export const ConfigurationPanel = ({ from, blueprint, onRefresh }: Props) => {
   const [type, setType] = useState<'name' | 'policy' | 'add-connection'>();
   const [rawPlan, setRawPlan] = useState('');
+  const [operating, setOperating] = useState(false);
 
   useEffect(() => {
     setRawPlan(JSON.stringify(blueprint.plan, null, '  '));
@@ -83,6 +87,25 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
     setType('add-connection');
   };
 
+  const handleUpdate = async (payload: any) => {
+    const [success] = await operator(
+      () =>
+        API.updateBlueprint(blueprint.id, {
+          ...blueprint,
+          ...payload,
+        }),
+      {
+        setOperating,
+        formatMessage: () => 'Update blueprint successful.',
+      },
+    );
+
+    if (success) {
+      onRefresh();
+      handleCancel();
+    }
+  };
+
   return (
     <S.ConfigurationPanel>
       <div className="block">
@@ -103,22 +126,31 @@ export const ConfigurationPanel = ({ blueprint, 
operating, onUpdate }: Props) =>
               title: 'Data Time Range',
               dataIndex: 'timeRange',
               key: 'timeRange',
+              render: (val) => `${formatTime(val)} to Now`,
             },
             {
               title: 'Sync Frequency',
               dataIndex: 'frequency',
               key: 'frequency',
+              align: 'center',
+              render: (val, row) => {
+                const cron = getCron(row.isManual, val);
+                return `${cron.label}${cron.description}`;
+              },
             },
             {
               title: 'Skip Failed Tasks',
               dataIndex: 'skipFailed',
               key: 'skipFailed',
+              align: 'center',
+              render: (val) => (val ? 'Enabled' : 'Disabled'),
             },
           ]}
           dataSource={[
             {
               timeRange: blueprint.settings.timeAfter,
               frequency: blueprint.cronConfig,
+              isManual: blueprint.isManual,
               skipFailed: blueprint.skipOnFail,
             },
           ]}
@@ -165,7 +197,15 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
                       <span>{cs.scope.length} data scope</span>
                     </div>
                     <div className="link">
-                      <Link 
to={`/blueprints/${blueprint.id}/${cs.unique}`}>Edit Data Scope and Scope 
Config</Link>
+                      <Link
+                        to={
+                          from === FromEnum.blueprint
+                            ? `/blueprints/${blueprint.id}/${cs.unique}`
+                            : `/projects/${blueprint.projectName}/${cs.unique}`
+                        }
+                      >
+                        Edit Data Scope and Scope Config
+                      </Link>
                     </div>
                   </S.ConnectionItem>
                 ))}
@@ -183,7 +223,7 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
               intent={Intent.PRIMARY}
               text="Save"
               onClick={() =>
-                onUpdate({
+                handleUpdate({
                   plan: !validRawPlan(rawPlan) ? JSON.parse(rawPlan) : 
JSON.stringify([[]], null, '  '),
                 })
               }
@@ -196,7 +236,7 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
           name={blueprint.name}
           operating={operating}
           onCancel={handleCancel}
-          onSubmit={(name) => onUpdate({ name }, handleCancel)}
+          onSubmit={(name) => handleUpdate({ name })}
         />
       )}
       {type === 'policy' && (
@@ -208,7 +248,7 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
           timeAfter={blueprint.settings?.timeAfter}
           operating={operating}
           onCancel={handleCancel}
-          onSubmit={(payload) => onUpdate(payload, handleCancel)}
+          onSubmit={(payload) => handleUpdate(payload)}
         />
       )}
       {type === 'add-connection' && (
@@ -216,7 +256,7 @@ export const ConfigurationPanel = ({ blueprint, operating, 
onUpdate }: Props) =>
           disabled={connections.map((cs) => cs.unique)}
           onCancel={handleCancel}
           onSubmit={(connection) =>
-            onUpdate({
+            handleUpdate({
               settings: { ...blueprint.settings, connections: 
[...blueprint.settings.connections, connection] },
             })
           }
diff --git a/config-ui/src/pages/blueprint/detail/status-panel.tsx 
b/config-ui/src/pages/blueprint/detail/status-panel.tsx
index 756e4b3f1..bf672b2b2 100644
--- a/config-ui/src/pages/blueprint/detail/status-panel.tsx
+++ b/config-ui/src/pages/blueprint/detail/status-panel.tsx
@@ -16,53 +16,133 @@
  *
  */
 
-import { useMemo } from 'react';
-import { Button, Intent, Position } from '@blueprintjs/core';
+import { useState, useMemo } from 'react';
+import { useHistory } from 'react-router-dom';
+import { Button, Switch, Icon, Intent, Position } from '@blueprintjs/core';
 import { Tooltip2 } from '@blueprintjs/popover2';
 
-import { Card } from '@/components';
+import { Card, IconButton, Dialog } from '@/components';
 import { getCron } from '@/config';
 import { PipelineContextProvider, PipelineInfo, PipelineTasks, 
PipelineHistorical } from '@/pages';
-import { formatTime } from '@/utils';
+import { formatTime, operator } from '@/utils';
 
-import type { BlueprintType } from '../types';
+import { BlueprintType, FromEnum } from '../types';
 
+import * as API from './api';
 import * as S from './styled';
 
 interface Props {
+  from: FromEnum;
   blueprint: BlueprintType;
   pipelineId?: ID;
-  operating: boolean;
-  onRun: (skipCollectors: boolean) => void;
+  onRefresh: () => void;
 }
 
-export const StatusPanel = ({ blueprint, pipelineId, operating, onRun }: 
Props) => {
+export const StatusPanel = ({ from, blueprint, pipelineId, onRefresh }: Props) 
=> {
+  const [isOpen, setIsOpen] = useState(false);
+  const [operating, setOperating] = useState(false);
+
+  const history = useHistory();
+
   const cron = useMemo(() => getCron(blueprint.isManual, 
blueprint.cronConfig), [blueprint]);
 
+  const handleShowDeleteDialog = () => {
+    setIsOpen(true);
+  };
+
+  const handleHideDeleteDialog = () => {
+    setIsOpen(false);
+  };
+
+  const handleRun = async (skipCollectors: boolean) => {
+    const [success] = await operator(() => API.runBlueprint(blueprint.id, 
skipCollectors), {
+      setOperating,
+      formatMessage: () => 'Trigger blueprint successful.',
+    });
+
+    if (success) {
+      onRefresh();
+    }
+  };
+
+  const handleUpdate = async (payload: any) => {
+    const [success] = await operator(
+      () =>
+        API.updateBlueprint(blueprint.id, {
+          ...blueprint,
+          ...payload,
+        }),
+      {
+        setOperating,
+        formatMessage: () => 'Update blueprint successful.',
+      },
+    );
+
+    if (success) {
+      onRefresh();
+    }
+  };
+
+  const handleDelete = async () => {
+    const [success] = await operator(() => API.deleteBluprint(blueprint.id), {
+      setOperating,
+      formatMessage: () => 'Delete blueprint successful.',
+    });
+
+    if (success) {
+      history.push('/blueprints');
+    }
+  };
+
   return (
     <S.StatusPanel>
-      <div className="info">
-        <span>{cron.value === 'manual' ? 'Manual' : `Next Run: 
${formatTime(cron.nextTime, 'YYYY-MM-DD HH:mm')}`}</span>
-        <Tooltip2
-          position={Position.TOP}
-          content="It is recommended to re-transform your data in this project 
if you have updated the transformation of the data scope in this project."
-        >
+      {from === FromEnum.project && (
+        <S.ProjectACtion>
+          <span>
+            {cron.value === 'manual' ? 'Manual' : `Next Run: 
${formatTime(cron.nextTime, 'YYYY-MM-DD HH:mm')}`}
+          </span>
+          <Tooltip2
+            position={Position.TOP}
+            content="It is recommended to re-transform your data in this 
project if you have updated the transformation of the data scope in this 
project."
+          >
+            <Button
+              disabled={!blueprint.enable}
+              loading={operating}
+              intent={Intent.PRIMARY}
+              text="Re-transform Data"
+              onClick={() => handleRun(true)}
+            />
+          </Tooltip2>
           <Button
             disabled={!blueprint.enable}
             loading={operating}
             intent={Intent.PRIMARY}
-            text="Re-transform Data"
-            onClick={() => onRun(true)}
+            text="Collect All Data"
+            onClick={() => handleRun(false)}
+          />
+        </S.ProjectACtion>
+      )}
+
+      {from === FromEnum.blueprint && (
+        <S.BlueprintAction>
+          <Button text="Run Now" onClick={() => handleRun(false)} />
+          <Switch
+            style={{ marginBottom: 0 }}
+            label="Blueprint Enabled"
+            disabled={!!blueprint.projectName}
+            checked={blueprint.enable}
+            onChange={(e) => handleUpdate({ enable: (e.target as 
HTMLInputElement).checked })}
           />
-        </Tooltip2>
-        <Button
-          disabled={!blueprint.enable}
-          loading={operating}
-          intent={Intent.PRIMARY}
-          text="Collect All Data"
-          onClick={() => onRun(false)}
-        />
-      </div>
+          <IconButton
+            loading={operating}
+            disabled={!!blueprint.projectName}
+            icon="trash"
+            tooltip="Delete Blueprint"
+            onClick={handleShowDeleteDialog}
+          />
+        </S.BlueprintAction>
+      )}
+
       <PipelineContextProvider>
         <div className="block">
           <h3>Current Pipeline</h3>
@@ -82,6 +162,25 @@ export const StatusPanel = ({ blueprint, pipelineId, 
operating, onRun }: Props)
           <PipelineHistorical blueprintId={blueprint.id} />
         </div>
       </PipelineContextProvider>
+
+      <Dialog
+        isOpen={isOpen}
+        style={{ width: 820 }}
+        title="Are you sure you want to delete this Blueprint?"
+        okText="Confirm"
+        okLoading={operating}
+        onCancel={handleHideDeleteDialog}
+        onOk={handleDelete}
+      >
+        <S.DialogBody>
+          <Icon icon="warning-sign" />
+          <span>
+            Please note: deleting the Blueprint will not delete the historical 
data of the Data Scopes in this
+            Blueprint. If you would like to delete the historical data of Data 
Scopes, please visit the Connection page
+            and do so.
+          </span>
+        </S.DialogBody>
+      </Dialog>
     </S.StatusPanel>
   );
 };
diff --git a/config-ui/src/pages/blueprint/detail/styled.ts 
b/config-ui/src/pages/blueprint/detail/styled.ts
index a7caedb95..cc28fb174 100644
--- a/config-ui/src/pages/blueprint/detail/styled.ts
+++ b/config-ui/src/pages/blueprint/detail/styled.ts
@@ -88,17 +88,27 @@ export const StatusPanel = styled.div`
     margin-bottom: 16px;
   }
 
-  & > .info {
-    display: flex;
-    justify-content: flex-end;
-    align-items: center;
+  .block + .block {
+    margin-top: 32px;
+  }
+`;
 
-    & > * {
-      margin-left: 16px;
-    }
+export const ProjectACtion = styled.div`
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+
+  & > * {
+    margin-left: 16px;
   }
+`;
 
-  .block + .block {
-    margin-top: 32px;
+export const BlueprintAction = styled.div`
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  & > .bp4-switch {
+    margin: 0 8px;
   }
 `;
diff --git a/config-ui/src/pages/blueprint/types.ts 
b/config-ui/src/pages/blueprint/types.ts
index ca87e5d6a..2c498e9c4 100644
--- a/config-ui/src/pages/blueprint/types.ts
+++ b/config-ui/src/pages/blueprint/types.ts
@@ -21,7 +21,13 @@ export enum ModeEnum {
   normal = 'NORMAL',
 }
 
+export enum FromEnum {
+  project = 'PROJECT',
+  blueprint = 'BLUEPRINT',
+}
+
 export type BlueprintType = {
+  projectName: string;
   id: ID;
   enable: boolean;
   name: string;
diff --git a/config-ui/src/pages/connection/detail/index.tsx 
b/config-ui/src/pages/connection/detail/index.tsx
index 12be3e8c3..a7c096ddb 100644
--- a/config-ui/src/pages/connection/detail/index.tsx
+++ b/config-ui/src/pages/connection/detail/index.tsx
@@ -16,7 +16,7 @@
  *
  */
 
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
 import { useParams, useHistory } from 'react-router-dom';
 import { Button, Icon, Intent } from '@blueprintjs/core';
 
@@ -35,12 +35,7 @@ import { operator } from '@/utils';
 import * as API from './api';
 import * as S from './styled';
 
-interface Props {
-  plugin: string;
-  id: ID;
-}
-
-const ConnectionDetail = ({ plugin, id }: Props) => {
+export const ConnectionDetailPage = () => {
   const [type, setType] = useState<
     | 'deleteConnection'
     | 'updateConnection'
@@ -55,12 +50,17 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
   const [scopeIds, setScopeIds] = useState<ID[]>([]);
   const [scopeConfigId, setScopeConfigId] = useState<ID>();
 
+  const { plugin, id } = useParams<{ plugin: string; id: string }>();
   const history = useHistory();
   const { onGet, onTest, onRefresh } = useConnections();
   const { setTips } = useTips();
   const { ready, data } = useRefreshData(() => API.getDataScopes(plugin, id), 
[version]);
 
-  const { unique, status, name, icon } = onGet(`${plugin}-${id}`);
+  const { unique, status, name, icon } = onGet(`${plugin}-${id}`) || {};
+
+  useEffect(() => {
+    onTest(`${plugin}-${id}`);
+  }, [plugin, id]);
 
   const handleHideDialog = () => {
     setType(undefined);
@@ -89,6 +89,7 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
     });
 
     if (success) {
+      onRefresh(plugin);
       history.push('/connections');
     }
   };
@@ -175,15 +176,19 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
       extra={<Button intent={Intent.DANGER} icon="trash" text="Delete 
Connection" onClick={handleShowDeleteDialog} />}
     >
       <S.Wrapper>
-        <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 className="top">
+          <div>Please note: In order to view DORA metrics, you will need to 
add Scope Configs.</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>
         <Buttons position="top" align="left">
           <Button intent={Intent.PRIMARY} icon="add" text="Add Data Scope" 
onClick={handleShowCreateDataScopeDialog} />
           {plugin !== 'tapd' && (
             <Button
+              disabled={!scopeIds.length}
               intent={Intent.PRIMARY}
               icon="many-to-one"
               text="Associate Scope Config"
@@ -370,9 +375,3 @@ const ConnectionDetail = ({ plugin, id }: Props) => {
     </PageHeader>
   );
 };
-
-export const ConnectionDetailPage = () => {
-  const { plugin, id } = useParams<{ plugin: string; id: string }>();
-
-  return <ConnectionDetail plugin={plugin} id={+id} />;
-};
diff --git a/config-ui/src/pages/connection/detail/styled.ts 
b/config-ui/src/pages/connection/detail/styled.ts
index 8a166f523..8d79884eb 100644
--- a/config-ui/src/pages/connection/detail/styled.ts
+++ b/config-ui/src/pages/connection/detail/styled.ts
@@ -19,6 +19,13 @@
 import styled from 'styled-components';
 
 export const Wrapper = styled.div`
+  .top {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 24px;
+  }
+
   .authentication {
     display: flex;
     align-items: center;
diff --git a/config-ui/src/pages/connection/home/index.tsx 
b/config-ui/src/pages/connection/home/index.tsx
index 9613bfca5..2bc644ca9 100644
--- a/config-ui/src/pages/connection/home/index.tsx
+++ b/config-ui/src/pages/connection/home/index.tsx
@@ -17,21 +17,22 @@
  */
 
 import { useState, useMemo } from 'react';
+import { useHistory } from 'react-router-dom';
 import { Tag, Intent } from '@blueprintjs/core';
 
 import { Dialog } from '@/components';
 import { useConnections } from '@/hooks';
 import type { PluginConfigType } from '@/plugins';
 import { PluginConfig, PluginType, ConnectionList, ConnectionForm } from 
'@/plugins';
-import { ConnectionContextProvider } from '@/store';
 
 import * as S from './styled';
 
-export const ConnectionHome = () => {
+export const ConnectionHomePage = () => {
   const [type, setType] = useState<'list' | 'form'>();
   const [pluginConfig, setPluginConfig] = useState<PluginConfigType>();
 
   const { connections, onRefresh } = useConnections();
+  const history = useHistory();
 
   const [plugins, webhook] = useMemo(
     () => [
@@ -61,9 +62,9 @@ export const ConnectionHome = () => {
     setPluginConfig(undefined);
   };
 
-  const handleCreateSuccess = async (plugin: string) => {
+  const handleCreateSuccess = async (plugin: string, id: ID) => {
     onRefresh(plugin);
-    setType('list');
+    history.push(`/connections/${plugin}/${id}`);
   };
 
   return (
@@ -138,17 +139,12 @@ export const ConnectionHome = () => {
           footer={null}
           onCancel={handleHideDialog}
         >
-          <ConnectionForm plugin={pluginConfig.plugin} onSuccess={() => 
handleCreateSuccess(pluginConfig.plugin)} />
+          <ConnectionForm
+            plugin={pluginConfig.plugin}
+            onSuccess={(id) => handleCreateSuccess(pluginConfig.plugin, id)}
+          />
         </Dialog>
       )}
     </S.Wrapper>
   );
 };
-
-export const ConnectionHomePage = () => {
-  return (
-    <ConnectionContextProvider>
-      <ConnectionHome />
-    </ConnectionContextProvider>
-  );
-};
diff --git a/config-ui/src/pages/project/detail/api.ts 
b/config-ui/src/pages/project/detail/api.ts
index a222dda7f..bc8fdaca4 100644
--- a/config-ui/src/pages/project/detail/api.ts
+++ b/config-ui/src/pages/project/detail/api.ts
@@ -29,7 +29,10 @@ export const updateProject = (name: string, payload: 
Omit<ProjectType, 'blueprin
   });
 
 export const updateBlueprint = (id: ID, payload: BlueprintType) =>
-  request(`/blueprints/${id}`, { method: 'patch', data: payload });
+  request(`/blueprints/${id}`, {
+    method: 'patch',
+    data: payload,
+  });
 
 export const deleteProject = (name: string) =>
   request(`/projects/${name}`, {
diff --git a/config-ui/src/pages/project/detail/index.tsx 
b/config-ui/src/pages/project/detail/index.tsx
index 4db19c51c..6a98974ff 100644
--- a/config-ui/src/pages/project/detail/index.tsx
+++ b/config-ui/src/pages/project/detail/index.tsx
@@ -22,7 +22,7 @@ import { Tabs, Tab } from '@blueprintjs/core';
 
 import { PageHeader, PageLoading } from '@/components';
 import { useRefreshData } from '@/hooks';
-import { BlueprintDetail } from '@/pages';
+import { BlueprintDetail, FromEnum } from '@/pages';
 
 import { WebhooksPanel } from './webhooks-panel';
 import { SettingsPanel } from './settings-panel';
@@ -71,7 +71,11 @@ export const ProjectDetailPage = () => {
     >
       <S.Wrapper>
         <Tabs selectedTabId={tabId} onChange={handleChangeTabId}>
-          <Tab id="blueprint" title="Blueprint" panel={<BlueprintDetail 
id={project.blueprint.id} />} />
+          <Tab
+            id="blueprint"
+            title="Blueprint"
+            panel={<BlueprintDetail id={project.blueprint.id} 
from={FromEnum.project} />}
+          />
           <Tab
             id="webhook"
             title="Incoming Webhooks"
diff --git a/config-ui/src/plugins/components/connection-form/index.tsx 
b/config-ui/src/plugins/components/connection-form/index.tsx
index 6ea9d89c6..bfb594fef 100644
--- a/config-ui/src/plugins/components/connection-form/index.tsx
+++ b/config-ui/src/plugins/components/connection-form/index.tsx
@@ -32,7 +32,7 @@ import * as S from './styled';
 interface Props {
   plugin: string;
   connectionId?: ID;
-  onSuccess?: () => void;
+  onSuccess?: (id: ID) => void;
 }
 
 export const ConnectionForm = ({ plugin, connectionId, onSuccess }: Props) => {
@@ -83,7 +83,7 @@ export const ConnectionForm = ({ plugin, connectionId, 
onSuccess }: Props) => {
   };
 
   const handleSave = async () => {
-    const [success] = await operator(
+    const [success, res] = await operator(
       () => (!connectionId ? API.createConnection(plugin, values) : 
API.updateConnection(plugin, connectionId, values)),
       {
         setOperating,
@@ -92,7 +92,7 @@ export const ConnectionForm = ({ plugin, connectionId, 
onSuccess }: Props) => {
     );
 
     if (success) {
-      onSuccess?.();
+      onSuccess?.(res.id);
     }
   };
 
diff --git a/config-ui/src/plugins/components/connection-list/index.tsx 
b/config-ui/src/plugins/components/connection-list/index.tsx
index 6e5fe4042..aa439d8db 100644
--- a/config-ui/src/plugins/components/connection-list/index.tsx
+++ b/config-ui/src/plugins/components/connection-list/index.tsx
@@ -55,6 +55,7 @@ const BaseList = ({ plugin, onCreate }: Props) => {
             title: 'Status',
             dataIndex: ['status', 'unique'],
             key: 'status',
+            width: 150,
             render: ({ status, unique }) => <ConnectionStatus status={status} 
unique={unique} onTest={onTest} />,
           },
           {
diff --git a/config-ui/src/plugins/components/data-scope-select/index.tsx 
b/config-ui/src/plugins/components/data-scope-select/index.tsx
index 4a3730972..b1005a787 100644
--- a/config-ui/src/plugins/components/data-scope-select/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select/index.tsx
@@ -19,7 +19,7 @@
 import { useState, useEffect } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
-import { PageLoading, FormItem, ExternalLink, Buttons, Table } from 
'@/components';
+import { PageLoading, FormItem, ExternalLink, Message, Buttons, Table } from 
'@/components';
 import { useRefreshData } from '@/hooks';
 import { getPluginId } from '@/plugins';
 
@@ -29,20 +29,31 @@ import * as S from './styled';
 interface Props {
   plugin: string;
   connectionId: ID;
+  showWarning?: boolean;
   initialScope?: any[];
   onCancel?: () => void;
   onSubmit?: (scope: any) => void;
 }
 
-export const DataScopeSelect = ({ plugin, connectionId, initialScope, 
onSubmit, onCancel }: Props) => {
+export const DataScopeSelect = ({
+  plugin,
+  connectionId,
+  showWarning = false,
+  initialScope,
+  onSubmit,
+  onCancel,
+}: Props) => {
+  const [version, setVersion] = useState(1);
   const [scopeIds, setScopeIds] = useState<ID[]>([]);
 
-  const { ready, data } = useRefreshData(() => API.getDataScope(plugin, 
connectionId));
+  const { ready, data } = useRefreshData(() => API.getDataScope(plugin, 
connectionId), [version]);
 
   useEffect(() => {
     setScopeIds((initialScope ?? data ?? []).map((sc: any) => 
sc[getPluginId(plugin)]) ?? []);
   }, [data]);
 
+  const handleRefresh = () => setVersion((v) => v + 1);
+
   const handleSubmit = () => {
     const scope = data.filter((it: any) => 
scopeIds.includes(it[getPluginId(plugin)]));
     onSubmit?.(scope);
@@ -76,9 +87,23 @@ export const DataScopeSelect = ({ plugin, connectionId, 
initialScope, onSubmit,
     >
       {data.length ? (
         <S.Wrapper>
-          <Buttons position="top" align="left">
-            <Button intent={Intent.PRIMARY} icon="refresh" text="Refresh Data 
Scope" />
-          </Buttons>
+          {showWarning ? (
+            <Message
+              style={{ marginBottom: 24 }}
+              content={
+                <>
+                  Unchecking Data Scope below will only remove it from the 
current Project and will not delete the
+                  historical data. If you would like to delete the data of 
Data Scope, please{' '}
+                  <ExternalLink 
link={`/connections/${plugin}/${connectionId}`}>go to the Connection 
page</ExternalLink>
+                  .
+                </>
+              }
+            />
+          ) : (
+            <Buttons position="top" align="left">
+              <Button intent={Intent.PRIMARY} icon="refresh" text="Refresh 
Data Scope" onClick={handleRefresh} />
+            </Buttons>
+          )}
           <Table
             noShadow
             loading={!ready}
diff --git a/config-ui/src/plugins/components/scope-config-form/index.tsx 
b/config-ui/src/plugins/components/scope-config-form/index.tsx
index 0637d2ee9..e46daf1da 100644
--- a/config-ui/src/plugins/components/scope-config-form/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-form/index.tsx
@@ -20,7 +20,7 @@ import { useState, useEffect, useMemo } from 'react';
 import { omit } from 'lodash';
 import { InputGroup, Button, Intent } from '@blueprintjs/core';
 
-import { Alert, ExternalLink, Card, FormItem, MultiSelector, Buttons, Divider 
} from '@/components';
+import { Alert, ExternalLink, Card, FormItem, MultiSelector, Message, Buttons, 
Divider } from '@/components';
 import { transformEntities, EntitiesLabel } from '@/config';
 import { getPluginConfig } from '@/plugins';
 import { GitHubTransformation } from '@/plugins/register/github';
@@ -40,13 +40,22 @@ import * as S from './styled';
 interface Props {
   plugin: string;
   connectionId: ID;
+  showWarning?: boolean;
   scopeId?: ID;
   scopeConfigId?: ID;
   onCancel?: () => void;
   onSubmit?: (trId: string) => void;
 }
 
-export const ScopeConfigForm = ({ plugin, connectionId, scopeId, 
scopeConfigId, onCancel, onSubmit }: Props) => {
+export const ScopeConfigForm = ({
+  plugin,
+  connectionId,
+  showWarning = false,
+  scopeId,
+  scopeConfigId,
+  onCancel,
+  onSubmit,
+}: Props) => {
   const [step, setStep] = useState(1);
   const [name, setName] = useState('');
   const [entities, setEntities] = useState<string[]>([]);
@@ -60,6 +69,10 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
     setHasRefDiff(!!config.transformation.refdiff);
   }, [config.transformation]);
 
+  useEffect(() => {
+    setEntities(config.entities);
+  }, [config.entities]);
+
   useEffect(() => {
     if (!scopeConfigId) return;
 
@@ -73,6 +86,10 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
     })();
   }, [scopeConfigId]);
 
+  const handlePrevStep = () => {
+    setStep(1);
+  };
+
   const handleNextStep = () => {
     setStep(2);
   };
@@ -133,6 +150,13 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
                 onChangeItems={(its) => setEntities(its.map((it) => it.value))}
               />
             </FormItem>
+            {showWarning && (
+              <Message
+                content="Please note: if you edit Data Entities and expect to 
see the Dashboards updated, you will need to visit
+                  the Project page of the Data Scope that has been associated 
with this Scope Config and click on “Collect
+                  All Data”."
+              />
+            )}
           </Card>
           <Buttons>
             <Button outlined intent={Intent.PRIMARY} text="Cancel" 
onClick={onCancel} />
@@ -143,12 +167,24 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
       {step === 2 && (
         <>
           <Card>
+            {showWarning && (
+              <>
+                <Message content="Please note: if you only edit the following 
Scope Configs without editing Data Entities in the previous step, you will only 
need to re-transform data on the Project page to see the Dashboard updated." />
+                <Divider />
+              </>
+            )}
+
             {plugin === 'github' && (
-              <GitHubTransformation transformation={transformation} 
setTransformation={setTransformation} />
+              <GitHubTransformation
+                entities={entities}
+                transformation={transformation}
+                setTransformation={setTransformation}
+              />
             )}
 
             {plugin === 'jira' && (
               <JiraTransformation
+                entities={entities}
                 connectionId={connectionId}
                 transformation={transformation}
                 setTransformation={setTransformation}
@@ -156,23 +192,40 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
             )}
 
             {plugin === 'gitlab' && (
-              <GitLabTransformation transformation={transformation} 
setTransformation={setTransformation} />
+              <GitLabTransformation
+                entities={entities}
+                transformation={transformation}
+                setTransformation={setTransformation}
+              />
             )}
 
             {plugin === 'jenkins' && (
-              <JenkinsTransformation transformation={transformation} 
setTransformation={setTransformation} />
+              <JenkinsTransformation
+                entities={entities}
+                transformation={transformation}
+                setTransformation={setTransformation}
+              />
             )}
 
             {plugin === 'bitbucket' && (
-              <BitbucketTransformation transformation={transformation} 
setTransformation={setTransformation} />
+              <BitbucketTransformation
+                entities={entities}
+                transformation={transformation}
+                setTransformation={setTransformation}
+              />
             )}
 
             {plugin === 'azuredevops' && (
-              <AzureTransformation transformation={transformation} 
setTransformation={setTransformation} />
+              <AzureTransformation
+                entities={entities}
+                transformation={transformation}
+                setTransformation={setTransformation}
+              />
             )}
 
             {plugin === 'tapd' && scopeId && (
               <TapdTransformation
+                entities={entities}
                 connectionId={connectionId}
                 scopeId={scopeId}
                 transformation={transformation}
@@ -180,15 +233,10 @@ export const ScopeConfigForm = ({ plugin, connectionId, 
scopeId, scopeConfigId,
               />
             )}
 
-            {hasRefDiff && (
-              <>
-                <Divider />
-                <AdditionalSettings transformation={transformation} 
setTransformation={setTransformation} />
-              </>
-            )}
+            {hasRefDiff && <AdditionalSettings transformation={transformation} 
setTransformation={setTransformation} />}
           </Card>
           <Buttons>
-            <Button outlined intent={Intent.PRIMARY} text="Cancel" 
onClick={onCancel} />
+            <Button outlined intent={Intent.PRIMARY} text="Prev" 
onClick={handlePrevStep} />
             <Button loading={operating} intent={Intent.PRIMARY} text="Save" 
onClick={handleSubmit} />
           </Buttons>
         </>
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 18fbcb6bd..3cba0b5bf 100644
--- a/config-ui/src/plugins/components/scope-config-select/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-select/index.tsx
@@ -50,6 +50,7 @@ export const ScopeConfigSelect = ({ plugin, connectionId, 
onCancel, onSubmit }:
 
   const handleHideDialog = () => {
     setIsOpen(false);
+    setUpdatedId(undefined);
   };
 
   const handleUpdate = async (id: ID) => {
@@ -92,10 +93,17 @@ export const ScopeConfigSelect = ({ plugin, connectionId, 
onCancel, onSubmit }:
         <Button outlined intent={Intent.PRIMARY} text="Cancel" 
onClick={onCancel} />
         <Button disabled={!trId} intent={Intent.PRIMARY} text="Save" 
onClick={() => trId && onSubmit?.(trId)} />
       </Buttons>
-      <Dialog style={{ width: 820 }} footer={null} isOpen={isOpen} title="Add 
Scope Config" onCancel={handleHideDialog}>
+      <Dialog
+        style={{ width: 820 }}
+        footer={null}
+        isOpen={isOpen}
+        title={!updatedId ? 'Add Scope Config' : 'Edit Scope Config'}
+        onCancel={handleHideDialog}
+      >
         <ScopeConfigForm
           plugin={plugin}
           connectionId={connectionId}
+          showWarning={!!updatedId}
           scopeConfigId={updatedId}
           onCancel={onCancel}
           onSubmit={handleSubmit}
diff --git a/config-ui/src/plugins/register/azure/transformation.tsx 
b/config-ui/src/plugins/register/azure/transformation.tsx
index 47205e82e..e5bebbd2b 100644
--- a/config-ui/src/plugins/register/azure/transformation.tsx
+++ b/config-ui/src/plugins/register/azure/transformation.tsx
@@ -24,11 +24,12 @@ import { ExternalLink, HelpTooltip } from '@/components';
 import * as S from './styled';
 
 interface Props {
+  entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const AzureTransformation = ({ transformation, setTransformation }: 
Props) => {
+export const AzureTransformation = ({ entities, transformation, 
setTransformation }: Props) => {
   const [enableCICD, setEnableCICD] = useState(true);
 
   useEffect(() => {
@@ -53,66 +54,68 @@ export const AzureTransformation = ({ transformation, 
setTransformation }: Props
 
   return (
     <S.Transfromation>
-      <S.CICD>
-        <h2>CI/CD</h2>
-        <h3>
-          <span>Deployment</span>
-          <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
-            DORA
-          </Tag>
-          <div className="switch">
-            <span>Enable</span>
-            <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
-          </div>
-        </h3>
-        {enableCICD && (
-          <>
-            <p>
-              Use Regular Expression to define Deployments in DevLake in order 
to measure DORA metrics.{' '}
-              <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
-                Learn more
-              </ExternalLink>
-            </p>
-            <div style={{ marginTop: 16 }}>Convert a Azure Pipeline Run as a 
DevLake Deployment when: </div>
-            <div className="text">
-              <span>
-                The name of the <strong>Azure pipeline</strong> or <strong>one 
of its jobs</strong> matches
-              </span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                placeholder="(deploy|push-image)"
-                value={transformation.deploymentPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    deploymentPattern: e.target.value,
-                    productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
-                  })
-                }
-              />
-              <i style={{ color: '#E34040' }}>*</i>
-              <HelpTooltip content="Azure Pipelines: 
https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?view=azure-devops#continuous-testing";
 />
+      {entities.includes('CICD') && (
+        <S.CICD>
+          <h2>CI/CD</h2>
+          <h3>
+            <span>Deployment</span>
+            <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
+              DORA
+            </Tag>
+            <div className="switch">
+              <span>Enable</span>
+              <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
             </div>
-            <div className="text">
-              <span>If the name also matches</span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                disabled={!transformation.deploymentPattern}
-                placeholder="prod(.*)"
-                value={transformation.productionPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    productionPattern: e.target.value,
-                  })
-                }
-              />
-              <span>, this Deployment is a ‘Production Deployment’</span>
-              <HelpTooltip content="If you leave this field empty, all DevLake 
Deployments will be tagged as in the Production environment. " />
-            </div>
-          </>
-        )}
-      </S.CICD>
+          </h3>
+          {enableCICD && (
+            <>
+              <p>
+                Use Regular Expression to define Deployments in DevLake in 
order to measure DORA metrics.{' '}
+                <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
+                  Learn more
+                </ExternalLink>
+              </p>
+              <div style={{ marginTop: 16 }}>Convert a Azure Pipeline Run as a 
DevLake Deployment when: </div>
+              <div className="text">
+                <span>
+                  The name of the <strong>Azure pipeline</strong> or 
<strong>one of its jobs</strong> matches
+                </span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  placeholder="(deploy|push-image)"
+                  value={transformation.deploymentPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      deploymentPattern: e.target.value,
+                      productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
+                    })
+                  }
+                />
+                <i style={{ color: '#E34040' }}>*</i>
+                <HelpTooltip content="Azure Pipelines: 
https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?view=azure-devops#continuous-testing";
 />
+              </div>
+              <div className="text">
+                <span>If the name also matches</span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  disabled={!transformation.deploymentPattern}
+                  placeholder="prod(.*)"
+                  value={transformation.productionPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      productionPattern: e.target.value,
+                    })
+                  }
+                />
+                <span>, this Deployment is a ‘Production Deployment’</span>
+                <HelpTooltip content="If you leave this field empty, all 
DevLake Deployments will be tagged as in the Production environment. " />
+              </div>
+            </>
+          )}
+        </S.CICD>
+      )}
     </S.Transfromation>
   );
 };
diff --git a/config-ui/src/plugins/register/bitbucket/transformation.tsx 
b/config-ui/src/plugins/register/bitbucket/transformation.tsx
index 2a13cb554..0dc647035 100644
--- a/config-ui/src/plugins/register/bitbucket/transformation.tsx
+++ b/config-ui/src/plugins/register/bitbucket/transformation.tsx
@@ -25,13 +25,14 @@ import ExampleJpg from './assets/bitbucket-example.jpg';
 import * as S from './styled';
 
 interface Props {
+  entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
 const ALL_STATES = ['new', 'open', 'resolved', 'closed', 'on hold', 'wontfix', 
'duplicate', 'invalid'];
 
-export const BitbucketTransformation = ({ transformation, setTransformation }: 
Props) => {
+export const BitbucketTransformation = ({ entities, transformation, 
setTransformation }: Props) => {
   const [useCustom, setUseCustom] = useState(false);
 
   useEffect(() => {
@@ -68,134 +69,136 @@ export const BitbucketTransformation = ({ transformation, 
setTransformation }: P
 
   return (
     <S.Transformation>
-      {/* Issue Tracking */}
-      <div className="issue-tracking">
-        <h2>Issue Tracking</h2>
-        <div className="issue-type">
-          <div className="title">
-            <span>Issue Status Mapping</span>
-            <HelpTooltip content="Standardize your issue statuses to the 
following issue statuses to view metrics such as `Requirement Delivery Rate` in 
built-in dashboards." />
+      {entities.includes('TICKET') && (
+        <div className="issue-tracking">
+          <h2>Issue Tracking</h2>
+          <div className="issue-type">
+            <div className="title">
+              <span>Issue Status Mapping</span>
+              <HelpTooltip content="Standardize your issue statuses to the 
following issue statuses to view metrics such as `Requirement Delivery Rate` in 
built-in dashboards." />
+            </div>
+            <div className="list">
+              <FormGroup inline label="TODO">
+                <MultiSelector
+                  items={ALL_STATES}
+                  disabledItems={selectedStates}
+                  selectedItems={transformation.issueStatusTodo ? 
transformation.issueStatusTodo.split(',') : []}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      issueStatusTodo: selectedItems.join(','),
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="IN-PROGRESS">
+                <MultiSelector
+                  items={ALL_STATES}
+                  disabledItems={selectedStates}
+                  selectedItems={
+                    transformation.issueStatusInProgress ? 
transformation.issueStatusInProgress.split(',') : []
+                  }
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      issueStatusInProgress: selectedItems.join(','),
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="DONE">
+                <MultiSelector
+                  items={ALL_STATES}
+                  disabledItems={selectedStates}
+                  selectedItems={transformation.issueStatusDone ? 
transformation.issueStatusDone.split(',') : []}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      issueStatusDone: selectedItems.join(','),
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="OTHER">
+                <MultiSelector
+                  items={ALL_STATES}
+                  disabledItems={selectedStates}
+                  selectedItems={transformation.issueStatusOther ? 
transformation.issueStatusOther.split(',') : []}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      issueStatusOther: selectedItems.join(','),
+                    })
+                  }
+                />
+              </FormGroup>
+            </div>
           </div>
-          <div className="list">
-            <FormGroup inline label="TODO">
-              <MultiSelector
-                items={ALL_STATES}
-                disabledItems={selectedStates}
-                selectedItems={transformation.issueStatusTodo ? 
transformation.issueStatusTodo.split(',') : []}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    issueStatusTodo: selectedItems.join(','),
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="IN-PROGRESS">
-              <MultiSelector
-                items={ALL_STATES}
-                disabledItems={selectedStates}
-                selectedItems={
-                  transformation.issueStatusInProgress ? 
transformation.issueStatusInProgress.split(',') : []
-                }
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    issueStatusInProgress: selectedItems.join(','),
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="DONE">
-              <MultiSelector
-                items={ALL_STATES}
-                disabledItems={selectedStates}
-                selectedItems={transformation.issueStatusDone ? 
transformation.issueStatusDone.split(',') : []}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    issueStatusDone: selectedItems.join(','),
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="OTHER">
-              <MultiSelector
-                items={ALL_STATES}
-                disabledItems={selectedStates}
-                selectedItems={transformation.issueStatusOther ? 
transformation.issueStatusOther.split(',') : []}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    issueStatusOther: selectedItems.join(','),
-                  })
-                }
-              />
-            </FormGroup>
-          </div>
-        </div>
-      </div>
-      <Divider />
-      {/* CI/CD */}
-      <S.CICD>
-        <h2>CI/CD</h2>
-        <h3>
-          <span>Deployment</span>
-          <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
-            DORA
-          </Tag>
-        </h3>
-        <p style={{ marginBottom: 16 }}>
-          Use Regular Expression to define Deployments in DevLake in order to 
measure DORA metrics.{' '}
-          <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
-            Learn more
-          </ExternalLink>
-        </p>
-        <div className="text">
-          <Checkbox disabled checked />
-          <span>Convert a BitBucket Deployment to a DevLake Deployment </span>
-          <HelpTooltip content={<img src={ExampleJpg} alt="" width={400} />} />
-        </div>
-        <div className="text">
-          <Checkbox checked={useCustom} onChange={handleChangeUseCustom} />
-          <span>
-            Convert a BitBucket Pipeline to a DevLake Deployment when its 
branch/tag name or one of its pipeline steps’
-            names
-          </span>
-        </div>
-        <div className="sub-text">
-          <span>matches</span>
-          <InputGroup
-            style={{ width: 200, margin: '0 8px' }}
-            placeholder="(deploy|push-image)"
-            value={transformation.deploymentPattern ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                deploymentPattern: e.target.value,
-                productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
-              })
-            }
-          />
-          <span>.</span>
-          <HelpTooltip content="View your BitBucket Pipelines: 
https://support.atlassian.com/bitbucket-cloud/docs/view-your-pipeline/"; />
-        </div>
-        <div className="sub-text">
-          <span>If the name also matches</span>
-          <InputGroup
-            style={{ width: 200, margin: '0 8px' }}
-            placeholder="prod(.*)"
-            value={transformation.productionPattern ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                productionPattern: e.target.value,
-              })
-            }
-          />
-          <span>, this Deployment is a ‘Production Deployment’</span>
-          <HelpTooltip content="If you leave this field empty, all Deployments 
will be tagged as in the Production environment. " />
+          <Divider />
         </div>
-      </S.CICD>
+      )}
+      {entities.includes('CICD') && (
+        <S.CICD>
+          <h2>CI/CD</h2>
+          <h3>
+            <span>Deployment</span>
+            <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
+              DORA
+            </Tag>
+          </h3>
+          <p style={{ marginBottom: 16 }}>
+            Use Regular Expression to define Deployments in DevLake in order 
to measure DORA metrics.{' '}
+            <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
+              Learn more
+            </ExternalLink>
+          </p>
+          <div className="text">
+            <Checkbox disabled checked />
+            <span>Convert a BitBucket Deployment to a DevLake Deployment 
</span>
+            <HelpTooltip content={<img src={ExampleJpg} alt="" width={400} />} 
/>
+          </div>
+          <div className="text">
+            <Checkbox checked={useCustom} onChange={handleChangeUseCustom} />
+            <span>
+              Convert a BitBucket Pipeline to a DevLake Deployment when its 
branch/tag name or one of its pipeline
+              steps’ names
+            </span>
+          </div>
+          <div className="sub-text">
+            <span>matches</span>
+            <InputGroup
+              style={{ width: 200, margin: '0 8px' }}
+              placeholder="(deploy|push-image)"
+              value={transformation.deploymentPattern ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  deploymentPattern: e.target.value,
+                  productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
+                })
+              }
+            />
+            <span>.</span>
+            <HelpTooltip content="View your BitBucket Pipelines: 
https://support.atlassian.com/bitbucket-cloud/docs/view-your-pipeline/"; />
+          </div>
+          <div className="sub-text">
+            <span>If the name also matches</span>
+            <InputGroup
+              style={{ width: 200, margin: '0 8px' }}
+              placeholder="prod(.*)"
+              value={transformation.productionPattern ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  productionPattern: e.target.value,
+                })
+              }
+            />
+            <span>, this Deployment is a ‘Production Deployment’</span>
+            <HelpTooltip content="If you leave this field empty, all 
Deployments will be tagged as in the Production environment. " />
+          </div>
+        </S.CICD>
+      )}
     </S.Transformation>
   );
 };
diff --git a/config-ui/src/plugins/register/github/transformation.tsx 
b/config-ui/src/plugins/register/github/transformation.tsx
index e8762e588..082725be3 100644
--- a/config-ui/src/plugins/register/github/transformation.tsx
+++ b/config-ui/src/plugins/register/github/transformation.tsx
@@ -24,11 +24,12 @@ import { ExternalLink, HelpTooltip, Divider } from 
'@/components';
 import * as S from './styled';
 
 interface Props {
+  entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const GitHubTransformation = ({ transformation, setTransformation }: 
Props) => {
+export const GitHubTransformation = ({ entities, transformation, 
setTransformation }: Props) => {
   const [enableCICD, setEnableCICD] = useState(true);
 
   useEffect(() => {
@@ -53,290 +54,295 @@ export const GitHubTransformation = ({ transformation, 
setTransformation }: Prop
 
   return (
     <S.Transformation>
-      {/* Issue Tracking */}
-      <div className="issue-tracking">
-        <h2>Issue Tracking</h2>
-        <p>
-          Tell DevLake what your issue labels mean to view metrics such as{' '}
-          <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugAge";>Bug Age</ExternalLink>,{' 
'}
-          <ExternalLink link="https://devlake.apache.org/docs/Metrics/MTTR";>
-            DORA - Median Time to Restore Service
-          </ExternalLink>
-          , etc.
-        </p>
-        <div className="issue-type">
-          <div className="title">
-            <span>Issue Type</span>
-            <HelpTooltip content="DevLake defines three standard types of 
issues: FEATURE, BUG and INCIDENT. Set your issues to these three types with 
issue labels that match the RegEx." />
-          </div>
-          <div className="list">
-            <FormGroup inline label="Requirement">
-              <InputGroup
-                placeholder="(feat|feature|proposal|requirement)"
-                value={transformation.issueTypeRequirement ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    issueTypeRequirement: e.target.value,
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="Bug">
-              <InputGroup
-                placeholder="(bug|broken)"
-                value={transformation.issueTypeBug ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    issueTypeBug: e.target.value,
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup
-              inline
-              label={
-                <span>
-                  Incident
-                  <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 4 
}}>
-                    DORA
-                  </Tag>
-                </span>
-              }
-            >
-              <InputGroup
-                placeholder="(incident|failure)"
-                value={transformation.issueTypeIncident ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    issueTypeIncident: e.target.value,
-                  })
+      {entities.includes('TICKET') && (
+        <div className="issue-tracking">
+          <h2>Issue Tracking</h2>
+          <p>
+            Tell DevLake what your issue labels mean to view metrics such as{' 
'}
+            <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugAge";>Bug Age</ExternalLink>,{' 
'}
+            <ExternalLink link="https://devlake.apache.org/docs/Metrics/MTTR";>
+              DORA - Median Time to Restore Service
+            </ExternalLink>
+            , etc.
+          </p>
+          <div className="issue-type">
+            <div className="title">
+              <span>Issue Type</span>
+              <HelpTooltip content="DevLake defines three standard types of 
issues: FEATURE, BUG and INCIDENT. Set your issues to these three types with 
issue labels that match the RegEx." />
+            </div>
+            <div className="list">
+              <FormGroup inline label="Requirement">
+                <InputGroup
+                  placeholder="(feat|feature|proposal|requirement)"
+                  value={transformation.issueTypeRequirement ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      issueTypeRequirement: e.target.value,
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="Bug">
+                <InputGroup
+                  placeholder="(bug|broken)"
+                  value={transformation.issueTypeBug ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      issueTypeBug: e.target.value,
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup
+                inline
+                label={
+                  <span>
+                    Incident
+                    <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 
4 }}>
+                      DORA
+                    </Tag>
+                  </span>
                 }
-              />
-            </FormGroup>
+              >
+                <InputGroup
+                  placeholder="(incident|failure)"
+                  value={transformation.issueTypeIncident ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      issueTypeIncident: e.target.value,
+                    })
+                  }
+                />
+              </FormGroup>
+            </div>
           </div>
-        </div>
-        <FormGroup
-          inline
-          label={
-            <>
-              <span>Issue Priority</span>
-              <HelpTooltip content="Labels that match the RegEx will be set as 
the priority of an issue." />
-            </>
-          }
-        >
-          <InputGroup
-            placeholder="(highest|high|medium|low|p0|p1|p2|p3)"
-            value={transformation.issuePriority ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                issuePriority: e.target.value,
-              })
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>Issue Priority</span>
+                <HelpTooltip content="Labels that match the RegEx will be set 
as the priority of an issue." />
+              </>
             }
-          />
-        </FormGroup>
-        <FormGroup
-          inline
-          label={
-            <>
-              <span>Issue Component</span>
-              <HelpTooltip content="Labels that match the RegEx will be set as 
the component of an issue." />
-            </>
-          }
-        >
-          <InputGroup
-            placeholder="component(.*)"
-            value={transformation.issueComponent ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                issueComponent: e.target.value,
-              })
+          >
+            <InputGroup
+              placeholder="(highest|high|medium|low|p0|p1|p2|p3)"
+              value={transformation.issuePriority ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  issuePriority: e.target.value,
+                })
+              }
+            />
+          </FormGroup>
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>Issue Component</span>
+                <HelpTooltip content="Labels that match the RegEx will be set 
as the component of an issue." />
+              </>
             }
-          />
-        </FormGroup>
-        <FormGroup
-          inline
-          label={
-            <>
-              <span>Issue Severity</span>
-              <HelpTooltip content="Labels that match the RegEx will be set as 
the serverity of an issue." />
-            </>
-          }
-        >
-          <InputGroup
-            placeholder="severity(.*)"
-            value={transformation.issueSeverity ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                issueSeverity: e.target.value,
-              })
+          >
+            <InputGroup
+              placeholder="component(.*)"
+              value={transformation.issueComponent ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  issueComponent: e.target.value,
+                })
+              }
+            />
+          </FormGroup>
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>Issue Severity</span>
+                <HelpTooltip content="Labels that match the RegEx will be set 
as the serverity of an issue." />
+              </>
             }
-          />
-        </FormGroup>
-      </div>
-      <Divider />
-      {/* CI/CD */}
-      <S.CICD>
-        <h2>CI/CD</h2>
-        <h3>
-          <span>Deployment</span>
-          <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
-            DORA
-          </Tag>
-          <div className="switch">
-            <span>Enable</span>
-            <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeEnableCICD} />
-          </div>
-        </h3>
-        {enableCICD && (
-          <>
-            <p>
-              Use Regular Expression to define Deployments in DevLake in order 
to measure DORA metrics.{' '}
-              <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
-                Learn more
-              </ExternalLink>
-            </p>
-            <div style={{ marginTop: 16 }}>Convert a GitHub Workflow run as a 
DevLake Deployment when: </div>
-            <div className="text">
-              <span>
-                The name of the <strong>GitHub workflow run</strong> or 
<strong>one of its jobs</strong> matches
-              </span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                placeholder="(deploy|push-image)"
-                value={transformation.deploymentPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    deploymentPattern: e.target.value,
-                    productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
-                  })
-                }
-              />
-              <i style={{ color: '#E34040' }}>*</i>
-              <HelpTooltip content="GitHub Workflow Runs: 
https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow";
 />
-            </div>
-            <div className="text">
-              <span>If the name also matches</span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                disabled={!transformation.deploymentPattern}
-                placeholder="prod(.*)"
-                value={transformation.productionPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    productionPattern: e.target.value,
-                  })
-                }
-              />
-              <span>, this Deployment is a ‘Production Deployment’</span>
-              <HelpTooltip content="If you leave this field empty, all DevLake 
Deployments will be tagged as in the Production environment. " />
+          >
+            <InputGroup
+              placeholder="severity(.*)"
+              value={transformation.issueSeverity ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  issueSeverity: e.target.value,
+                })
+              }
+            />
+          </FormGroup>
+          <Divider />
+        </div>
+      )}
+      {entities.includes('CICD') && (
+        <S.CICD>
+          <h2>CI/CD</h2>
+          <h3>
+            <span>Deployment</span>
+            <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
+              DORA
+            </Tag>
+            <div className="switch">
+              <span>Enable</span>
+              <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeEnableCICD} />
             </div>
-          </>
-        )}
-      </S.CICD>
-      <Divider />
-      {/* Code Review */}
-      <div>
-        <h2>Code Review</h2>
-        <p>
-          If you use labels to identify types and components of pull requests, 
use the following RegExes to extract them
-          into corresponding columns.{' '}
-          <ExternalLink 
link="https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema#pull_requests";>
-            Learn More
-          </ExternalLink>
-        </p>
-        <FormGroup
-          inline
-          label={
-            <>
-              <span>PR Type</span>
-              <HelpTooltip content="Labels that match the RegEx will be set as 
the type of a pull request." />
-            </>
-          }
-        >
-          <InputGroup
-            placeholder="type(.*)$"
-            value={transformation.prType ?? ''}
-            onChange={(e) => setTransformation({ ...transformation, prType: 
e.target.value })}
-          />
-        </FormGroup>
-        <FormGroup
-          inline
-          label={
+          </h3>
+          {enableCICD && (
             <>
-              <span>PR Component</span>
-              <HelpTooltip content="Labels that match the RegEx will be set as 
the component of a pull request." />
+              <p>
+                Use Regular Expression to define Deployments in DevLake in 
order to measure DORA metrics.{' '}
+                <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
+                  Learn more
+                </ExternalLink>
+              </p>
+              <div style={{ marginTop: 16 }}>Convert a GitHub Workflow run as 
a DevLake Deployment when: </div>
+              <div className="text">
+                <span>
+                  The name of the <strong>GitHub workflow run</strong> or 
<strong>one of its jobs</strong> matches
+                </span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  placeholder="(deploy|push-image)"
+                  value={transformation.deploymentPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      deploymentPattern: e.target.value,
+                      productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
+                    })
+                  }
+                />
+                <i style={{ color: '#E34040' }}>*</i>
+                <HelpTooltip content="GitHub Workflow Runs: 
https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow";
 />
+              </div>
+              <div className="text">
+                <span>If the name also matches</span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  disabled={!transformation.deploymentPattern}
+                  placeholder="prod(.*)"
+                  value={transformation.productionPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      productionPattern: e.target.value,
+                    })
+                  }
+                />
+                <span>, this Deployment is a ‘Production Deployment’</span>
+                <HelpTooltip content="If you leave this field empty, all 
DevLake Deployments will be tagged as in the Production environment. " />
+              </div>
             </>
-          }
-        >
-          <InputGroup
-            placeholder="component(.*)$"
-            value={transformation.prComponent ?? ''}
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                prComponent: e.target.value,
-              })
+          )}
+          <Divider />
+        </S.CICD>
+      )}
+      {entities.includes('CODEREVIEW') && (
+        <div>
+          <h2>Code Review</h2>
+          <p>
+            If you use labels to identify types and components of pull 
requests, use the following RegExes to extract
+            them into corresponding columns.{' '}
+            <ExternalLink 
link="https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema#pull_requests";>
+              Learn More
+            </ExternalLink>
+          </p>
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>PR Type</span>
+                <HelpTooltip content="Labels that match the RegEx will be set 
as the type of a pull request." />
+              </>
             }
-          />
-        </FormGroup>
-      </div>
-      <Divider />
-      {/* Cross-domain */}
-      <div>
-        <h2>Cross-domain</h2>
-        <p>
-          Connect entities across domains to measure metrics such as{' '}
-          <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugCountPer1kLinesOfCode";>
-            Bug Count per 1k Lines of Code
-          </ExternalLink>
-          .
-        </p>
-        <FormGroup
-          inline
-          label={
-            <div className="label">
-              <span>Connect PRs and Issues</span>
-              <HelpTooltip
-                content={
-                  <>
-                    <div>
-                      <Icon icon="tick-circle" size={12} color={Colors.GREEN4} 
style={{ marginRight: '4px' }} />
-                      Example 1: PR #321 body contains "<strong>Closes 
#1234</strong>" (PR #321 and issue #1234 will be
-                      mapped by the following RegEx)
-                    </div>
-                    <div>
-                      <Icon icon="delete" size={12} color={Colors.RED4} 
style={{ marginRight: '4px' }} />
-                      Example 2: PR #321 body contains "<strong>Related to 
#1234</strong>" (PR #321 and issue #1234 will
-                      NOT be mapped by the following RegEx)
-                    </div>
-                  </>
-                }
-              />
-            </div>
-          }
-        >
-          <TextArea
-            value={transformation.prBodyClosePattern ?? ''}
-            
placeholder="(?mi)(fix|close|resolve|fixes|closes|resolves|fixed|closed|resolved)[s]*.*(((and
 )?(#|https://github.com/%s/%s/issues/)d+[ ]*)+)"
-            onChange={(e) =>
-              setTransformation({
-                ...transformation,
-                prBodyClosePattern: e.target.value,
-              })
+          >
+            <InputGroup
+              placeholder="type(.*)$"
+              value={transformation.prType ?? ''}
+              onChange={(e) => setTransformation({ ...transformation, prType: 
e.target.value })}
+            />
+          </FormGroup>
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>PR Component</span>
+                <HelpTooltip content="Labels that match the RegEx will be set 
as the component of a pull request." />
+              </>
+            }
+          >
+            <InputGroup
+              placeholder="component(.*)$"
+              value={transformation.prComponent ?? ''}
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  prComponent: e.target.value,
+                })
+              }
+            />
+          </FormGroup>
+          <Divider />
+        </div>
+      )}
+      {entities.includes('CROSS') && (
+        <div>
+          <h2>Cross-domain</h2>
+          <p>
+            Connect entities across domains to measure metrics such as{' '}
+            <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugCountPer1kLinesOfCode";>
+              Bug Count per 1k Lines of Code
+            </ExternalLink>
+            .
+          </p>
+          <FormGroup
+            inline
+            label={
+              <div className="label">
+                <span>Connect PRs and Issues</span>
+                <HelpTooltip
+                  content={
+                    <>
+                      <div>
+                        <Icon icon="tick-circle" size={12} 
color={Colors.GREEN4} style={{ marginRight: '4px' }} />
+                        Example 1: PR #321 body contains "<strong>Closes 
#1234</strong>" (PR #321 and issue #1234 will
+                        be mapped by the following RegEx)
+                      </div>
+                      <div>
+                        <Icon icon="delete" size={12} color={Colors.RED4} 
style={{ marginRight: '4px' }} />
+                        Example 2: PR #321 body contains "<strong>Related to 
#1234</strong>" (PR #321 and issue #1234
+                        will NOT be mapped by the following RegEx)
+                      </div>
+                    </>
+                  }
+                />
+              </div>
             }
-            fill
-            rows={2}
-          />
-        </FormGroup>
-      </div>
+          >
+            <TextArea
+              value={transformation.prBodyClosePattern ?? ''}
+              
placeholder="(?mi)(fix|close|resolve|fixes|closes|resolves|fixed|closed|resolved)[s]*.*(((and
 )?(#|https://github.com/%s/%s/issues/)d+[ ]*)+)"
+              onChange={(e) =>
+                setTransformation({
+                  ...transformation,
+                  prBodyClosePattern: e.target.value,
+                })
+              }
+              fill
+              rows={2}
+            />
+          </FormGroup>
+          <Divider />
+        </div>
+      )}
     </S.Transformation>
   );
 };
diff --git a/config-ui/src/plugins/register/gitlab/transformation.tsx 
b/config-ui/src/plugins/register/gitlab/transformation.tsx
index 78a1ecd31..864f380bf 100644
--- a/config-ui/src/plugins/register/gitlab/transformation.tsx
+++ b/config-ui/src/plugins/register/gitlab/transformation.tsx
@@ -19,16 +19,17 @@
 import React, { useState, useEffect } from 'react';
 import { Tag, Intent, Switch, InputGroup } from '@blueprintjs/core';
 
-import { ExternalLink, HelpTooltip } from '@/components';
+import { ExternalLink, HelpTooltip, Divider } from '@/components';
 
 import * as S from './styled';
 
 interface Props {
+  entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const GitLabTransformation = ({ transformation, setTransformation }: 
Props) => {
+export const GitLabTransformation = ({ entities, transformation, 
setTransformation }: Props) => {
   const [enableCICD, setEnableCICD] = useState(true);
 
   useEffect(() => {
@@ -53,66 +54,69 @@ export const GitLabTransformation = ({ transformation, 
setTransformation }: Prop
 
   return (
     <S.Transformation>
-      <S.CICD>
-        <h2>CI/CD</h2>
-        <h3>
-          <span>Deployment</span>
-          <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
-            DORA
-          </Tag>
-          <div className="switch">
-            <span>Enable</span>
-            <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
-          </div>
-        </h3>
-        {enableCICD && (
-          <>
-            <p>
-              Use Regular Expression to define Deployments in DevLake in order 
to measure DORA metrics.{' '}
-              <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
-                Learn more
-              </ExternalLink>
-            </p>
-            <div style={{ marginTop: 16 }}>Convert a GitLab Pipeline as a 
DevLake Deployment when: </div>
-            <div className="text">
-              <span>
-                The name of the <strong>GitLab pipeline</strong> or 
<strong>one of its jobs</strong> matches
-              </span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                placeholder="(deploy|push-image)"
-                value={transformation.deploymentPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    deploymentPattern: e.target.value,
-                    productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
-                  })
-                }
-              />
-              <i style={{ color: '#E34040' }}>*</i>
-              <HelpTooltip content="GitLab Pipelines: 
https://docs.gitlab.com/ee/ci/pipelines/"; />
+      {entities.includes('CICD') && (
+        <S.CICD>
+          <h2>CI/CD</h2>
+          <h3>
+            <span>Deployment</span>
+            <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
+              DORA
+            </Tag>
+            <div className="switch">
+              <span>Enable</span>
+              <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
             </div>
-            <div className="text">
-              <span>If the name also matches</span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                disabled={!transformation.deploymentPattern}
-                placeholder="prod(.*)"
-                value={transformation.productionPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    productionPattern: e.target.value,
-                  })
-                }
-              />
-              <span>, this Deployment is a ‘Production Deployment’</span>
-              <HelpTooltip content="If you leave this field empty, all DevLake 
Deployments will be tagged as in the Production environment. " />
-            </div>
-          </>
-        )}
-      </S.CICD>
+          </h3>
+          {enableCICD && (
+            <>
+              <p>
+                Use Regular Expression to define Deployments in DevLake in 
order to measure DORA metrics.{' '}
+                <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
+                  Learn more
+                </ExternalLink>
+              </p>
+              <div style={{ marginTop: 16 }}>Convert a GitLab Pipeline as a 
DevLake Deployment when: </div>
+              <div className="text">
+                <span>
+                  The name of the <strong>GitLab pipeline</strong> or 
<strong>one of its jobs</strong> matches
+                </span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  placeholder="(deploy|push-image)"
+                  value={transformation.deploymentPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      deploymentPattern: e.target.value,
+                      productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
+                    })
+                  }
+                />
+                <i style={{ color: '#E34040' }}>*</i>
+                <HelpTooltip content="GitLab Pipelines: 
https://docs.gitlab.com/ee/ci/pipelines/"; />
+              </div>
+              <div className="text">
+                <span>If the name also matches</span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  disabled={!transformation.deploymentPattern}
+                  placeholder="prod(.*)"
+                  value={transformation.productionPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      productionPattern: e.target.value,
+                    })
+                  }
+                />
+                <span>, this Deployment is a ‘Production Deployment’</span>
+                <HelpTooltip content="If you leave this field empty, all 
DevLake Deployments will be tagged as in the Production environment. " />
+              </div>
+            </>
+          )}
+          <Divider />
+        </S.CICD>
+      )}
     </S.Transformation>
   );
 };
diff --git a/config-ui/src/plugins/register/jenkins/transformation.tsx 
b/config-ui/src/plugins/register/jenkins/transformation.tsx
index 01c9e0999..5ec2980ed 100644
--- a/config-ui/src/plugins/register/jenkins/transformation.tsx
+++ b/config-ui/src/plugins/register/jenkins/transformation.tsx
@@ -23,11 +23,12 @@ import * as S from './styled';
 import { ExternalLink, HelpTooltip } from '@/components';
 
 interface Props {
+  entities: string[];
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const JenkinsTransformation = ({ transformation, setTransformation }: 
Props) => {
+export const JenkinsTransformation = ({ entities, transformation, 
setTransformation }: Props) => {
   const [enableCICD, setEnableCICD] = useState(true);
 
   useEffect(() => {
@@ -52,66 +53,68 @@ export const JenkinsTransformation = ({ transformation, 
setTransformation }: Pro
 
   return (
     <S.Transformation>
-      <S.CICD>
-        <h2>CI/CD</h2>
-        <h3>
-          <span>Deployment</span>
-          <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
-            DORA
-          </Tag>
-          <div className="switch">
-            <span>Enable</span>
-            <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
-          </div>
-        </h3>
-        {enableCICD && (
-          <>
-            <p>
-              Use Regular Expression to define Deployments in DevLake in order 
to measure DORA metrics.{' '}
-              <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
-                Learn more
-              </ExternalLink>
-            </p>
-            <div style={{ marginTop: 16 }}>Convert a Jenkins Build as a 
DevLake Deployment when: </div>
-            <div className="text">
-              <span>
-                The name of the <strong>Jenkins job</strong> or <strong>one of 
its stages</strong> matches
-              </span>
-              <InputGroup
-                style={{ width: 200, margin: '0 8px' }}
-                placeholder="(deploy|push-image)"
-                value={transformation.deploymentPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    deploymentPattern: e.target.value,
-                    productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
-                  })
-                }
-              />
-              <i style={{ color: '#E34040' }}>*</i>
-              <HelpTooltip content="Jenkins Builds: 
https://www.jenkins.io/doc/pipeline/steps/pipeline-build-step/"; />
+      {entities.includes('CICD') && (
+        <S.CICD>
+          <h2>CI/CD</h2>
+          <h3>
+            <span>Deployment</span>
+            <Tag minimal intent={Intent.PRIMARY} style={{ marginLeft: 8 }}>
+              DORA
+            </Tag>
+            <div className="switch">
+              <span>Enable</span>
+              <Switch alignIndicator="right" inline checked={enableCICD} 
onChange={handleChangeCICDEnable} />
             </div>
-            <div className="text">
-              <span>If the name also matches</span>
-              <InputGroup
-                style={{ width: 120, margin: '0 8px' }}
-                disabled={!transformation.deploymentPattern}
-                placeholder="prod(.*)"
-                value={transformation.productionPattern ?? ''}
-                onChange={(e) =>
-                  setTransformation({
-                    ...transformation,
-                    productionPattern: e.target.value,
-                  })
-                }
-              />
-              <span>, this Deployment is a ‘Production Deployment’</span>
-              <HelpTooltip content="If you leave this field empty, all DevLake 
Deployments will be tagged as in the Production environment. " />
-            </div>
-          </>
-        )}
-      </S.CICD>
+          </h3>
+          {enableCICD && (
+            <>
+              <p>
+                Use Regular Expression to define Deployments in DevLake in 
order to measure DORA metrics.{' '}
+                <ExternalLink 
link="https://devlake.apache.org/docs/Configuration/GitHub#step-3---adding-transformation-rules-optional";>
+                  Learn more
+                </ExternalLink>
+              </p>
+              <div style={{ marginTop: 16 }}>Convert a Jenkins Build as a 
DevLake Deployment when: </div>
+              <div className="text">
+                <span>
+                  The name of the <strong>Jenkins job</strong> or <strong>one 
of its stages</strong> matches
+                </span>
+                <InputGroup
+                  style={{ width: 200, margin: '0 8px' }}
+                  placeholder="(deploy|push-image)"
+                  value={transformation.deploymentPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      deploymentPattern: e.target.value,
+                      productionPattern: !e.target.value ? '' : 
transformation.productionPattern,
+                    })
+                  }
+                />
+                <i style={{ color: '#E34040' }}>*</i>
+                <HelpTooltip content="Jenkins Builds: 
https://www.jenkins.io/doc/pipeline/steps/pipeline-build-step/"; />
+              </div>
+              <div className="text">
+                <span>If the name also matches</span>
+                <InputGroup
+                  style={{ width: 120, margin: '0 8px' }}
+                  disabled={!transformation.deploymentPattern}
+                  placeholder="prod(.*)"
+                  value={transformation.productionPattern ?? ''}
+                  onChange={(e) =>
+                    setTransformation({
+                      ...transformation,
+                      productionPattern: e.target.value,
+                    })
+                  }
+                />
+                <span>, this Deployment is a ‘Production Deployment’</span>
+                <HelpTooltip content="If you leave this field empty, all 
DevLake Deployments will be tagged as in the Production environment. " />
+              </div>
+            </>
+          )}
+        </S.CICD>
+      )}
     </S.Transformation>
   );
 };
diff --git 
a/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx 
b/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
index f27065ab8..6db672bd7 100644
--- a/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
+++ b/config-ui/src/plugins/register/jira/transformation-fields/cross-domain.tsx
@@ -19,7 +19,7 @@
 import { useState, useEffect } from 'react';
 import { Radio, Icon, Collapse, InputGroup, Button, Intent } from 
'@blueprintjs/core';
 
-import { ExternalLink, IconButton } from '@/components';
+import { ExternalLink, IconButton, Divider } from '@/components';
 import JiraIssueTipsImg from '@/images/jira-issue-tips.png';
 
 import * as S from './styled';
diff --git a/config-ui/src/plugins/register/jira/transformation.tsx 
b/config-ui/src/plugins/register/jira/transformation.tsx
index 75cba06f3..1b264e4f3 100644
--- a/config-ui/src/plugins/register/jira/transformation.tsx
+++ b/config-ui/src/plugins/register/jira/transformation.tsx
@@ -35,12 +35,13 @@ enum StandardType {
 }
 
 interface Props {
+  entities: string[];
   connectionId: ID;
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const JiraTransformation = ({ connectionId, transformation, 
setTransformation }: Props) => {
+export const JiraTransformation = ({ entities, connectionId, transformation, 
setTransformation }: Props) => {
   const [requirements, setRequirements] = useState<string[]>([]);
   const [bugs, setBugs] = useState<string[]>([]);
   const [incidents, setIncidents] = useState<string[]>([]);
@@ -115,133 +116,137 @@ export const JiraTransformation = ({ connectionId, 
transformation, setTransforma
 
   return (
     <S.TransformationWrapper>
-      <div className="issue-tracking">
-        <h2>Issue Tracking</h2>
-        <p>
-          Tell DevLake what types of Jira issues you are using as features, 
bugs and incidents, and what field as `Epic
-          Link` or `Story Points`.
-        </p>
-        <div className="issue-type">
-          <div className="title">
-            <span>Issue Type</span>
-            <Popover2
-              position="top"
-              content={
-                <div style={{ padding: '8px 12px', color: '#ffffff', 
backgroundColor: 'rgba(0,0,0,.8)' }}>
-                  DevLake defines three standard types of issues: FEATURE, BUG 
and INCIDENT. Standardize your Jira issue
-                  types to these three types so that DevLake can calculate 
metrics such as{' '}
-                  <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/RequirementLeadTime";>
-                    Requirement Lead Time
-                  </ExternalLink>
-                  , <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugAge";>Bug Age</ExternalLink>,
-                  <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/MTTR";>
-                    DORA - Median Time to Restore Service
-                  </ExternalLink>
-                  , etc.
-                </div>
-              }
-            >
-              <Icon icon="help" size={12} color="#94959f" style={{ marginLeft: 
4, cursor: 'pointer' }} />
-            </Popover2>
-          </div>
-          <div className="list">
-            <FormGroup inline label="Requirement">
-              <MultiSelector
-                items={issueTypes}
-                disabledItems={[...bugItems, ...incidentItems]}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                getIcon={(it) => it.iconUrl}
-                selectedItems={requirementItems}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(selectedItems, 
StandardType.Requirement),
-                      ...transformaType(bugItems, StandardType.Bug),
-                      ...transformaType(incidentItems, StandardType.Incident),
-                    },
-                  })
+      {entities.includes('TICKET') && (
+        <div className="issue-tracking">
+          <h2>Issue Tracking</h2>
+          <p>
+            Tell DevLake what types of Jira issues you are using as features, 
bugs and incidents, and what field as
+            `Epic Link` or `Story Points`.
+          </p>
+          <div className="issue-type">
+            <div className="title">
+              <span>Issue Type</span>
+              <Popover2
+                position="top"
+                content={
+                  <div style={{ padding: '8px 12px', color: '#ffffff', 
backgroundColor: 'rgba(0,0,0,.8)' }}>
+                    DevLake defines three standard types of issues: FEATURE, 
BUG and INCIDENT. Standardize your Jira
+                    issue types to these three types so that DevLake can 
calculate metrics such as{' '}
+                    <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/RequirementLeadTime";>
+                      Requirement Lead Time
+                    </ExternalLink>
+                    , <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/BugAge";>Bug Age</ExternalLink>,
+                    <ExternalLink 
link="https://devlake.apache.org/docs/Metrics/MTTR";>
+                      DORA - Median Time to Restore Service
+                    </ExternalLink>
+                    , etc.
+                  </div>
                 }
-              />
-            </FormGroup>
-            <FormGroup inline label="Bug">
-              <MultiSelector
-                items={issueTypes}
-                disabledItems={[...requirementItems, ...incidentItems]}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                getIcon={(it) => it.iconUrl}
-                selectedItems={bugItems}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(requirementItems, 
StandardType.Requirement),
-                      ...transformaType(selectedItems, StandardType.Bug),
-                      ...transformaType(incidentItems, StandardType.Incident),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup
-              inline
-              label={
-                <>
-                  <span>Incident</span>
-                  <Tag intent={Intent.PRIMARY} style={{ marginLeft: 4 }}>
-                    DORA
-                  </Tag>
-                </>
-              }
-            >
-              <MultiSelector
-                items={issueTypes}
-                disabledItems={[...requirementItems, ...bugItems]}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                getIcon={(it) => it.iconUrl}
-                selectedItems={incidentItems}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(requirementItems, 
StandardType.Requirement),
-                      ...transformaType(bugItems, StandardType.Bug),
-                      ...transformaType(selectedItems, StandardType.Incident),
-                    },
-                  })
+              >
+                <Icon icon="help" size={12} color="#94959f" style={{ 
marginLeft: 4, cursor: 'pointer' }} />
+              </Popover2>
+            </div>
+            <div className="list">
+              <FormGroup inline label="Requirement">
+                <MultiSelector
+                  items={issueTypes}
+                  disabledItems={[...bugItems, ...incidentItems]}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  getIcon={(it) => it.iconUrl}
+                  selectedItems={requirementItems}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(selectedItems, 
StandardType.Requirement),
+                        ...transformaType(bugItems, StandardType.Bug),
+                        ...transformaType(incidentItems, 
StandardType.Incident),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="Bug">
+                <MultiSelector
+                  items={issueTypes}
+                  disabledItems={[...requirementItems, ...incidentItems]}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  getIcon={(it) => it.iconUrl}
+                  selectedItems={bugItems}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(requirementItems, 
StandardType.Requirement),
+                        ...transformaType(selectedItems, StandardType.Bug),
+                        ...transformaType(incidentItems, 
StandardType.Incident),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup
+                inline
+                label={
+                  <>
+                    <span>Incident</span>
+                    <Tag intent={Intent.PRIMARY} style={{ marginLeft: 4 }}>
+                      DORA
+                    </Tag>
+                  </>
                 }
-              />
-            </FormGroup>
+              >
+                <MultiSelector
+                  items={issueTypes}
+                  disabledItems={[...requirementItems, ...bugItems]}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  getIcon={(it) => it.iconUrl}
+                  selectedItems={incidentItems}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(requirementItems, 
StandardType.Requirement),
+                        ...transformaType(bugItems, StandardType.Bug),
+                        ...transformaType(selectedItems, 
StandardType.Incident),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+            </div>
           </div>
-        </div>
-        <FormGroup
-          inline
-          label={
-            <>
-              <span>Story Points</span>
-              <HelpTooltip content="Choose the issue field you are using as 
`Story Points`." />
-            </>
-          }
-        >
-          <Selector
-            items={fields}
-            getKey={(it) => it.id}
-            getName={(it) => it.name}
-            selectedItem={fields.find((it) => it.id === 
transformation.storyPointField)}
-            onChangeItem={(selectedItem) =>
-              setTransformation({
-                ...transformation,
-                storyPointField: selectedItem.id,
-              })
+          <FormGroup
+            inline
+            label={
+              <>
+                <span>Story Points</span>
+                <HelpTooltip content="Choose the issue field you are using as 
`Story Points`." />
+              </>
             }
-          />
-        </FormGroup>
-      </div>
-      <Divider />
-      <CrossDomain transformation={transformation} 
setTransformation={setTransformation} />
+          >
+            <Selector
+              items={fields}
+              getKey={(it) => it.id}
+              getName={(it) => it.name}
+              selectedItem={fields.find((it) => it.id === 
transformation.storyPointField)}
+              onChangeItem={(selectedItem) =>
+                setTransformation({
+                  ...transformation,
+                  storyPointField: selectedItem.id,
+                })
+              }
+            />
+          </FormGroup>
+          <Divider />
+        </div>
+      )}
+      {entities.includes('CROSS') && (
+        <CrossDomain transformation={transformation} 
setTransformation={setTransformation} />
+      )}
     </S.TransformationWrapper>
   );
 };
diff --git a/config-ui/src/plugins/register/tapd/transformation.tsx 
b/config-ui/src/plugins/register/tapd/transformation.tsx
index f488e5585..eb1bab91b 100644
--- a/config-ui/src/plugins/register/tapd/transformation.tsx
+++ b/config-ui/src/plugins/register/tapd/transformation.tsx
@@ -39,13 +39,14 @@ enum StandardStatus {
 }
 
 interface Props {
+  entities: string[];
   connectionId: ID;
   scopeId: ID;
   transformation: any;
   setTransformation: React.Dispatch<React.SetStateAction<any>>;
 }
 
-export const TapdTransformation = ({ connectionId, scopeId, transformation, 
setTransformation }: Props) => {
+export const TapdTransformation = ({ entities, connectionId, scopeId, 
transformation, setTransformation }: Props) => {
   const [featureTypeList, setFeatureTypeList] = useState<string[]>([]);
   const [bugTypeList, setBugTypeList] = useState<string[]>([]);
   const [incidentTypeList, setIncidentTypeList] = useState<string[]>([]);
@@ -130,168 +131,173 @@ export const TapdTransformation = ({ connectionId, 
scopeId, transformation, setT
   };
   return (
     <S.TransformationWrapper>
-      {/* Issue Tracking */}
-      <div className="issue-tracking">
-        <h2>Issue Tracking</h2>
-        <div className="issue-type">
-          <div className="title">
-            <span>Issue Type Mapping</span>
-            <HelpTooltip content="Standardize your issue types to the 
following issue types to view metrics such as `Requirement lead time` and `Bug 
age` in built-in dashboards." />
-          </div>
-          <div className="list">
-            <FormGroup inline label="Requirement">
-              <MultiSelector
-                items={typeList}
-                disabledItems={typeList.filter((v) => [...bugTypeList, 
...incidentTypeList].includes(v.id))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={typeList.filter((v) => 
featureTypeList.includes(v.id))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(
-                        selectedItems.map((v) => v.id),
-                        StandardType.Requirement,
-                      ),
-                      ...transformaType(bugTypeList, StandardType.Bug),
-                      ...transformaType(incidentTypeList, 
StandardType.Incident),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="Bug">
-              <MultiSelector
-                items={typeList}
-                disabledItems={typeList.filter((v) => [...featureTypeList, 
...incidentTypeList].includes(v.id))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={typeList.filter((v) => 
bugTypeList.includes(v.id))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(featureTypeList, 
StandardType.Requirement),
-                      ...transformaType(
-                        selectedItems.map((v) => v.id),
-                        StandardType.Bug,
-                      ),
-                      ...transformaType(incidentTypeList, 
StandardType.Incident),
-                    },
-                  })
+      {entities.includes('TICKET') && (
+        <div className="issue-tracking">
+          <h2>Issue Tracking</h2>
+          <div className="issue-type">
+            <div className="title">
+              <span>Issue Type Mapping</span>
+              <HelpTooltip content="Standardize your issue types to the 
following issue types to view metrics such as `Requirement lead time` and `Bug 
age` in built-in dashboards." />
+            </div>
+            <div className="list">
+              <FormGroup inline label="Requirement">
+                <MultiSelector
+                  items={typeList}
+                  disabledItems={typeList.filter((v) => [...bugTypeList, 
...incidentTypeList].includes(v.id))}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={typeList.filter((v) => 
featureTypeList.includes(v.id))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(
+                          selectedItems.map((v) => v.id),
+                          StandardType.Requirement,
+                        ),
+                        ...transformaType(bugTypeList, StandardType.Bug),
+                        ...transformaType(incidentTypeList, 
StandardType.Incident),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="Bug">
+                <MultiSelector
+                  items={typeList}
+                  disabledItems={typeList.filter((v) => [...featureTypeList, 
...incidentTypeList].includes(v.id))}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={typeList.filter((v) => 
bugTypeList.includes(v.id))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(featureTypeList, 
StandardType.Requirement),
+                        ...transformaType(
+                          selectedItems.map((v) => v.id),
+                          StandardType.Bug,
+                        ),
+                        ...transformaType(incidentTypeList, 
StandardType.Incident),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup
+                inline
+                label={
+                  <>
+                    <span>Incident</span>
+                    <Tag intent={Intent.PRIMARY} style={{ marginLeft: 4 }}>
+                      DORA
+                    </Tag>
+                  </>
                 }
-              />
-            </FormGroup>
-            <FormGroup
-              inline
-              label={
-                <>
-                  <span>Incident</span>
-                  <Tag intent={Intent.PRIMARY} style={{ marginLeft: 4 }}>
-                    DORA
-                  </Tag>
-                </>
-              }
-            >
-              <MultiSelector
-                items={typeList}
-                disabledItems={typeList.filter((v) => [...featureTypeList, 
...bugTypeList].includes(v.id))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={typeList.filter((v) => 
incidentTypeList.includes(v.id))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    typeMappings: {
-                      ...transformaType(featureTypeList, 
StandardType.Requirement),
-                      ...transformaType(bugTypeList, StandardType.Bug),
-                      ...transformaType(
-                        selectedItems.map((v) => v.id),
-                        StandardType.Incident,
-                      ),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
-          </div>
-        </div>
-        <div className="issue-status">
-          <div className="title">
-            <span>Issue Status Mapping</span>
-            <HelpTooltip content="Standardize your issue statuses to the 
following issue statuses to view metrics such as `Requirement Delivery Rate` in 
built-in dashboards." />
+              >
+                <MultiSelector
+                  items={typeList}
+                  disabledItems={typeList.filter((v) => [...featureTypeList, 
...bugTypeList].includes(v.id))}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={typeList.filter((v) => 
incidentTypeList.includes(v.id))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      typeMappings: {
+                        ...transformaType(featureTypeList, 
StandardType.Requirement),
+                        ...transformaType(bugTypeList, StandardType.Bug),
+                        ...transformaType(
+                          selectedItems.map((v) => v.id),
+                          StandardType.Incident,
+                        ),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+            </div>
           </div>
-          <div className="list">
-            <FormGroup inline label="TODO">
-              <MultiSelector
-                items={statusList}
-                disabledItems={statusList.filter((v) => 
[...inProgressStatusList, ...doneStatusList].includes(v.name))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={statusList.filter((v) => 
todoStatusList.includes(v.name))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    statusMappings: {
-                      ...transformaType(
-                        selectedItems.map((v) => v.name),
-                        StandardStatus.Todo,
-                      ),
-                      ...transformaType(inProgressStatusList, 
StandardStatus.InProgress),
-                      ...transformaType(doneStatusList, StandardStatus.Done),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="IN-PROGRESS">
-              <MultiSelector
-                items={statusList}
-                disabledItems={statusList.filter((v) => [...todoStatusList, 
...doneStatusList].includes(v.name))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={statusList.filter((v) => 
inProgressStatusList.includes(v.name))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    statusMappings: {
-                      ...transformaType(todoStatusList, StandardStatus.Todo),
-                      ...transformaType(
-                        selectedItems.map((v) => v.name),
-                        StandardStatus.InProgress,
-                      ),
-                      ...transformaType(doneStatusList, StandardStatus.Done),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
-            <FormGroup inline label="DONE">
-              <MultiSelector
-                items={statusList}
-                disabledItems={statusList.filter((v) => [...todoStatusList, 
...inProgressStatusList].includes(v.name))}
-                getKey={(it) => it.id}
-                getName={(it) => it.name}
-                selectedItems={statusList.filter((v) => 
doneStatusList.includes(v.name))}
-                onChangeItems={(selectedItems) =>
-                  setTransformation({
-                    ...transformation,
-                    statusMappings: {
-                      ...transformaType(todoStatusList, StandardStatus.Todo),
-                      ...transformaType(inProgressStatusList, 
StandardStatus.InProgress),
-                      ...transformaType(
-                        selectedItems.map((v) => v.name),
-                        StandardStatus.Done,
-                      ),
-                    },
-                  })
-                }
-              />
-            </FormGroup>
+          <div className="issue-status">
+            <div className="title">
+              <span>Issue Status Mapping</span>
+              <HelpTooltip content="Standardize your issue statuses to the 
following issue statuses to view metrics such as `Requirement Delivery Rate` in 
built-in dashboards." />
+            </div>
+            <div className="list">
+              <FormGroup inline label="TODO">
+                <MultiSelector
+                  items={statusList}
+                  disabledItems={statusList.filter((v) =>
+                    [...inProgressStatusList, 
...doneStatusList].includes(v.name),
+                  )}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={statusList.filter((v) => 
todoStatusList.includes(v.name))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      statusMappings: {
+                        ...transformaType(
+                          selectedItems.map((v) => v.name),
+                          StandardStatus.Todo,
+                        ),
+                        ...transformaType(inProgressStatusList, 
StandardStatus.InProgress),
+                        ...transformaType(doneStatusList, StandardStatus.Done),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="IN-PROGRESS">
+                <MultiSelector
+                  items={statusList}
+                  disabledItems={statusList.filter((v) => [...todoStatusList, 
...doneStatusList].includes(v.name))}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={statusList.filter((v) => 
inProgressStatusList.includes(v.name))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      statusMappings: {
+                        ...transformaType(todoStatusList, StandardStatus.Todo),
+                        ...transformaType(
+                          selectedItems.map((v) => v.name),
+                          StandardStatus.InProgress,
+                        ),
+                        ...transformaType(doneStatusList, StandardStatus.Done),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+              <FormGroup inline label="DONE">
+                <MultiSelector
+                  items={statusList}
+                  disabledItems={statusList.filter((v) =>
+                    [...todoStatusList, 
...inProgressStatusList].includes(v.name),
+                  )}
+                  getKey={(it) => it.id}
+                  getName={(it) => it.name}
+                  selectedItems={statusList.filter((v) => 
doneStatusList.includes(v.name))}
+                  onChangeItems={(selectedItems) =>
+                    setTransformation({
+                      ...transformation,
+                      statusMappings: {
+                        ...transformaType(todoStatusList, StandardStatus.Todo),
+                        ...transformaType(inProgressStatusList, 
StandardStatus.InProgress),
+                        ...transformaType(
+                          selectedItems.map((v) => v.name),
+                          StandardStatus.Done,
+                        ),
+                      },
+                    })
+                  }
+                />
+              </FormGroup>
+            </div>
           </div>
         </div>
-      </div>
+      )}
     </S.TransformationWrapper>
   );
 };

Reply via email to